⚠️ Warning: This is a draft ⚠️

This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.

If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.

```autohotkey /* WinSock2.ahk // a rewrite by derRaphael (w) Sep, 9 2008

based on the WinLIRC Script from Chris http://www.autohotkey.com/docs/scripts/WinLIRC.htm and on the WinLIRC Rewrite by ZedGecko http://www.autohotkey.com/forum/viewtopic.php?t=13829

__WSA_GetHostByName - Parts based upon scripts from DarviK and Tasman. Not much left of the origin source, but it was their achievement by doing the neccessary research. */

; WS2 Connect - This establishes a connection to a named resource ; The parameter is to be passed in an URI:Port manner. ; Returns the socket upon successfull connection, otherwise it ; returns -1. In the latter case more Information is in the global ; variable __WSA_ErrMsg ; ; Usage-Example: ; Pop3_Socket := WS2_Connect("mail.isp.com:110") ; See the Doc for more Information. WS2_Connect(lpszUrl) {

Global 

; split our targetURI 
__WinINet_InternetCrackURL("info://" lpszUrl,"__WSA") 

; name our port 
WS2_Port := __WSA_nPort 

; Init the Winsock connection 
if (     !( __WSA_ScriptInit()           )         ; Init the Scriptvariables 
      || !( __WSA_Startup()              ) ) {     ; Fire up the WSA 
    WS2_CleanUp()         ; Do a premature cleanup 
    return -1             ; and return an error indication 
} 
; check the URI if it's valid 
if (RegExMatch(__WSA_lpszHostName,"[^\d.]+")) ; Must be different than IP 
{ 
    WS2_IPAddress := __WSA_GetHostByName(__WSA_lpszHostName) 
} else {     ; Let's check if the IP is valid 
    StringSplit,__WSA_tmpIPFragment, __WSA_lpszHostName,. 
    Loop,4 
        If (    ( __WSA_tmpIPFragment%A_Index%<0   ) 
             || ( __WSA_tmpIPFragment%A_Index%>255 ) 
             || ( __WSA_tmpIPFragment0!=4          ) ) { 
            __WSA_IPerror = 1 
            Break 
        } 
    If (__WSA_IPerror=1) 
        __WSA_ErrMsg .= "No valid IP Supplied" 
    else 
        WS2_IPAddress := __WSA_lpszHostName 
} 

; CONVERSIONS 

; The htons function returns the value in TCP/IP network byte order. 
; http://msdn.microsoft.com/en-us/library/ms738557(VS.85).aspx 
__WSA_Port                := DllCall("Ws2_32\htons", "UShort", WS2_Port) 

; The inet_addr function converts a string containing an IPv4 dotted-decimal 
; address into a proper address for the IN_ADDR structure. 
; inet_addr: http://msdn.microsoft.com/en-us/library/ms738563(VS.85).aspx 
; IN_ADDR:   http://msdn.microsoft.com/en-us/library/ms738571(VS.85).aspx 
__WSA_InetAddr           := DllCall("Ws2_32\inet_addr", "Str", WS2_IPAddress) 

If (     ( __WSA_Socket:=__WSA_Socket() ) 
      && ( __WSA_Connect()              )   ) 
    return __WSA_Socket   ; All went OK, return the SocketID 
Else { 
    WS2_CleanUp()         ; Do a premature cleanup 
    return -1             ; and return an error indication 
} 

}

; WS2 OnMessage - This function defines, whatever should happen when ; a Message is received on the socket. ; Expected Parameter: ; Ws2_Socket => Socket returned from WS2_Connect() Call ; UDF => An UserDefinedFunction to which the received ; Data will be passed to ; Optional Parameter: ; WindowMessage => A number indicating upon which WM_Message to react ; ; Returns -1 on error, 0 on success

WS2_AsyncSelect(Ws2_Socket,UDF,WindowMessage="") { Global __WSA_ErrMsg If ( ( StrLen(Ws2_Socket)=0 ) || ( StrLen(UDF)=0 ) ) { res := -1 } else { If ( (StrLen(WindowMessage)=0) || (WindowMessage+0=0) ) WindowMessage := 0x5000 res := __WSA_AsyncSelect(Ws2_Socket, UDF, WindowMessage) } return res }

WS2_SendData(WS2_Socket,DataToSend) { Global __WSA_ErrMsg If (__WSA_send(WS2_Socket, DataToSend)=-1) { MsgBox, 16, %A_ScriptName%: Send-Error, % __WSA_ErrMsg } }

; WS2 Cleanup - This needs to be called whenever Your Script exits ; Usually this is invoked by some OnExit, Label subroutines. WS2_CleanUp() { DllCall("Ws2_32\WSACleanup") }

WS2_Disconnect(WS2_Socket) { Global __WSA_ErrMsg if (res := __WSA_CloseSocket(WS2_Socket)) MsgBox, 16, %A_ScriptName%: CloseSocket-Error, % __WSA_ErrMsg }

; WS2 ScriptInit - for internal use only ; Initializes neccessary variables for this Script. __WSA_ScriptInit() { ; CONTANTS

; We're working with version 2 of Winsock 
Local VersionRequested    := 2 
; from http://msdn.microsoft.com/en-us/library/ms742212(VS.85).aspx 
Local AF_INET             := 2 
Local SOCK_STREAM         := 1 
Local IPPROTO_TCP         := 6 
Local FD_READ             := 0x1 
Local FD_CLOSE            := 0x20 

__AI_PASSIVE              := 1 

__WSA_WSVersion           := VersionRequested 
__WSA_SocketType          := SOCK_STREAM 
__WSA_SocketProtocol      := IPPROTO_TCP 
__WSA_SocketAF            := AF_INET 
__WSA_lEvent              := FD_READ|FD_CLOSE 

__WSA_WOULDBLOCK          := 10035  ; http://www.sockets.com/err_lst1.htm#WSAECONNRESET 
__WSA_CONNRESET           := 10054  ; http://www.sockets.com/err_lst1.htm#WSAECONNRESET 

return 1 

}

; WS2 Startup - for internal use only ; Initializes the Winsock 2 Adapter __WSA_Startup() { Global WSAData, __WSA_ErrMsg, __WSA_WSVersion

; It's a good idea, to have a __WSA_ErrMsg Container, so any Error Msgs 
; may be catched by the script. 
__WSA_ErrMsg := "" 

; Generate Structure for the lpWSAData 
; as stated on http://msdn.microsoft.com/en-us/library/ms742213.aspx 
; More on WSADATA (structure) to be found here: 
; http://msdn.microsoft.com/en-us/library/ms741563(VS.85).aspx 
VarSetCapacity(WSAData, 32) 
result := DllCall("Ws2_32\WSAStartup", "UShort", __WSA_WSVersion, "UInt", &WSAData) 

if (ErrorLevel) 
    __WSA_ErrMsg .= "Ws2_32\WSAStartup could not be called due to error " ErrorLevel "`n" 
                  . "Winsock 2.0 or higher is required.`n" 
