Code: Select all
MsgBox, % GetNetworkTime()
GetNetworkTime(Server := "", Port := "") {
; stackoverflow.com/questions/1193955/how-to-query-an-ntp-server-using-c
Static NtpServer := "time.windows.com"
, NtpPort := 123
; -----------------------------------------------------------------------------------------------------------------------------
If (Server = "")
Server := NtpServer
If (Port = "")
Port := NtpPort
; -----------------------------------------------------------------------------------------------------------------------------
Ws2 := DllCall("LoadLibrary", "Str", "Ws2_32.dll")
If !(Ws2) {
Msg := "WS2_32.dll could not be loaded!"
Return GetNetworkTime_Error(Msg, Ws2)
}
; -----------------------------------------------------------------------------------------------------------------------------
; Initialize the winsock library
VarSetCapacity(WsaData, 512, 0) ; more than sufficient
If (DllCall("Ws2_32\WSAStartup", "UShort", 0x0202, "UInt", &WsaData) <> 0) { ; Request Winsock 2.2
Msg := "WSAStartup() could not be called due to error " . A_LastError . " - " . ErrorLevel
. "`nWinsock 2.2 or higher is required."
Return GetNetworkTime_Error(Msg, Ws2)
}
; -----------------------------------------------------------------------------------------------------------------------------
; Name resolution
If !(HOSTENT := DllCall("Ws2_32.dll\gethostbyname", "AStr", Server, "UPtr")) {
Msg := "gethostbyname failed with error " . DllCall("Ws2_32.dll\WSAGetLastError", "Int")
Return GetNetworkTime_Error(Msg, Ws2)
}
PAddrList := NumGet(HOSTENT + 0, (2 * A_PtrSize) + 4 + (A_PtrSize - 4), "UPtr")
PIPAddr := NumGet(PAddrList + 0, 0, "UPtr")
Addr := StrGet(DllCall("Ws2_32.dll\inet_ntoa", "UInt", NumGet(PIPAddr + 0, 0, "UInt"), "UPtr"), "CP0")
InetAddr := DllCall("Ws2_32.dll\inet_addr", "AStr", Addr, "UInt") ; convert address to 32-bit UInt
If (InetAddr = 0xFFFFFFFF) {
Msg := "inet_addr failed for address " . Addr
Return GetNetworkTime_Error(Msg, Ws2)
}
; -----------------------------------------------------------------------------------------------------------------------------
; Create a socket: AF_INET = 2, SOCK_DGRAM = 2, IPPROTO_UDP = 17
Socket := DllCall("Ws2_32\socket", "UInt", 2, "UInt", 2, "UInt", 17, "Int")
If (Socket = -1) { ; INVALID_SOCKET = -1
Msg := "socket() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
Return GetNetworkTime_Error(Msg, Ws2)
}
; -----------------------------------------------------------------------------------------------------------------------------
; Connect to the socket
SocketAddrSize := 16
VarSetCapacity(SocketAddr, SocketAddrSize, 0)
VarSetCapacity(SocketAddr, SocketAddrSize, 0)
NumPut(2, SocketAddr, 0, "Short") ; sin_family = AF_INET
NumPut(DllCall("Ws2_32\htons", "UShort", Port), SocketAddr, 2, "UShort") ; sin_port
Numput(InetAddr, SocketAddr, 4, "UInt") ; sin_addr.s_addr
; Attempt connection
If DllCall("Ws2_32\connect", "UInt", Socket, "UInt", &SocketAddr, "Int", SocketAddrSize) {
Msg := "connect() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
Return GetNetworkTime_Error(Msg, Ws2)
}
; -----------------------------------------------------------------------------------------------------------------------------
; Send an NTP request
SocketError := -1
VarSetCapacity(Data, 48, 0)
NumPut(0x1B, Data, "UChar") ; LI = 0 (no warning), VN = 3 (IPv4 only), Mode = 3 (Client Mode)
SendRet := DllCall("Ws2_32\send", "UInt", Socket, "Str", Data, "Int", 48, "Int", 0, "Int")
If (SendRet = SocketError) {
Msg := "send() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
Return GetNetworkTime_Error(Msg, Ws2)
}
; -----------------------------------------------------------------------------------------------------------------------------
; Shutdown sending
DllCall("Ws2_32\shutdown", "UInt", Socket, "Int", 1) ; SD_SEND = 1
; -----------------------------------------------------------------------------------------------------------------------------
; Get the answer
RecvRet := DllCall("Ws2_32\recv", "UInt", Socket, "Ptr", &Data, "Int", 48, "Int", 0, "Int")
If (RecvRet = SocketError) {
Msg := "recv() indicated Winsock error " . DllCall("Ws2_32\WSAGetLastError")
Return GetNetworkTime_Error(Msg, Ws2)
}
; -----------------------------------------------------------------------------------------------------------------------------
; Free resources
DllCall("Ws2_32\closesocket", "UInt", Socket)
DllCall("Ws2_32.dll\WSACleanup") ; Terminate the use of the Winsock 2 DLL
DllCall("FreeLibrary", "Ptr", Ws2)
; -----------------------------------------------------------------------------------------------------------------------------
; Swap byte order
Sek := (NumGet(Data, 40, "Uchar") << 24) | (NumGet(Data, 41, "Uchar") << 16) | (NumGet(Data, 42, "Uchar") << 8)
| NumGet(Data, 43, "Uchar")
DT := "19000101"
DT += Sek, S
Return DT
}
GetNetworkTime_Error(Msg, HMOD, RetVal := 0) {
MsgBox, 0, %A_ThisFunc%, %Msg%
DllCall("Ws2_32.dll\WSACleanup") ; Terminate the use of the Winsock 2 DLL
DllCall("FreeLibrary", "Ptr", HMOD)
Return RetVal
}
Ich habe das nur gegen den Microsoft Server getestet. Damit läuft es hier.