OS: Windows 10 Pro 64-bit
IDE: Delphi XE6 + Update 1
Create an application in Delphi XE6 sending Magic packet through Indy components in order to achieve Wake-on-LAN a local server. Server has been tested to be able to wake from a Linux client.
Note, that I want to create my own solution, no application suggestions, please. Thank you.
Quoting part of Wikipedia article:
The magic packet is a broadcast frame containing anywhere within its payload 6 bytes of all 255 (FF FF FF FF FF FF in hexadecimal), followed by sixteen repetitions of the target computer's 48-bit MAC address, for a total of 102 bytes.
I got the base version from this page.
The author does not mention which version of Delphi he used, let's just suppose an older one.
I will quote it, in case the page becomes unavailable, unaltered:
procedure WakeOnLan(const AMacAddress : string);
type
TMacAddress = array [1..6] of byte;
TWakeRecord = packed record
Waker : TMACAddress;
MAC : array[0..15] of TMACAddress;
end;
var i : integer;
WR : TWakeRecord;
MacAddress : TMacAddress;
UDP : TIdUDPClient;
sData : string;
begin
// Convert MAC string into MAC array
fillchar(MacAddress,SizeOf(TMacAddress),0);
sData := trim(AMacAddress);
if length(sData) = 17 then begin
for i := 1 to 6 do begin
MacAddress[i] := StrToIntDef('$' + copy(sData,1,2),0);
sData := copy(sData,4,17);
end;
end;
for i := 1 To 6 do WR.Waker[i] := $FF;
for i := 0 to 15 do WR.MAC[i] := MacAddress;
// Create UDP and Broadcast data structure
UDP := TIdUDPClient.Create(nil);
UDP.Host := '255.255.255.255';
UDP.Port := 32767;
UDP.BroadCastEnabled := true;
UDP.SendBuffer(WR,SizeOf(TWakeRecord));
UDP.BroadcastEnabled := false;
UDP.Free;
end;
But the compiler of Delphi XE6 complains on line:
UDP.SendBuffer(WR,SizeOf(TWakeRecord));
where it says:
[dcc64 Error] main.pas(73): E2250 There is no overloaded version of 'SendBuffer' that can be called with these arguments
Re-written the above code for better readability + I have tried various approaches which won't compile ending with this one, which does compile, though it obviously does not work (does not wake the server).
procedure WakeOnLan(const AMacAddress: string);
type
TMacAddress = array [1..6] of Byte;
TWakeRecord = packed record
Waker : TMACAddress;
MAC : array [0..15] of TMacAddress;
end;
var
I : Integer;
WR : TWakeRecord;
MacAddress : TMacAddress;
UDPClient : TIdUDPClient;
sData : string;
begin
FillChar(MacAddress, SizeOf(TMacAddress), 0);
sData := Trim(AMacAddress);
if Length(sData) = 17 then begin
for I := 1 to 6 do begin
MacAddress[I] := StrToIntDef('$' + Copy(sData, 1, 2), 0);
sData := Copy(sData, 4, 17);
end;
end;
for I := 1 to 6 do WR.Waker[I] := $FF;
for I := 0 to 15 do WR.MAC[I] := MacAddress;
UDPClient := TIdUDPClient.Create(nil);
try
// UDP.Host := '255.255.255.255';
// UDP.Port := 32767;
UDPClient.BroadCastEnabled := True;
UDPClient.Broadcast(RawToBytes(WR, SizeOf(TWakeRecord)), 7);
// UDP.SendBuffer(RawToBytes(WR, SizeOf(TWakeRecord)));
UDPClient.BroadcastEnabled := False;
finally
UDPClient.Free;
end;
end;
I don't want to use any IP addresses at all, just pure MAC address should do.
The original code was written for Indy 9. The Indy 10 equivalent would look more like this:
UDPClient := TIdUDPClient.Create(nil);
try
UDP.Host := '255.255.255.255';
UDP.Port := 32767;
UDP.IPVersion := Id_IPv4;
UDP.BroadcastEnabled := True;
UDP.SendBuffer(RawToBytes(WR, SizeOf(WR)));
finally
UDP.Free;
end;
Or:
UDPClient := TIdUDPClient.Create(nil);
try
UDP.IPVersion := Id_IPv4;
UDP.BroadCastEnabled := True;
UDP.SendBuffer('255.255.255.255', 32767, RawToBytes(WR, SizeOf(WR)));
finally
UDP.Free;
end;
Or:
UDP := TIdUDPClient.Create(nil);
try
UDP.IPVersion := Id_IPv4;
UDP.Broadcast(RawToBytes(WR, SizeOf(WR)), 32767);
finally
UDP.Free;
end;