if (result!=0) 
    __WSA_ErrMsg .= "Ws2_32\WSAStartup " __WSA_GetLastError() 

If (StrLen(__WSA_ErrMsg)>0) 
    Return -1 
Else 
    Return 1 

}

; WS2 Socket Descriptor - for internal use only ; Sets type and neccessary structures for a successfull connection __WSA_Socket() { Global __WSA_ErrMsg, __WSA_SocketProtocol, __WSA_SocketType, __WSA_SocketAF

; Supposed to return a descriptor referencing the new socket 
; http://msdn.microsoft.com/en-us/library/ms742212(VS.85).aspx 
__WSA_Socket := DllCall("Ws2_32\socket" 
                        , "Int", __WSA_SocketAF 
                        , "Int", __WSA_SocketType 
                        , "Int", __WSA_SocketProtocol) 
if (socket = -1) 
    __WSA_ErrMsg .= "Ws2_32\socket " __WSA_GetLastError() 

If (StrLen(__WSA_ErrMsg)>0) 
    Return -1 
Else 
    Return __WSA_Socket 

}

; WS2 Connection call - for internal use only ; Establishes a connection to a foreign IP at the specified port __WSA_Connect() { Global __WSA_ErrMsg, __WSA_Port, __WSA_Socket, __WSA_InetAddr, __WSA_SocketAF

; Generate socketaddr structure for the connect() 
; http://msdn.microsoft.com/en-us/library/ms740496(VS.85).aspx 
__WSA_SockAddrNameLen  := 16 
VarSetCapacity(__WSA_SockAddr, __WSA_SockAddrNameLen) 
NumPut(__WSA_SocketAF, __WSA_SockAddr, 0, "UShort") 
NumPut(__WSA_Port,     __WSA_SockAddr, 2, "UShort") 
NumPut(__WSA_InetAddr, __WSA_SockAddr, 4) 

; The connect function establishes a connection to a specified socket. 
; http://msdn.microsoft.com/en-us/library/ms737625(VS.85).aspx 
result := DllCall("Ws2_32\connect" 
                    , "UInt", __WSA_Socket 
                    , "UInt", &__WSA_SockAddr 
                    , "Int" , __WSA_SockAddrNameLen) 
if (result) 
    __WSA_ErrMsg .= "Ws2_32\connect " __WSA_GetLastError() 

If (StrLen(__WSA_ErrMsg)>0) 
    Return -1 
Else 
    Return 1 

}

