Currently WinSock2.ahk can't be used to send binary data. Ideally WS2_SendData would accept a pointer and data length, but since changing it now would cause compatibility issues, I suggest the following changes/additions:
Code:
WS2_SendData(WS2_Socket, StringToSend) {
Global __WSA_ErrMsg
If (__WSA_send(WS2_Socket, &StringToSend, StrLen(StringToSend))=-1) {
MsgBox, 16, %A_ScriptName%: Send-Error, % __WSA_ErrMsg
}
}
WS2_SendDataEx(WS2_Socket, DataToSend, DataLength) {
Global __WSA_ErrMsg
If (__WSA_send(WS2_Socket, DataToSend, DataLength)=-1) {
MsgBox, 16, %A_ScriptName%: Send-Error, % __WSA_ErrMsg
}
}
WS2_SendNumber(WS2_Socket, Num, Type="UInt") {
Global __WSA_ErrMsg
VarSetCapacity(DataToSend, 8)
DataLength := NumPut(Num, DataToSend, 0, Type) - &DataToSend
If (__WSA_send(WS2_Socket, &DataToSend, DataLength)=-1) {
MsgBox, 16, %A_ScriptName%: Send-Error, % __WSA_ErrMsg
}
}
; WSA Send - for internal use only
; Users are encouraged to use the WS2_SendData() Function
__WSA_send(__WSA_Socket, __WSA_Data, __WSA_DataLen)
{
Global __WSA_ErrMsg
Result := DllCall("Ws2_32\send"
, "UInt", __WSA_Socket
, "UInt", __WSA_Data
, "Int", __WSA_DataLen
, "Int", 0)
If (Result = -1)
__WSA_ErrMsg .= "Ws2_32\send " __WSA_GetLastError()
Return Result
}
I also recommend a few changes to __WSA_recv:
Code:
__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) ; 0 or -1 (probably never < -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_UDF != "" && (__WSA_BufferLength = 0 || __WSA_Err = __WSA_CONNRESET))
return 1, %__WSA_UDF%(__WSA_Socket, __WSA_Buffer:="", 0)
__WSA_ErrMsg .= "Ws2_32\recv indicated Winsock error " __WSA_Err "`n"
break
}
if __WSA_UDF != ; If set, call UserDefinedFunction and pass Buffer to it
%__WSA_UDF%(__WSA_Socket, __WSA_Buffer, __WSA_BufferLength)
}
return 1
}
I've added an optional third parameter for the user-defined callback function (__WSA_UDF), containing the length of the data received. This allows it to handle binary data, as long as it declares the second parameter ByRef. Additionally, the callback will be called with data:="" and length:=0 when the socket disconnects.
Finally, I suggest __WSA_ErrLookUp be replaced with the Win32 function FormatMessage:
Code:
__WSA_GetLastError(txt=1)
{
err := DllCall("Ws2_32\WSAGetLastError")
if txt {
VarSetCapacity(txt, 1024) ; "Limit" to 1024 chars.
if DllCall("FormatMessage", uint, 0x1200, uint, 0, int, err
, uint, 1024, str, txt, uint, 1024, uint, 0)
return "indicated Winsock error " . err . ":`n" . txt
}
return err
}
__WSA_ErrLookUp can then be deleted.
jdpmd wrote:
Instead of coding a pathway, you can put WinSock.ahk in LIB
I suggest simply naming the file "WS2.ahk" and using the WS2_*() functions as appropriate.