React to Wake On LAN magic packet using AutoHotkey

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
downloaderfan
Posts: 34
Joined: 09 Jun 2017, 09:19

React to Wake On LAN magic packet using AutoHotkey

Post by downloaderfan » 28 Jan 2023, 22:57

Hello,

I have a setup where I'm able to wake my laptop from sleep using Wake ON LAN magic packet sent by Alexa. I was wondering, when the laptop is On, can I make AHK read the WOL magic packet and react to it? I would like to put PC to sleep using the same WOL command.

I've found a utility that does something similar:
https://github.com/SR-G/sleep-on-lan

But it requires reversing the MAC address. I want the MAC address to be the same, so was wondering whether an AHK solution exists so that I can customise it.

User avatar
WAZAAAAA
Posts: 88
Joined: 13 Jan 2015, 19:48

Re: React to Wake On LAN magic packet using AutoHotkey

Post by WAZAAAAA » 27 Dec 2023, 01:24

Not the prettiest code since I couldn't make Socket.ahk work...
I used SimpleWoL on my Android to test WOL packets in the first place.
I put several Sleep calls and a Reload because that's the most braindead way I could come up with to deal with repeated packets.
The script will beep and put the PC in standby when it receives ANY UDP packet at port 9... but hey, works for me.

Code: Select all

;#Requires AutoHotkey v1
;slightly modified from https://www.autohotkey.com/boards/viewtopic.php?t=399
;Performs an action when any UDP packet is received on the specified port.



Port = 9 ;insert port to listen here
SetTimer, Recv, 1000 ;check packets queue every second
EnableMyToken() ;grant yourself the rights to put the PC in standby mode
Sleep,800
PacketReceivedAction() ;what to do when a packet arrives
{
	SoundBeep
	Sleep,800
	DllCall("ntdll\ZwInitiatePowerAction","Int",2,"Int",4,"UInt",0x80000000,"UChar",1) ;PC standby (S3)
	Reload
	Sleep,3000
}



#Persistent
OnExit, AppExit
AF_INET := 2
PF_INET := AF_INET
SOCK_DGRAM := 2
IPPROTO_UDP := 17
INADDR_ANY := 0
FIONREAD := 0x4004667F
;WSADESCRIPTION_LEN := 256, WSASYS_STATUS_LEN  := 128
WSADATAsize := 388 + (2 * 4) + A_PtrSize + (A_PtrSize - 2)
SOCKADDRsize := 16



;Init DLL
VarSetCapacity(WSADATA, WSADATAsize, 0)
If (DllCall("Ws2_32.dll\WSAStartup", "UShort", 0x0202, "Ptr", &WSADATA, "Int"))
	ErrorMsg("WSAStartup()")
;Socket
RecvSocket := DllCall("Ws2_32.dll\socket", "Int", PF_INET, "Int", SOCK_DGRAM, "Int", IPPROTO_UDP, "UPtr")
If (RecvSocket = 0xFFFFFF)
	ErrorMsg("socket()")
VarSetCapacity(SOCKADDR, SOCKADDRsize, 0)
NumPut(PF_INET, SOCKADDR, 0, "Short")
NumPut(DllCall("Ws2_32.dll\htons", "UShort", Port), SOCKADDR, 2, "UShort")
NumPut(INADDR_ANY, SOCKADDR, 4, "UInt")
;Bind
If DllCall("Ws2_32.dll\bind", "Ptr", RecvSocket, "Ptr", &SOCKADDR, "Int", SOCKADDRsize, "Int")
	ErrorMsg("bind()")
Return



Recv:
VarSetCapacity(Arg, A_PtrSize, 0)
If DllCall("Ws2_32.dll\ioctlsocket", "Ptr", RecvSocket, "UInt", FIONREAD, "Ptr", &Arg, "Int")
	ErrorMsg("ioctlsocket()")
If ((RecvLen := NumGet(Arg, "UInt")) > 0) {
	VarSetCapacity(Buffer, RecvLen, 0)
	VarSetCapacity(FromBuffer, 16, 0)
	FromBufferLen := 16
	Result := DllCall("Ws2_32.dll\recvfrom", "Ptr", RecvSocket, "Ptr", &Buffer, "UInt", RecvLen
                                          , "UInt", 0, "Ptr", &FromBuffer, "IntP", FromBufferLen, "Int")
	If (Result = -1)
		ErrorMsg("recvfrom()")
	FromIP := ""
	Received := ""
	Received := StrGet(&Buffer, RecvLen, "CP0")
	If (NumGet(FromBuffer, 0, "UShort") = AF_INET) {
		Loop, 4 {
			If (FromIP = "")
				FromIP := NumGet(FromBuffer, A_Index + 3, "UChar")
			Else
				FromIP .= "." . NumGet(FromBuffer, A_Index + 3, "UChar")
		}
	}
	NewReceived := FromIP . A_Tab . Received
	If NewReceived
		PacketReceivedAction()
;	If (NewReceived = LastReceived)
;		Return
;	LastReceived := NewReceived
;	MsgBox, 0, Received Data, %NewReceived%
}
Return


EnableMyToken() ;enable SeShutdownPrivilege token (example #4 in documentation https://www.autohotkey.com/docs/commands/Process.htm#ListEx)
{
	Process, Exist  ; Sets ErrorLevel to the PID of this running script.
	; Get the handle of this script with PROCESS_QUERY_INFORMATION (0x0400):
	h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", ErrorLevel, "Ptr")
	; Open an adjustable access token with this process (TOKEN_ADJUST_PRIVILEGES = 32):
	DllCall("Advapi32.dll\OpenProcessToken", "Ptr", h, "UInt", 32, "PtrP", t)
	VarSetCapacity(ti, 16, 0)  ; structure of privileges
	NumPut(1, ti, 0, "UInt")  ; one entry in the privileges array...
	; Retrieves the locally unique identifier of the privilege:
	DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", "SeShutdownPrivilege", "Int64P", luid)
	NumPut(luid, ti, 4, "Int64")
	NumPut(2, ti, 12, "UInt")  ; Enable this privilege: SE_PRIVILEGE_ENABLED = 2
	; Update the privileges of this process with the new access token:
	r := DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", t, "Int", false, "Ptr", &ti, "UInt", 0, "Ptr", 0, "Ptr", 0)
	DllCall("CloseHandle", "Ptr", t)  ; Close this access token handle to save memory.
	DllCall("CloseHandle", "Ptr", h)  ; Close this process handle to save memory.
}


ErrorMsg(Msg) {
;	MsgBox % Msg . " indicated Winsock error " . DllCall("Ws2_32.dll\WSAGetLastError") . "?"
	Reload
	ExitApp
}
AppExit:
DllCall("Ws2_32.dll\WSACleanup")
ExitApp
YOU'RE NOT ALEXANDER

Post Reply

Return to “Ask for Help (v1)”