/* This code based originally upon an example by DarviK http://www.autohotkey.com/forum/topic8871.html and on the modifcations by Tasman http://www.autohotkey.com/forum/viewtopic.php?t=9937 */ ; Resolves canonical domainname to IP __WSA_GetHostByName(url) { Global __WSA_ErrMsg ; gethostbyname returns information about a domainname into a Hostent Structure ; http://msdn.microsoft.com/en-us/library/ms738524(VS.85).aspx IP := "" if ((PtrHostent:=DllCall("Ws2_32\gethostbyname","str",url)) != 0) { Loop, 1 ; 3 is max No of retrieved addresses If (PtrTmpIP := NumGet(NumGet(PtrHostent+12)+(offset:=(A_Index-1)*4),offset)) { IP := (IP) ? IP "|" : "" Loop, 4 ; Read our IP address IP .= NumGet(PtrTmpIP+offset,(A_Index-1 ),"UChar") "." IP := SubStr(IP,1,-1) } else ; No more IPs left Break result := IP } else { __WSA_ErrMsg .= "Ws2_32\gethostbyname failed`n " result := -1 } return result }

; Return the last Error with a lil bit o' text if neccessary ; Note: the txt variable is set to 0 when checking for received content __WSA_GetLastError(txt=1) { Err := DllCall("Ws2_32\WSAGetLastError") ExtraInfo := __WSA_ErrLookUp(RegExReplace(Err,"1")) If ((InStr(ExtraInfo,"Sorry, no")) || (txt!=1)) ExtraInfo := "" Return ( txt ? "indicated Winsock error " : "") . Err . ( txt ? "`n" ExtraInfo : "") }

; WS2 AsyncSelect - for internal use only ; Sets up an Notification Handler for Receiving Messages ; Expected Parameters: Socket from Initialisation ; Optional: NotificationMsg - default 0x5000 ; WSA_DataReiceiver - an different Name to standard ; wm_* processor function. ; default __WSA_ReceiveData ; Returns -1 on Error, 0 on success __WSA_AsyncSelect(__WSA_Socket, UDF, __WSA_NotificationMsg=0x5000 ,__WSA_DataReceiver="__WSA_recv") { Global

__WSA_UDF := UDF 

OnMessage(__WSA_NotificationMsg, __WSA_DataReceiver) 
; The WSAAsyncSelect function requests Windows message-based notification 
; of network events for a socket. 
; http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx 
Result := DllCall("Ws2_32\WSAAsyncSelect" 
            , "UInt", __WSA_Socket 
            , "UInt", __WSA_GetThisScriptHandle() 
            , "UInt", __WSA_NotificationMsg 
            , "Int",  __WSA_lEvent) 
if (Result) { 
    __WSA_ErrMsg .= "Ws2_32\WSAAsyncSelect() " . __WSA_GetLastError() 
    Result := -1 
} 
Return Result 

}

; WS2 Receive - for internal use only ; Triggers upon Notification Handler when Receiving Messages __WSA_recv(wParam, lParam) { Global __WSA_UDF, __WSA_ErrMsg ; __WSA_UDF containes the name of the UserDefinedFunction to call when the event ; has been triggered and text may be processed (allthough the reveived text might ; be inclomplete, especially when receiving large chunks of data, like in eMail- ; attachments or sometimes in IRC). The UDF needs to accept two parameter: socket ; and the received buffer

__WSA_Socket := wParam 
__WSA_BufferSize = 4096 
Loop 
{ 
    VarSetCapacity(__WSA_Buffer, __WSA_BufferSize, 0) 
    __WSA_BufferLength := DllCall("Ws2_32\recv" 
                                    , "UInt", __WSA_Socket 
                                    , "Str",  __WSA_Buffer 
                                    , "Int",  __WSA_BufferSize 
                                    , "Int",  0 ) 
    if (__WSA_BufferLength = 0) 
        break 
    if (__WSA_BufferLength = -1) 
    { 
        __WSA_Err := __WSA_GetLastError(0) 
        ; __WSA_WOULDBLOCK (from http://www.sockets.com/) 
        ; The socket is marked as non-blocking (non-blocking operation mode), and 
        ; the requested operation is not complete at this time. The operation is 
        ; underway, but as yet incomplete. 
        if (__WSA_Err = __WSA_WOULDBLOCK ) 
            return 1 

        ; __WSA_CONNRESET: (from http://www.sockets.com/) 
        ; A connection was forcibly closed by a peer. This normally results from 
        ; a loss of the connection on the remote socket due to a timeout or a reboot. 
        if (__WSA_Err != __WSA_CONNRESET) 
            __WSA_ErrMsg .= "Ws2_32\recv indicated Winsock error " __WSA_Err "`n" 
        break 
    } 

    if (StrLen(__WSA_UDF)!=0) ; If set, call UserDefinedFunction and pass Buffer to it 
        %__WSA_UDF%(__WSA_Socket,__WSA_Buffer) 
} 
return 1 

}

; WSA Send - for internal use only ; Users are encouraged to use the WS2_SendData() Function __WSA_send(__WSA_Socket, __WSA_Data) { Global __WSA_ErrMsg

Result := DllCall("Ws2_32\send" 
                   , "UInt", __WSA_Socket 
                   , "Str",  __WSA_Data 
                   , "Int", StrLen(__WSA_Data) 
                   , "Int", 0) 

If (Result = -1) __WSA_ErrMsg .= "Ws2_32\send " __WSA_GetLastError() Return Result }

; Closes Open Socket - for internal use only ; Returns 0 on success __WSA_CloseSocket(__WSA_Socket) { Global __WSA_ErrMsg

Result := DllCall("Ws2_32\closesocket" 
                   , "UInt", __WSA_Socket) 
If (Result != 0) 
  __WSA_ErrMsg .=  "Ws2_32\closesocket " __WSA_GetLastError() 

Return result 

}

; GetThisScriptHandle - for internal use only ; Returns the handle of the executing script __WSA_GetThisScriptHandle() {

HiddenWindowsSave := A_DetectHiddenWindows 

DetectHiddenWindows On 
ScriptMainWindowId := WinExist("ahk_class AutoHotkey ahk_pid " DllCall("GetCurrentProcessId")) 
DetectHiddenWindows %HiddenWindowsSave% 

Return ScriptMainWindowId 

}

; Lookup Winsock ErrCode - for internal use only ; This list is form http://www.sockets.com __WSA_ErrLookUp(sNumber) { WSA_ErrorList = (LTrim Joinn 10004 - Interrupted system call 10009 - Bad file number 10013 - Permission denied 10014 - Bad address 10022 - Invalid argument 10024 - Too many open files 10035 - Operation would block 10036 - Operation now in progress 10037 - Operation already in progress 10038 - Socket operation on non-socket 10039 - D estination address required 10040 - Message too long 10041 - Protocol wrong type for socket 10042 - Bad protocol option 10043 - Protocol not supported 10044 - Socket type not supported 10045 - Operation not supported on socket 10046 - Protocol family not supported 10047 - Address family not supported by protocol family 10048 - Address already in use 10049 - Can't assign requested address 10050 - Network is down 10051 - Network is unreachable 10052 - Net dropped connection or reset 10053 - Software caused connection abort 10054 - Connection reset by peer 10055 - No buffer space available 10056 - Socket is already connected 10057 - Socket is not connected 10058 - Can't send after socket shutdown 10059 - Too many references, can't splice 10060 - Connection timed out 10061 - Connection refused 10062 - Too many levels of symbolic links 10063 - File name too long 10064 - Host is down 10065 - No Route to Host 10066 - Directory not empty 10067 - Too many processes 10068 - Too many users 10069 - Disc Quota Exceeded 10070 - Stale NFS file handle 10091 - Network SubSystem is unavailable 10092 - WINSOCK DLL Version out of range 10093 - Successful WSASTARTUP not yet performed 10071 - Too many levels of remote in path 11001 - Host not found 11002 - Non-Authoritative Host not found 11003 - Non-Recoverable errors: FORMERR, REFUSED, NOTIMP 11004 - Valid name, no data record of requested type 11004 - No address, look for MX record ) ExNr := 0, ExErr := "Sorry, but no definition available." Loop,Parse,WSA_ErrorList,n { RegExMatch(A_LoopField,"(?P\d+) - (?P.*)",Ex) if (sNumber = ExNr) break } Return ExNr " means " ExErr "`n" } ; WinINet InternetCrackURL - for internal use only ; v 0.1 / (w) 25.07.2008 by derRaphael / zLib-Style release ; This routine was originally posted here: ; http://www.autohotkey.com/forum/viewtopic.php?p=209957#209957 __WinINet_InternetCrackURL(lpszUrl,arrayName="URL") { local hModule, offset_name_length hModule := DllCall("LoadLibrary", "Str", "WinINet.Dll")

; SetUpStructures for URL_COMPONENTS / needed for InternetCrackURL 
; http://msdn.microsoft.com/en-us/library/aa385420(VS.85).aspx 
offset_name_length:= "4-lpszScheme-255|16-lpszHostName-1024|28-lpszUserName-1024|" 
                   . "36-lpszPassword-1024|44-lpszUrlPath-1024|52-lpszExtrainfo-1024" 

VarSetCapacity(URL_COMPONENTS,60,0) 
; Struc Size               ; Scheme Size                  ; Max Port Number 
NumPut(60,URL_COMPONENTS,0), NumPut(255,URL_COMPONENTS,12), NumPut(0xffff,URL_COMPONENTS,24) 
Loop,Parse,offset_name_length,| 
{ 
    RegExMatch(A_LoopField,"(?P<Offset>\d+)-(?P<Name>[a-zA-Z]+)-(?P<Size>\d+)",iCU_) 
    VarSetCapacity(%iCU_Name%,iCU_Size,0) 
    NumPut(&%iCU_Name%,URL_COMPONENTS,iCU_Offset) 
    NumPut(iCU_Size,URL_COMPONENTS,iCU_Offset+4) 
} 

; Split the given URL; extract scheme, user, pass, authotity (host), port, path, and query (extrainfo) 
; http://msdn.microsoft.com/en-us/library/aa384376(VS.85).aspx 
DllCall("WinINet\InternetCrackUrlA","Str",lpszUrl,"uInt",StrLen(lpszUrl),"uInt",0,"uInt",&URL_COMPONENTS) 
; Update variables to retrieve results 
Loop,Parse,offset_name_length,| 
{ 
    RegExMatch(A_LoopField,"-(?P<Name>[a-zA-Z]+)-",iCU_) 
    VarSetCapacity(%iCU_Name%,-1) 
    %arrayName%_%iCU_Name% := % %iCU_Name% 
} 
%arrayName%_nPort:=NumGet(URL_COMPONENTS,24,"uInt") 
DllCall("FreeLibrary", "UInt", hModule)                    ; unload the library 

}

</div>