我创建了下面的Excel VBA代码,该代码使用Winsock API连接到IP地址,从Excel单元格发送文本字符串,然后返回接收文本字符串。
我的代码最初指向带有端口127.0.0.1
的IP地址80
,没有任何问题。但是,此后我不得不将目标端口更新为60401
,这还需要将端口输入变量sin_port
更改为Long,因为新端口超过了VBA Integer的最大长度。在这些更新之后,代码仍然可以编译,但是Winsock API不会处理任何东西?
我认为该错误可能与sin_zero
变量有关,该变量可能随着端口长度的增加而缓冲了太多的零?我曾尝试调整此变量并在其他地方诊断代码,但是在修改代码几个小时后,它仍然无法处理。
非常感谢所有帮助。谢谢你。
原始代码-端口80-成功编译和处理
Type WSAData
wVersion As Integer
wHighVersion As Integer
szDescription(0 To 255) As Byte
szSystemStatus(0 To 128) As Byte
iMaxSockets As Integer
iMaxUdpDg As Integer
lpVendorInfo As Long
End Type
Type sockaddr_in
sin_family As Integer
sin_port As Integer
sin_addr As Long
sin_zero(0 to 7) As Byte
End Type
Public Declare Function WSAStartup Lib "ws2_32" ( _
ByVal wVersionRequired As Integer, ByRef lpWSAData As WSAData) As Long
Public Declare Function WSAGetLastError Lib "ws2_32" () As Long
Public Declare Function socket Lib "ws2_32" ( _
ByVal af As Long, ByVal socktype As Long, ByVal protocol As Long) As Long
Public Declare Function connect Lib "ws2_32" ( _
ByVal sock As Long, ByRef name As sockaddr_in, ByVal namelen As Integer) As Long
Public Declare Function send Lib "ws2_32" ( _
ByVal sock As Long, ByVal buf As String, ByVal bufLen As Long, ByVal flags As Long) As Long
Public Declare Function recv Lib "ws2_32" ( _
ByVal sock As Long, ByRef buf As Byte, ByVal bufLen As Long, ByVal flags As Long) As Long
Public Declare Function inet_addr Lib "ws2_32" ( _
ByVal s As String) As Long
Public Declare Function htons Lib "ws2_32" ( _
ByVal hostshort As Long) As Long
Function FetchData() As String
Dim iReturn As Long
Dim wsaDat As WSAData
iReturn = WSAStartup(&H202, wsaDat)
If iReturn <> 0 Then
MsgBox "WSAStartup failed", 0, ""
End If
Dim sock As Long
Dim sock1 As Long
Dim lasterr As Long
Dim i As Long
Dim buf(10) As Byte
Dim s As String
Dim j As Integer
sock = socket(2, 1, 6)
Dim addr As sockaddr_in
addr.sin_family = 2
addr.sin_port = htons(80)
addr.sin_addr = inet_addr("127.0.0.1")
i = connect(sock, addr, LenB(addr))
i = send(sock, "*SRTF" & vbCr, 6, 0)
i = recv(sock, buf(0), 10, 0)
For j = 0 To i - 1
s = s & Chr(buf(j))
Next
FetchData = s
End Function
Sub Button2_Click()
Range("C3").Formula = FetchData()
End Sub
新代码-端口60401-编译,但不处理?
Type WSAData
wVersion As Integer
wHighVersion As Integer
szDescription(0 To 255) As Byte
szSystemStatus(0 To 128) As Byte
iMaxSockets As Integer
iMaxUdpDg As Integer
lpVendorInfo As Long
End Type
Type sockaddr_in
sin_family As Integer
sin_port As Long
sin_addr As Long
sin_zero(0 to 7) As Byte
End Type
Public Declare Function WSAStartup Lib "ws2_32" ( _
ByVal wVersionRequired As Integer, ByRef lpWSAData As WSAData) As Long
Public Declare Function WSAGetLastError Lib "ws2_32" () As Long
Public Declare Function socket Lib "ws2_32" ( _
ByVal af As Long, ByVal socktype As Long, ByVal protocol As Long) As Long
Public Declare Function connect Lib "ws2_32" ( _
ByVal sock As Long, ByRef name As sockaddr_in, ByVal namelen As Integer) As Long
Public Declare Function send Lib "ws2_32" ( _
ByVal sock As Long, ByVal buf As String, ByVal bufLen As Long, ByVal flags As Long) As Long
Public Declare Function recv Lib "ws2_32" ( _
ByVal sock As Long, ByRef buf As Byte, ByVal bufLen As Long, ByVal flags As Long) As Long
Public Declare Function inet_addr Lib "ws2_32" ( _
ByVal s As String) As Long
Public Declare Function htons Lib "ws2_32" ( _
ByVal hostshort As Long) As Long
Function FetchData() As String
Dim iReturn As Long
Dim wsaDat As WSAData
iReturn = WSAStartup(&H202, wsaDat)
If iReturn <> 0 Then
MsgBox "WSAStartup failed", 0, ""
End If
Dim sock As Long
Dim sock1 As Long
Dim lasterr As Long
Dim i As Long
Dim buf(10) As Byte
Dim s As String
Dim j As Integer
sock = socket(2, 1, 6)
Dim addr As sockaddr_in
addr.sin_family = 2
addr.sin_port = htons(60401)
addr.sin_addr = inet_addr("127.0.01")
i = connect(sock, addr, LenB(addr))
i = send(sock, "*SRTF" & vbCr, 6, 0)
i = recv(sock, buf(0), 10, 0)
For j = 0 To i - 1
s = s & Chr(buf(j))
Next
FetchData = s
End Function
Sub Button2_Click()
Range("C3").Formula = FetchData()
End Sub
最佳答案
您更改了sockaddr_in
的定义,以将更大的数据类型用于sin_port
字段。你不能那样做。您需要恢复原始定义以与Winsock保持兼容。
您对htons()
的定义也是错误的。 htons()
中的实际ws2_32
函数对16位数字进行操作,而不是您定义的32位数字(htonl()
对32位数字进行操作)。
您遇到的真正问题是VBA的Integer
类型是带符号的,它可以容纳的最高值为32767。如果尝试使用更高的值,它将换为负数。
Winsock的实际sockaddr_in
结构(和htons()
函数)对sin_port
字段使用16位无符号类型。 VBA根本没有16位无符号类型。因此,您必须忍受16位带符号Integer
的限制。
您需要修正您的定义:
Type sockaddr_in
sin_family As Integer
sin_port As Integer
sin_addr As Long
sin_zero(0 to 7) As Byte
End Type
Public Declare Function htons Lib "ws2_32" ( _ ByVal hostshort As Integer) As Integer
话虽如此,无符号数字60401是hex
0xEBF1
。该值与带符号的-5135相同。当字节被0xF1EB
交换时,它变成htons()
(-3605)。因此,请尝试以下方法之一:
addr.sin_port = htons(&HEBF1)
addr.sin_port = htons(-5135)
addr.sin_port = -3605
此外,
inet_addr("127.0.01")
应该读取inet_addr("127.0.0.1")
。
关于vba - VBA Winsock无法使用更长的端口长度(sin_port),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43197814/