I want to do someting like that:
var
ip,ip2: string;
begin
ip:= '127.0.0.1';
ip2:= ip+1;
end;
after this code executed ip2 should be 127.0.0.2
Question is: How can I increase an IP address like that?
Using the api, as an alternative:
uses
winsock;
procedure TForm1.Button1Click(Sender: TObject);
var
addr: in_addr;
begin
addr.S_addr := htonl(ntohl(inet_addr('127.0.0.1')) + 1);
ShowMessage(inet_ntoa(addr));
end;
You might try the following:
type
TIPAddress = array[0..3] of Byte;
function IncIPAddress(const IPAddress: TIPAddress;
Value: Integer = 1): TIPAddress;
begin
PInteger(#Result)^ := PInteger(#IPAddress)^ + Value;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
S: string;
IPAddress: TIPAddress;
IPAddress2: TIPAddress;
begin
IPAddress[3] := 127;
IPAddress[2] := 0;
IPAddress[1] := 0;
IPAddress[0] := 1;
S := Format('%d.%d.%d.%d', [IPAddress[3], IPAddress[2],
IPAddress[1], IPAddress[0]]);
ShowMessage(S);
IPAddress2 := IncIPAddress(IPAddress);
S := Format('%d.%d.%d.%d', [IPAddress2[3], IPAddress2[2],
IPAddress2[1], IPAddress2[0]]);
ShowMessage(S);
end;
Related
Delphi offers the library System.Win.Registry to manipulate the windows registry.
Unfortunately it doesn't contain read/write procedures for the registry datatype REG_MULTI_SZ (=list of strings).
The following code returns an ERegistryException with "invalid datatype" - it seems only to work with datatype REG_SZ:
Registry := TRegistry.Create;
Registry.RootKey := HKEY_LOCAL_MACHINE;
Registry.OpenKey(cKey, false);
sValue := Registry.ReadString('MyRegEntry');
Meanwhile I am able to read the REG_MULTI_SZ value with
Registry.ReadBinaryData('MyRegEntry', pBuf, sizeof(pBuf));
but if I write it back using WriteBinaryData() it will be written to the registry as datatype REG_BINARY instead of REG_MULTI_SZ. So that's not working properly.
How can I manipulate registry data of datatype REG_MULTI_SZ using Delphi?
I have written two functions (a class helper) to extend the functionality of TRegistry:
unit Common.RegistryHelper;
interface
uses
System.Classes, System.Win.Registry, Winapi.Windows, System.Math;
type
TRegistryHelper = class helper for TRegistry
public
function ReadMultiSz(const name: string; var Strings: TStrings): boolean;
function WriteMultiSz(const name: string; const value: TStrings): boolean;
end;
implementation
function TRegistryHelper.ReadMultiSz(const name: string; var Strings: TStrings): boolean;
var
iSizeInByte: integer;
Buffer: array of WChar;
iWCharsInBuffer: integer;
z: integer;
sString: string;
begin
iSizeInByte := GetDataSize(name);
if iSizeInByte > 0 then begin
SetLength(Buffer, Floor(iSizeInByte / sizeof(WChar)));
iWCharsInBuffer := Floor(ReadBinaryData(name, Buffer[0],
iSizeInByte) / sizeof(WChar));
sString := '';
for z := 0 to iWCharsInBuffer do begin
if Buffer[z] <> #0 then begin
sString := sString + Buffer[z];
end else begin
if sString <> '' then begin
Strings.Append(sString);
sString := '';
end;
end;
end;
result := true;
end else begin
result := false;
end;
end;
function TRegistryHelper.WriteMultiSz(const name: string; const value: TStrings): boolean;
var
sContent: string;
x: integer;
begin
sContent := '';
for x := 0 to pred(value.Count) do begin
sContent := sContent + value.Strings[x] + #0;
end;
sContent := sContent + #0;
result := RegSetValueEx(CurrentKey, pchar(name), 0, REG_MULTI_SZ,
pointer(sContent), Length(sContent)*sizeof(Char)) = 0;
end;
end.
Using the functions above you can simply write in your program the following code to add a value to a REG_MULTI_SZ entry:
procedure AddValueToRegistry();
const
cKey = '\SYSTEM\ControlSet001\services\TcSysSrv';
var
Registry: TRegistry;
MyList: TStrings;
begin
Registry := TRegistry.Create;
Registry.RootKey := HKEY_LOCAL_MACHINE;
Registry.OpenKey(cKey, false);
try
MyList := TStringList.Create();
Registry.ReadMultiSz('MyRegEntry', MyList);
MyList.Add('NewEntry');
Registry.WriteMultiSz('MyRegEntry', MyList);
finally
MyList.Free;
end;
Registry.Free;
end;
I know the only way to do that is to remap keys with regedit.
Have someone has done that with delphi ? (disable it and enable it again)
http://www.northcode.com/blog.php/2007/07/25/Securing-Windows-For-Use-As-A-Kiosk
The information in the article would translate to Delphi as follows:
uses
Registry;
const
DisableScancodes: packed array[0..11] of DWORD = (
$00000000, // version = 0
$00000000, // flags = 0
$00000009, // # of mappings = 9
$E05B0000, // disable Windows key
$E05C0000, // disable Windows key
$E05D0000, // disable Windows menu key
$00440000, // disable F10 key
$001D0000, // disable Left Ctrl key
$00380000, // disable Left Alt key
$E01D0000, // disable Right Ctrl key
$E0380000, // disable Right Alt key
$00000000 // end of list
);
var
Reg: TRegistry;
begin
Reg := TRegistry.Create(KEY_WRITE);
try
Reg.RootKey := HKEY_LOCAL_MACHINE;
if Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Keyboard Layout', True) then
begin
try
// to enable the mapping
Reg.WriteBinaryData('Scancode Map', DisableScancodes, SizeOf(DisableScancodes));
// to disable the mapping
Reg.DeleteValue('Scancode Map');
finally
Reg.CloseKey;
end;
end;
finally
Reg.Free;
end;
end;
If you need to be more dynamic about which scancodes you enable/disable, you will have to use TRegistry.ReadBinaryData() to read the current Scancode Map value (if it exists), modify it as needed, and then save the changes using TRegistry.WriteBinaryData(). Try something like this:
unit ScanCodeMap;
interface
type
TMappedScancode = record
Scancode: WORD;
MappedTo: WORD;
end;
procedure AddScancodeMappings(const Values: array of TMappedScancode);
procedure AddScancodeMapping(const Value: TMappedScancode);
procedure AddScancodeMapping(Scancode, MappedTo: WORD);
procedure RemoveScancodeMappings(const Scancodes: array of WORD);
procedure RemoveScancodeMapping(Scancode: WORD);
procedure DisableScancodes(Scancodes: array of WORD);
procedure DisableScancode(Scancode: WORD);
implementation
uses
Windows, Registry;
type
PScancodeMapHdr = ^TScancodeMapHdr;
TScancodeMapHdr = packed record
Version: DWORD;
Flags: DWORD;
NumMappings: DWORD;
end;
TScancodeMap = record
Version: DWORD;
Flags: DWORD;
Mappings: array of TMappedScancode;
end;
procedure AddScancodesToMap(var Map: TScancodeMap; const Values: array of TMappedScancode);
var
I, J, Idx: Integer;
begin
for I := 0 to High(Values) do
begin
Idx := -1;
for J := 0 to High(Map.Mappings) do
begin
if Map.Mappings[J].Scancode = Values[I].Scancode then
begin
Idx := J;
Break;
end;
end;
if Idx = -1 then
begin
SetLength(Map.Mappings, Length(Map.Mappings)+1);
Idx := High(Map.Mappings);
end;
Map.Mappings[Idx].MappedTo := Values[I].MappedTo;
end;
end;
procedure RemoveScancodesFromMap(var Map: TScancodeMap; const Scancodes: array of WORD);
var
I, J: Integer;
begin
for I := 0 to High(Scancodes) do
begin
for J := 0 to High(Map.Mappings) do
begin
if Map.Mappings[J].Scancode = Scancodes[I] then
begin
if J < High(Map.Mappings) then
Move(Map.Mappings[J+1], Map.Mappings[J], (High(Mappings)-J) * SizeOf(TMappedScancode));
SetLength(Map.Mappings, Length(Map.Mappings)-1);
Break;
end;
end;
end;
end;
procedure WriteScanCodeMap(const Map: TScancodeMap);
var
Reg: TRegistry;
Data: array of Byte;
Tmp: PByte;
Hdr: PScancodeMapHdr;
I: Integer;
begin
if Length(Map.Mappings) > 0 then
begin
SetLength(Data, sizeof(TScancodeMapHdr) + (Length(Map.Mappings) + 1) * SizeOf(DWORD));
Tmp := PByte(Data);
Hdr := PScancodeMapHdr(Tmp);
Hdr.Version := Map.Version;
Hdr.Flags := Map.Flags;
Hdr.NumMappings := Length(Map.Mappings) + 1;
Inc(Tmp, SizeOf(TScancodeMapHdr));
for I := 0 to High(Map.Mappings) do
begin
PDWORD(Tmp)^ := (DWORD(Map.Mappings[0].Scancode) shr 16) or DWORD(Map.Mappings[0].MappedTo);
Inc(Tmp, SizeOf(DWORD));
end;
PDWORD(Tmp)^ := 0;
end;
Reg := TRegistry.Create(KEY_WRITE);
try
Reg.RootKey := HKEY_LOCAL_MACHINE;
if Reg.OpenKey('\SYSTEM\CurrentControlSet\Control\Keyboard Layout', True) then
begin
try
if Length(Data) > 0 then
Reg.WriteBinaryData('Scancode Map', Data[0], Length(Data))
else
Reg.DeleteValue('Scancode Map');
finally
Reg.CloseKey;
end;
end;
finally
Reg.Free;
end;
end;
procedure ReadScanCodeMap(var Map: TScancodeMap);
var
Reg: TRegistry;
Size: Integer;
Data: array of Byte;
Tmp: PByte;
Hdr: PScancodeMapHdr;
I: Integer;
begin
Map.Version := 0;
Map.Flags := 0;
SetLength(Map.Mappings, 0);
Reg := TRegistry.Create;
try
Reg.RootKey := HKEY_LOCAL_MACHINE;
if Reg.OpenKeyReadOnly('\SYSTEM\CurrentControlSet\Control\Keyboard Layout') then
begin
try
Size := Reg.GetDataSize('Scancode Map');
if Size > SizeOf(TScancodeMapHdr) then
begin
SetLength(Data, Size);
Reg.ReadBinaryData('Scancode Map', Data[0], Size);
Tmp := PByte(Data);
Hdr := PScancodeMapHdr(Tmp);
Map.Version := Hdr.Version;
Map.Flags := Hdr.Flags;
Inc(Tmp, SizeOf(TScancodeMapHdr));
if Hdr.NumMappings > 1 then
begin
SetLength(Map.Mappings, Hdr.NumMappings-1);
for I := 0 to High(Map.Mappings) do
begin
Map.Mappings[I].Scancode := HIWORD(PDWORD(Tmp)^);
Map.Mappings[I].MappedTo := LOWORD(PDWORD(Tmp)^);
end;
end;
end;
finally
Reg.CloseKey;
end;
end;
finally
Reg.Free;
end;
end;
procedure AddScancodeMappings(const Values: array of TMappedScancode);
var
Map: TScancodeMap;
begin
ReadScanCodeMap(Map);
AddScancodesToMap(Map, Values);
WriteScanCodeMap(Map);
end;
procedure AddScancodeMapping(const Value: TMappedScancode);
begin
AddScancodeMappings([Value]);
end;
procedure AddScancodeMapping(Scancode, MappedTo: WORD);
var
Value: array[0..0] of TMappedScancode;
begin
Value[0].Scancode := Scancode;
Value[0].MappedTo := MappedTo;
AddScancodeMappings([Value]);
end;
procedure RemoveScancodeMappings(const Scancodes: array of WORD);
var
Map: TScancodeMap;
begin
ReadScanCodeMap(Map);
RemoveScancodesFromMap(Map, Scancodes);
WriteScanCodeMap(Map);
end;
procedure RemoveScancodeMapping(Scancode: WORD);
begin
RemoveScancodeMappings([Scancode]);
end;
procedure DisableScancodes(Scancodes: array of WORD);
var
Values: array of TMappedScancode;
I: Integer;
begin
SetLength(Values, Length(Scancodes));
for I := 0 to High(Mappings) do
begin
Values[I].Scancode := Scancodes[I];
Values[I].MappedTo := $0000;
end;
AddScancodeMappings(Values);
end;
procedure DisableScancode(Scancode: WORD);
begin
AddScancodeMapping(Scancode, $0000);
end;
end.
Then you can do this:
uses
ScanCodeMap;
const
Scancodes: packed array[0..7] of WORD = (
$E05B, // Windows key
$E05C, // Windows key
$E05D, // Windows menu key
$0044, // F10 key
$001D, // Left Ctrl key
$0038, // Left Alt key
$E01D, // Right Ctrl key
$E038 // Right Alt key
);
procedure DisableCtrlAltDel;
begin
DisableScancodes(Scancodes);
end;
procedure EnableCtrlAltDel;
begin
RemoveScancodeMappings(Scancodes);
end;
I have this code that gets called from an injected DLL from a foreign process. It sould read some memory ranges but I sometimes get a segmentation fault at this line DataBuffer := TCharPointer(Address + CharOffset)^;. So is there any way to check if the memory is readable?
function GetCurrentData(Address: Pointer): PChar;
var
DataBuffer: Char;
CharArray: Array of Char;
CharOffset: Integer;
ReadBytes: longword;
begin
CharOffset := 0;
SetLength(CharArray, 0);
repeat
DataBuffer := TCharPointer(Address + CharOffset)^;
CharOffset := CharOffset + 1;
SetLength(CharArray, CharOffset);
CharArray[CharOffset - 1] := DataBuffer;
until (Ord(DataBuffer) = 0);
Result := PChar(#CharArray[0]);
end;
i also tryed to catch the exception but for some reason this is not working. The host programm still crashes.
unit UnitEventBridgeExports;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Windows, ShellAPI, JwaTlHelp32, SimpleIPC;
type
TCharPointer = ^Char;
const
WOWEXE = 'TestProgramm.exe';
var
IPCClient: TSimpleIPCClient;
PID: DWord;
Process: THandle;
procedure EventCalled;
procedure InitializeWoWEventBridge; stdcall;
implementation
function GetProcessIDByName(Exename: String): DWord;
var
hProcSnap: THandle;
pe32: TProcessEntry32;
begin
Result := 0;
hProcSnap := CreateToolHelp32SnapShot(TH32CS_SNAPPROCESS, 0);
if hProcSnap <> INVALID_HANDLE_VALUE then
begin
pe32.dwSize := SizeOf(ProcessEntry32);
if Process32First(hProcSnap, pe32) = True then
begin
while Process32Next(hProcSnap, pe32) = True do
begin
if pos(Exename, pe32.szExeFile) <> 0 then
Result := pe32.th32ProcessID;
end;
end;
CloseHandle(hProcSnap);
end;
end;
procedure InitializeEventBridge; stdcall;
begin
IPCClient := TSimpleIPCClient.Create(nil);
IPCClient.ServerID := 'EventBridgeServer';
IPCClient.Active := True;
IPCClient.SendStringMessage('init');
PID := GetProcessIDByName(EXE);
Process := OpenProcess(PROCESS_ALL_ACCESS, False, PID);
end;
function GetCurrentData(Address: Pointer): PChar;
var
DataBuffer: Char;
CharArray: Array of Char;
CharOffset: Integer;
ReadBytes: longword;
CharPointer: TCharPointer;
BreakLoop: Boolean;
begin
CharOffset := 0;
SetLength(CharArray, 0);
BreakLoop := False;
repeat
try
CharPointer := TCharPointer(Address + CharOffset);
DataBuffer := CharPointer^;
CharOffset := CharOffset + 1;
SetLength(CharArray, CharOffset);
CharArray[CharOffset - 1] := DataBuffer;
except
BreakLoop := True;
end;
until (Ord(DataBuffer) = 0) or BreakLoop;
Result := PChar(#CharArray[0]);
end;
procedure EventCalled;
var
TmpAddress: Pointer;
StringData: PChar;
begin
{$ASMMODE intel}
asm
mov [TmpAddress], edi
end;
StringData := GetCurrentData(TmpAddress);
IPCClient.SendStringMessage('update:' + StringData);
//IPCClient.SendStringMessage('update');
end;
end.
Your GetCurrentData() implementation is returning a pointer to a local array that goees out of scope when the function exits, then EventCalled() tries to use that poiner after it is no longer valid. Try this instead:
function GetCurrentData(Address: Pointer): AnsiString;
var
Offset: Integer;
begin
Result := '';
Offset := 0;
repeat
try
if PByte(Longint(Address) + Offset)^ = #0 then Break;
Inc(Offset);
except
Break;
end;
until False;
SetString(Result, PAnsiChar(Address), Offset);
end;
procedure EventCalled;
var
TmpAddress: Pointer;
StringData: AnsiString;
begin
{$ASMMODE intel}
asm
mov [TmpAddress], edi
end;
StringData := GetCurrentData(TmpAddress);
IPCClient.SendStringMessage('update:' + StringData);
//IPCClient.SendStringMessage('update');
end;
IsBadReadPtr API is here to help. You give address and size, and you get the readability back. Raymond Chen suggests to never use it though.
Other than that, VirtualQuery should give you information about the address in question to tell its readability.
Since Ken in comments below re-warned about danger of IsBadReadPtr, I bring it up to the answer to not pass by. Be sure to read the comments and links to Raymdond's blog. Be sure to see also:
Most efficient replacement for IsBadReadPtr?
How to check if a pointer is valid?
I would like to perform a thorough LAN devices discovery, so that I can create a diagram similar to the one attached, but with additional information like IP and MAC addresses.
I've tried the code from Torry:
type
PNetResourceArray = ^TNetResourceArray;
TNetResourceArray = array[0..100] of TNetResource;
function CreateNetResourceList(ResourceType: DWord;
NetResource: PNetResource;
out Entries: DWord;
out List: PNetResourceArray): Boolean;
var
EnumHandle: THandle;
BufSize: DWord;
Res: DWord;
begin
Result := False;
List := Nil;
Entries := 0;
if WNetOpenEnum(RESOURCE_GLOBALNET,
ResourceType,
0,
NetResource,
EnumHandle) = NO_ERROR then begin
try
BufSize := $4000; // 16 kByte
GetMem(List, BufSize);
try
repeat
Entries := DWord(-1);
FillChar(List^, BufSize, 0);
Res := WNetEnumResource(EnumHandle, Entries, List, BufSize);
if Res = ERROR_MORE_DATA then
begin
ReAllocMem(List, BufSize);
end;
until Res <> ERROR_MORE_DATA;
Result := Res = NO_ERROR;
if not Result then
begin
FreeMem(List);
List := Nil;
Entries := 0;
end;
except
FreeMem(List);
raise;
end;
finally
WNetCloseEnum(EnumHandle);
end;
end;
end;
procedure ScanNetworkResources(ResourceType, DisplayType: DWord; List: TStrings);
procedure ScanLevel(NetResource: PNetResource);
var
Entries: DWord;
NetResourceList: PNetResourceArray;
i: Integer;
begin
if CreateNetResourceList(ResourceType, NetResource, Entries, NetResourceList) then try
for i := 0 to Integer(Entries) - 1 do
begin
if (DisplayType = RESOURCEDISPLAYTYPE_GENERIC) or
(NetResourceList[i].dwDisplayType = DisplayType) then begin
List.AddObject(NetResourceList[i].lpRemoteName,
Pointer(NetResourceList[i].dwDisplayType));
end;
if (NetResourceList[i].dwUsage and RESOURCEUSAGE_CONTAINER) <> 0 then
ScanLevel(#NetResourceList[i]);
end;
finally
FreeMem(NetResourceList);
end;
end;
begin
ScanLevel(Nil);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
ScanNetworkResources(RESOURCETYPE_DISK, RESOURCEDISPLAYTYPE_SERVER, ListBox1.Items);
end;
But it only returns the names of the computers in the network, without the router and their IP address. So that's not really a solution.
Could you please tell me what is a good way to enumerate all devices (routers, computers, printers) in a local network, along with their IP and MAC addresses?
Thank you.
I modified you code adding the function GetHostName and inet_ntoa to get the ip address and the SendARP function to get the MAC address of a network resource.
{$APPTYPE CONSOLE}
{$R *.res}
uses
StrUtils,
Windows,
WinSock,
SysUtils;
type
PNetResourceArray = ^TNetResourceArray;
TNetResourceArray = array[0..1023] of TNetResource;
function SendArp(DestIP,SrcIP:ULONG;pMacAddr:pointer;PhyAddrLen:pointer) : DWord; StdCall; external 'iphlpapi.dll' name 'SendARP';
function GetIPAddress(const HostName: AnsiString): AnsiString;
var
HostEnt: PHostEnt;
Host: AnsiString;
SockAddr: TSockAddrIn;
begin
Result := '';
Host := HostName;
if Host = '' then
begin
SetLength(Host, MAX_PATH);
GetHostName(PAnsiChar(Host), MAX_PATH);
end;
HostEnt := GetHostByName(PAnsiChar(Host));
if HostEnt <> nil then
begin
SockAddr.sin_addr.S_addr := Longint(PLongint(HostEnt^.h_addr_list^)^);
Result := inet_ntoa(SockAddr.sin_addr);
end;
end;
function GetMacAddr(const IPAddress: AnsiString; var ErrCode : DWORD): AnsiString;
var
MacAddr : Array[0..5] of Byte;
DestIP : ULONG;
PhyAddrLen : ULONG;
begin
Result :='';
ZeroMemory(#MacAddr,SizeOf(MacAddr));
DestIP :=inet_addr(PAnsiChar(IPAddress));
PhyAddrLen:=SizeOf(MacAddr);
ErrCode :=SendArp(DestIP,0,#MacAddr,#PhyAddrLen);
if ErrCode = S_OK then
Result:=AnsiString(Format('%2.2x-%2.2x-%2.2x-%2.2x-%2.2x-%2.2x',[MacAddr[0], MacAddr[1],MacAddr[2], MacAddr[3], MacAddr[4], MacAddr[5]]));
end;
function ParseRemoteName(Const lpRemoteName : string) : string;
begin
Result:=lpRemoteName;
if StartsStr('\\', lpRemoteName) and (Length(lpRemoteName)>2) and (LastDelimiter('\', lpRemoteName)>2) then
Result:=Copy(lpRemoteName, 3, PosEx('\', lpRemoteName,3)-3)
else
if StartsStr('\\', lpRemoteName) and (Length(lpRemoteName)>2) and (LastDelimiter('\', lpRemoteName)=2) then
Result:=Copy(lpRemoteName, 3, length(lpRemoteName));
end;
function CreateNetResourceList(ResourceType: DWord;
NetResource: PNetResource;
out Entries: DWord;
out List: PNetResourceArray): Boolean;
var
EnumHandle: THandle;
BufSize: DWord;
Res: DWord;
begin
Result := False;
List := Nil;
Entries := 0;
if WNetOpenEnum(RESOURCE_GLOBALNET, ResourceType, 0, NetResource, EnumHandle) = NO_ERROR then
begin
try
BufSize := $4000; // 16 kByte
GetMem(List, BufSize);
try
repeat
Entries := DWord(-1);
FillChar(List^, BufSize, 0);
Res := WNetEnumResource(EnumHandle, Entries, List, BufSize);
if Res = ERROR_MORE_DATA then
begin
ReAllocMem(List, BufSize);
end;
until Res <> ERROR_MORE_DATA;
Result := Res = NO_ERROR;
if not Result then
begin
FreeMem(List);
List := Nil;
Entries := 0;
end;
except
FreeMem(List);
raise;
end;
finally
WNetCloseEnum(EnumHandle);
end;
end;
end;
procedure ScanNetworkResources(ResourceType, DisplayType: DWord);
procedure ScanLevel(NetResource: PNetResource);
var
Entries: DWord;
NetResourceList: PNetResourceArray;
i: Integer;
IPAddress, MacAddress : AnsiString;
ErrCode : DWORD;
begin
if CreateNetResourceList(ResourceType, NetResource, Entries, NetResourceList) then try
for i := 0 to Integer(Entries) - 1 do
begin
if (DisplayType = RESOURCEDISPLAYTYPE_GENERIC) or
(NetResourceList[i].dwDisplayType = DisplayType) then
begin
IPAddress :=GetIPAddress(ParseRemoteName(AnsiString(NetResourceList[i].lpRemoteName)));
MacAddress :=GetMacAddr(IPAddress, ErrCode);
Writeln(Format('Remote Name %s Ip %s MAC %s',[NetResourceList[i].lpRemoteName, IPAddress, MacAddress]));
end;
if (NetResourceList[i].dwUsage and RESOURCEUSAGE_CONTAINER) <> 0 then
ScanLevel(#NetResourceList[i]);
end;
finally
FreeMem(NetResourceList);
end;
end;
begin
ScanLevel(Nil);
end;
var
WSAData: TWSAData;
begin
try
if WSAStartup($0101, WSAData)=0 then
try
ScanNetworkResources(RESOURCETYPE_ANY, RESOURCEDISPLAYTYPE_SERVER);
Writeln('Done');
finally
WSACleanup;
end;
except
on E:Exception do
Writeln(E.Classname, ': ', E.Message);
end;
Readln;
end.
Here a unit i can't get working properly on Delphi 2009. I give you the original code that correctly transmit data when compiled with Delphi 2007. Ansifying the code for Delphi 2009 gives me a connection to the server but no data is transmitted and no feedback). Thanks.
unit SMTP_Connections2007;
// *********************************************************************
// Unit Name : SMTP_Connections *
// Author : Melih SARICA (Non ZERO) *
// Date : 01/17/2004 *
//**********************************************************************
interface
uses
Classes, StdCtrls;
const
WinSock = 'wsock32.dll';
Internet = 2;
Stream = 1;
fIoNbRead = $4004667F;
WinSMTP = $0001;
LinuxSMTP = $0002;
type
TWSAData = packed record
wVersion: Word;
wHighVersion: Word;
szDescription: array[0..256] of Char;
szSystemStatus: array[0..128] of Char;
iMaxSockets: Word;
iMaxUdpDg: Word;
lpVendorInfo: PChar;
end;
PHost = ^THost;
THost = packed record
Name: PChar;
aliases: ^PChar;
addrtype: Smallint;
Length: Smallint;
addr: ^Pointer;
end;
TSockAddr = packed record
Family: Word;
Port: Word;
Addr: Longint;
Zeros: array[0..7] of Byte;
end;
function WSAStartup(Version:word; Var Data:TwsaData):integer; stdcall; far; external winsock;
function socket(Family,Kind,Protocol:integer):integer; stdcall; far; external winsock;
function shutdown(Socket,How:Integer):integer; stdcall; far; external winsock;
function closesocket(socket:Integer):integer; stdcall; far; external winsock;
function WSACleanup:integer; stdcall; far; external winsock;
function bind(Socket:Integer; Var SockAddr:TSockAddr; AddrLen:integer):integer; stdcall; far; external winsock;
function listen(socket,flags:Integer):integer; stdcall; far; external winsock;
function connect(socket:Integer; Var SockAddr:TSockAddr; AddrLen:integer):integer; stdcall; far; external winsock;
function accept(socket:Integer; Var SockAddr:TSockAddr; Var AddrLen:Integer):integer; stdcall; far; external winsock;
function WSAGetLastError:integer; stdcall; far; external winsock;
function recv(socket:integer; data:pchar; datalen,flags:integer):integer; stdcall; far; external winsock;
function send(socket:integer; var data; datalen,flags:integer):integer; stdcall; far; external winsock;
function gethostbyname(HostName:PChar):PHost; stdcall; far; external winsock;
function WSAIsBlocking:boolean; stdcall; far; external winsock;
function WSACancelBlockingCall:integer; stdcall; far; external winsock;
function ioctlsocket(socket:integer; cmd: Longint; var arg: longint): Integer; stdcall; far; external winsock;
function gethostname(name:pchar; size:integer):integer; stdcall; far; external winsock;
procedure _authSendMail(MailServer,uname,upass,mFrom,mFromName,mToName,Subject:string;mto,mbody:TStringList);
function ConnectServer(mhost:string;mport:integer):integer;
function ConnectServerwin(mhost:string;mport:integer):integer;
function DisConnectServer:integer;
function Stat: string;
function SendCommand(Command: String): string;
function SendData(Command: String): string;
function SendCommandWin(Command: String): string;
function ReadCommand: string;
function encryptB64(s:string):string;
var
mconnHandle: Integer;
mFin, mFOut: Textfile;
EofSock: Boolean;
mactive: Boolean;
mSMTPErrCode: Integer;
mSMTPErrText: string;
mMemo: TMemo;
implementation
uses
SysUtils, Sockets, IdBaseComponent,
IdCoder, IdCoder3to4, IdCoderMIME, IniFiles,Unit1;
var
mClient: TTcpClient;
procedure _authSendMail(MailServer, uname, upass, mFrom, mFromName,
mToName, Subject: string; mto, mbody: TStringList);
var
tmpstr: string;
cnt: Integer;
mstrlist: TStrings;
RecipientCount: Integer;
begin
if ConnectServerWin(Mailserver, 587) = 250 then //port is 587
begin
Sendcommandwin('AUTH LOGIN ');
SendcommandWin(encryptB64(uname));
SendcommandWin(encryptB64(upass));
SendcommandWin('MAIL FROM: ' + mfrom);
for cnt := 0 to mto.Count - 1 do
SendcommandWin('RCPT TO: ' + mto[cnt]);
Sendcommandwin('DATA');
SendData('Subject: ' + Subject);
SendData('From: "' + mFromName + '" <' + mfrom + '>');
SendData('To: ' + mToName);
SendData('Mime-Version: 1.0');
SendData('Content-Type: multipart/related; boundary="Esales-Order";');
SendData(' type="text/html"');
SendData('');
SendData('--Esales-Order');
SendData('Content-Type: text/html;');
SendData(' charset="iso-8859-9"');
SendData('Content-Transfer-Encoding: QUOTED-PRINTABLE');
SendData('');
for cnt := 0 to mbody.Count - 1 do
SendData(mbody[cnt]);
Senddata('');
SendData('--Esales-Order--');
Senddata(' ');
mSMTPErrText := SendCommand(crlf + '.' + crlf);
try
mSMTPErrCode := StrToInt(Copy(mSMTPErrText, 1, 3));
except
end;
SendData('QUIT');
DisConnectServer;
end;
end;
function Stat: string;
var
s: string;
begin
s := ReadCommand;
Result := s;
end;
function EchoCommand(Command: string): string;
begin
SendCommand(Command);
Result := ReadCommand;
end;
function ReadCommand: string;
var
tmp: string;
begin
repeat
ReadLn(mfin, tmp);
if Assigned(mmemo) then
mmemo.Lines.Add(tmp);
until (Length(tmp) < 4) or (tmp[4] <> '-');
Result := tmp
end;
function SendData(Command: string): string;
begin
Writeln(mfout, Command);
end;
function SendCommand(Command: string): string;
begin
Writeln(mfout, Command);
Result := stat;
end;
function SendCommandWin(Command: string): string;
begin
Writeln(mfout, Command + #13);
Result := stat;
end;
function FillBlank(Source: string; number: Integer): string;
var
a: Integer;
begin
Result := '';
for a := Length(trim(Source)) to number do
Result := Result + ' ';
end;
function IpToLong(ip: string): Longint;
var
x, i: Byte;
ipx: array[0..3] of Byte;
v: Integer;
begin
Result := 0;
Longint(ipx) := 0;
i := 0;
for x := 1 to Length(ip) do
if ip[x] = '.' then
begin
Inc(i);
if i = 4 then Exit;
end
else
begin
if not (ip[x] in ['0'..'9']) then Exit;
v := ipx[i] * 10 + Ord(ip[x]) - Ord('0');
if v > 255 then Exit;
ipx[i] := v;
end;
Result := Longint(ipx);
end;
function HostToLong(AHost: string): Longint;
var
Host: PHost;
begin
Result := IpToLong(AHost);
if Result = 0 then
begin
Host := GetHostByName(PChar(AHost));
if Host <> nil then Result := Longint(Host^.Addr^^);
end;
end;
function LongToIp(Long: Longint): string;
var
ipx: array[0..3] of Byte;
i: Byte;
begin
Longint(ipx) := long;
Result := '';
for i := 0 to 3 do Result := Result + IntToStr(ipx[i]) + '.';
SetLength(Result, Length(Result) - 1);
end;
procedure Disconnect(Socket: Integer);
begin
ShutDown(Socket, 1);
CloseSocket(Socket);
end;
function CallServer(Server: string; Port: Word): Integer;
var
SockAddr: TSockAddr;
begin
Result := socket(Internet, Stream, 0);
if Result = -1 then Exit;
FillChar(SockAddr, SizeOf(SockAddr), 0);
SockAddr.Family := Internet;
SockAddr.Port := swap(Port);
SockAddr.Addr := HostToLong(Server);
if Connect(Result, SockAddr, SizeOf(SockAddr)) <> 0 then
begin
Disconnect(Result);
Result := -1;
end;
end;
function OutputSock(var F: TTextRec): Integer; far;
begin
if F.BufPos <> 0 then
begin
Send(F.Handle, F.BufPtr^, F.BufPos, 0);
F.BufPos := 0;
end;
Result := 0;
end;
function InputSock(var F: TTextRec): Integer; far;
var
Size: Longint;
begin
F.BufEnd := 0;
F.BufPos := 0;
Result := 0;
repeat
if (IoctlSocket(F.Handle, fIoNbRead, Size) < 0) then
begin
EofSock := True;
Exit;
end;
until (Size >= 0);
F.BufEnd := Recv(F.Handle, F.BufPtr, F.BufSize, 0);
EofSock := (F.Bufend = 0);
end;
function CloseSock(var F: TTextRec): Integer; far;
begin
Disconnect(F.Handle);
F.Handle := -1;
Result := 0;
end;
function OpenSock(var F: TTextRec): Integer; far;
begin
if F.Mode = fmInput then
begin
EofSock := False;
F.BufPos := 0;
F.BufEnd := 0;
F.InOutFunc := #InputSock;
F.FlushFunc := nil;
end
else
begin
F.Mode := fmOutput;
F.InOutFunc := #OutputSock;
F.FlushFunc := #OutputSock;
end;
F.CloseFunc := #CloseSock;
Result := 0;
end;
procedure AssignCrtSock(Socket:integer; Var Input,Output:TextFile);
begin
with TTextRec(Input) do
begin
Handle := Socket;
Mode := fmClosed;
BufSize := SizeOf(Buffer);
BufPtr := #Buffer;
OpenFunc := #OpenSock;
end;
with TTextRec(Output) do
begin
Handle := Socket;
Mode := fmClosed;
BufSize := SizeOf(Buffer);
BufPtr := #Buffer;
OpenFunc := #OpenSock;
end;
Reset(Input);
Rewrite(Output);
end;
function ConnectServer(mhost: string; mport: Integer): Integer;
var
tmp: string;
begin
mClient := TTcpClient.Create(nil);
mClient.RemoteHost := mhost;
mClient.RemotePort := IntToStr(mport);
mClient.Connect;
mconnhandle := callserver(mhost, mport);
if (mconnHandle<>-1) then
begin
AssignCrtSock(mconnHandle, mFin, MFout);
tmp := stat;
tmp := SendCommand('HELO bellona.com.tr');
if Copy(tmp, 1, 3) = '250' then
begin
Result := StrToInt(Copy(tmp, 1, 3));
end;
end;
end;
function ConnectServerWin(mhost: string; mport: Integer): Integer;
var
tmp: string;
begin
mClient := TTcpClient.Create(nil);
mClient.RemoteHost := mhost;
mClient.RemotePort := IntToStr(mport);
mClient.Connect;
mconnhandle := callserver(mhost, mport);
if (mconnHandle<>-1) then
begin
AssignCrtSock(mconnHandle, mFin, MFout);
tmp := stat;
tmp := SendCommandWin('HELO bellona.com.tr');
if Copy(tmp, 1, 3) = '250' then
begin
Result := StrToInt(Copy(tmp, 1, 3));
end;
end;
end;
function DisConnectServer: Integer;
begin
closesocket(mconnhandle);
mClient.Disconnect;
mclient.Free;
end;
function encryptB64(s: string): string;
var
hash1: TIdEncoderMIME;
p: string;
begin
if s <> '' then
begin
hash1 := TIdEncoderMIME.Create(nil);
p := hash1.Encode(s);
hash1.Free;
end;
Result := p;
end;
end.
Here some code to give it a try:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
// Button1: TButton;
// Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses
SMTP_Connections2007;
procedure TForm1.Button1Click(Sender: TObject);
var
mto, mbody: TStringList;
MailServer, uname, upass, mFrom, mFromName,
mToName, Subject: string;
begin
mMemo := Memo1; // to output server feedback
//..........................
MailServer := 'somename.servername';
uname := 'username';
upass := 'password';
mFrom := 'someuser#xyz.net';
mFromName := 'forename surname';
mToName := '';
Subject := 'Your Subject';
//..........................
mto := TStringList.Create;
mbody := TStringList.Create;
try
mto.Add('destination_emailaddress');
mbody.Add('Test Mail');
//Send Mail.................
_authSendMail(MailServer, uname, upass, mFrom, mFromName, mToName, Subject, mto, mbody);
//..........................
finally
mto.Free;
mbody.Free;
end;
end;
end.
I ansified your code, and tested it with Delphi2009, it works without any problem. I've managed to send email from gmx.com to mail.google.com.
I did change string to AnsiString, Char to AnsiChar, and PChar to PAnsiChar.
Maybe you simply forgot to ansify Char or PChar?
One thing to consider would be the TCP/IP library Synapse, of which the latest development version in SVN compiles and runs against Delphi 2009 with Unicode and
has all of the functionality in your unit and can easily perform the steps of your test program.