Distributed programming/AutoHotkey: Difference between revisions
(split huge AutoHotkey entry from Distributed program) |
No edit summary |
||
Line 1: | Line 1: | ||
{{collection|Distributed Program}} |
{{collection|Distributed Program}} |
||
{{library|WinSock2.ahk}} |
|||
WinSock2 library created by derRaphael. Basic code structure created by Trikster. Untested. If someone reading this has two computers and AutoHotkey installed on both, please test. My other computers are all in states of semi-decay. |
WinSock2 library created by derRaphael. Basic code structure created by Trikster. Untested. If someone reading this has two computers and AutoHotkey installed on both, please test. My other computers are all in states of semi-decay. |
||
<div style="clear:both;width:full;overflow:scroll"><lang autohotkey> |
<div style="clear:both;width:full;overflow:scroll"><lang autohotkey>#Include WinSock2.ahk |
||
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,"[^\d]")) |
|||
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 Join`n |
|||
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<Nr>\d+) - (?P<Err>.*)",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 |
|||
} |
|||
#Persistent |
#Persistent |
||
#SingleInstance, force |
#SingleInstance, force |
||
Line 612: | Line 111: | ||
Put the above on one computer, and run it. Then put the below on a different computer (no need for a network, just add Internet!) and run it. |
Put the above on one computer, and run it. Then put the below on a different computer (no need for a network, just add Internet!) and run it. |
||
<div style="width:full;overflow:scroll"><lang autohotkey> |
<div style="width:full;overflow:scroll"><lang autohotkey>#Include WinSock2.ahk |
||
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,"[^\d]")) |
|||
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 Join`n |
|||
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<Nr>\d+) - (?P<Err>.*)",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 |
|||
} |
|||
#Persistent |
#Persistent |
||
#SingleInstance, force |
#SingleInstance, force |
Revision as of 16:57, 9 September 2009
This is an example of a library. You may see a list of other libraries used on Rosetta Code at Category:Solutions by Library.
WinSock2 library created by derRaphael. Basic code structure created by Trikster. Untested. If someone reading this has two computers and AutoHotkey installed on both, please test. My other computers are all in states of semi-decay.
- Persistent
- SingleInstance, force
- Include WinSock2.ahk ; derRaphaels WinSock Rewrite
SetBatchLines, -1 SetWorkingDir, %A_ScriptDir% Gui, Add, Button, gB1, Button number One! Gui, Add, Edit, vE1, Type in me! Gui, Add, Button, gB2, Press me after you're done typing! Gui, Add, DropDownList, vDDL1 gDDL1, Select something!||One|Two|Three|Four|Five|Six|Seven|Eight|Nine|Ten Gui, Add, Button, gB3, Click me!
Server := "irc.freenode.net" Port := "6667"
Channel := "#UIHjbfilgbafLIEfbAIJCICBGncaiJBHiwehFIUHEIbnjKCINJEhiUAHEJcKLACui" ; Choose something long and random - a channel sure to be deserted.
Nick := "somenick" ; Register this! You can drop it later if you want, but register it! Pass := "somepass" ; It can be any nick and any pass.
Name := "distributed program"
BotCmd := "!" OtherBotCmd := "~"
OnExit, CleanUp WS2_CleanUp() If (!Socket := WS2_Connect(Connection := Server . ":" . Port)) {
MsgBox, 16, Error!, An error occured wilist connecting to %Connection%
}
; Set OnMessage function WS2_AsyncSelect(Socket, "DataProcess") ; Send AUTH info to the server ; USER A-trivial-nickname a-domain-like-google.com some-trivial-stuff :your-real-name WS2_SendData(Socket, "USER " . Nick . " google.com AHKBOT :" . Name . "`n") ; All data send to the server must be ; followed by a newline. ; PASS A-trivial-pass WS2_SendData(Socket, "PASS " . Pass . "`n") ; NICK A-trivial-nick WS2_SendData(Socket, "NICK " . Nick . "`n") ; Join channel ; JOIN A-trivial-channel WS2_SendData(Socket, "JOIN " . Channel . "`n") Gui, Show
Return
DataProcess(Socket, Data) ; OnMessage function {
global Server,Port,Channel,Nick,Pass,Name,BotCMD StringSplit, Param, Data, %A_Space% Name := SubStr(Data, 2, InStr(Data, "!")-2) StringReplace, Command, Param5, % Chr(10),, All StringReplace, Command, Command, % Chr(13),, All If (Param1 == "PING") WS2_SendData(Socket, "PONG " . Param2 . "`n") Else If (RegExMatch(Data, ":\" . BotCMD . " ")) { If (Command == "B1" MsgBox, The other person pressed Button Number One Else If (Command == "B2E1") { MsgBox, The other person typed in Edit One then pressed Button Two Loop { If (A_Index <= 6) continue If Param%A_Index% out := out . " " . Param%A_Index% Else break } MsgBox, The other person typed:%out% } Else If (Command == "DDL1") MsgBox, The other person selected %Param7% in the drop-down-list. Else If (Command == "B3") MsgBox, The other person clicked Button Three. } return
} B1: WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " B1" return B2: Gui, Submit, NoHide WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " B2E1 " . E1 . " | " . B2 return DDL1: Gui, Submit, NoHide WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " DDL1 " . DDL1 return B3: WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " B3" return CleanUp: GuiClose: WS2_CleanUp()
ExitApp</lang>Put the above on one computer, and run it. Then put the below on a different computer (no need for a network, just add Internet!) and run it.
- Persistent
- SingleInstance, force
- Include WinSock2.ahk ; derRaphaels WinSock Rewrite
SetBatchLines, -1 SetWorkingDir, %A_ScriptDir% Gui, Add, Button, gB1, Button number One! Gui, Add, Edit, vE1, Type in me! Gui, Add, Button, gB2, Press me after you're done typing! Gui, Add, DropDownList, vDDL1 gDDL1, Select something!||One|Two|Three|Four|Five|Six|Seven|Eight|Nine|Ten Gui, Add, Button, gB3, Click me!
Server := "irc.freenode.net" Port := "6667"
Channel := "#UIHjbfilgbafLIEfbAIJCICBGncaiJBHiwehFIUHEIbnjKCINJEhiUAHEJcKLACui" ; Choose something long and random - a channel sure to be deserted.
Nick := "someothernick" ; Register this! You can drop it later if you want, but register it! Pass := "someotherpass" ; It can be any nick and any pass.
Name := "distributed program"
BotCmd := "~" OtherBotCmd := "!"
OnExit, CleanUp WS2_CleanUp() If (!Socket := WS2_Connect(Connection := Server . ":" . Port)) {
MsgBox, 16, Error!, An error occured wilist connecting to %Connection%
}
; Set OnMessage function WS2_AsyncSelect(Socket, "DataProcess") ; Send AUTH info to the server ; USER A-trivial-nickname a-domain-like-google.com some-trivial-stuff :your-real-name WS2_SendData(Socket, "USER " . Nick . " google.com AHKBOT :" . Name . "`n") ; All data send to the server must be ; followed by a newline. ; PASS A-trivial-pass WS2_SendData(Socket, "PASS " . Pass . "`n") ; NICK A-trivial-nick WS2_SendData(Socket, "NICK " . Nick . "`n") ; Join channel ; JOIN A-trivial-channel WS2_SendData(Socket, "JOIN " . Channel . "`n") Gui, Show
Return
DataProcess(Socket, Data) ; OnMessage function {
global Server,Port,Channel,Nick,Pass,Name,BotCMD StringSplit, Param, Data, %A_Space% Name := SubStr(Data, 2, InStr(Data, "!")-2) StringReplace, Command, Param5, % Chr(10),, All StringReplace, Command, Command, % Chr(13),, All If (Param1 == "PING") WS2_SendData(Socket, "PONG " . Param2 . "`n") Else If (RegExMatch(Data, ":\" . BotCMD . " ")) { If (Command == "B1" MsgBox, The other person pressed Button Number One Else If (Command == "B2E1") { MsgBox, The other person typed in Edit One then pressed Button Two Loop { If (A_Index <= 6) continue If Param%A_Index% out := out . " " . Param%A_Index% Else break } MsgBox, The other person typed:%out% } Else If (Command == "DDL1") MsgBox, The other person selected %Param7% in the drop-down-list. Else If (Command == "B3") MsgBox, The other person clicked Button Three. } return
} B1: WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " B1" return B2: Gui, Submit, NoHide WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " B2E1 " . E1 . " | " . B2 return DDL1: Gui, Submit, NoHide WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " DDL1 " . DDL1 return B3: WS2_SendData(Socket, "PRIVMSG " . Channel . " :" . OtherBotCmd . " B3" return CleanUp: GuiClose: WS2_CleanUp()
ExitApp</lang>