我使用来自这里的代码进行了一些更改--在某些定义中添加了私有关键字,因为Excel报告了错误,并将类型更改为IPRAW/ICMP。
最后,我在数据包的数据部分的wireshark中看到垃圾,但是数据大小是正确的(3个字节)。当执行sendBuf时,我检查了sendTo实际上包含了作为三个'a‘的第一个字节。怎么啦?
数据是使用清单底部的CommandButton1_Click()子发送的。
这是密码
'reference
'http://msdn.microsoft.com/en-us/library/windows/desktop/ms740673(v=vs.85).aspx
Const INVALID_SOCKET = -1
Const WSADESCRIPTION_LEN = 256
Enum AF
AF_UNSPEC = 0
AF_INET = 2
AF_IPX = 6
AF_APPLETALK = 16
AF_NETBIOS = 17
AF_INET6 = 23
AF_IRDA = 26
AF_BTH = 32
End Enum
Enum sock_type
SOCK_STREAM = 1
SOCK_DGRAM = 2
SOCK_RAW = 3
SOCK_RDM = 4
SOCK_SEQPACKET = 5
End Enum
Enum Protocol
IPPROTO_ICMP = 1
IPPROTO_IGMP = 2
BTHPROTO_RFCOMM = 3
IPPROTO_TCP = 6
IPPROTO_UDP = 17
IPPROTO_ICMPV6 = 58
IPPROTO_RM = 113
End Enum
'Type sockaddr
' sa_family As Integer
' sa_data(0 To 13) As Byte
'End Type
Private Type sockaddr_in
sin_family As Integer
sin_port As Integer
sin_addr(0 To 3) As Byte
sin_zero(0 To 7) As Byte
End Type
Private Type socket
pointer As Long
End Type
Private Type LPWSADATA_Type
wVersion As Integer
wHighVersion As Integer
szDescription(0 To WSADESCRIPTION_LEN) As Byte
szSystemStatus(0 To WSADESCRIPTION_LEN) As Byte
iMaxSockets As Integer
iMaxUdpDg As Integer
lpVendorInfo As Long
End Type
Private Declare Function WSAGetLastError Lib "Ws2_32.dll" () As Integer
Private Declare Function WSAStartup Lib "Ws2_32.dll" (ByVal wVersionRequested As Integer, ByRef lpWSAData As LPWSADATA_Type) As Long
Private Declare Function sendto Lib "Ws2_32.dll" (ByVal socket As Long, ByRef buf() As Byte, ByVal length As Long, ByVal flags As Long, ByRef toaddr As sockaddr_in, tolen As Long) As Long
Private Declare Function f_socket Lib "Ws2_32.dll" Alias "socket" (ByVal AF As Long, ByVal stype As Long, ByVal Protocol As Long) As Long
Private Declare Function closesocket Lib "Ws2_32.dll" (ByVal socket As Long) As Long
Private Declare Sub WSACleanup Lib "Ws2_32.dll" ()
Sub SendPacket(Message As String, IP As String, Port As Integer)
Dim ConnectSocket As socket
Dim wsaData As LPWSADATA_Type
Dim iResult As Integer: iResult = 0
Dim send_sock As sock_type: send_sock = INVALID_SOCKET
Dim iFamily As AF: iFamily = AF_INET
Dim iType As Integer: iType = SOCK_RAW 'SOCK_UDP
Dim iProtocol As Integer: iProtocol = IPPROTO_ICMP 'IPPROTO_UDP
Dim SendBuf(0 To 1023) As Byte
Dim BufLen As Integer: BufLen = 1024
Dim RecvAddr As sockaddr_in: RecvAddr.sin_family = AF_INET: RecvAddr.sin_port = Port
Dim SplitArray As Variant: SplitArray = Split(IP, ".")
RecvAddr.sin_addr(0) = SplitArray(0)
RecvAddr.sin_addr(1) = SplitArray(1)
RecvAddr.sin_addr(2) = SplitArray(2)
RecvAddr.sin_addr(3) = SplitArray(3)
For buf = 1 To Len(Message)
SendBuf(buf - 1) = Asc(Mid(Message, buf, 1))
Next buf
SendBuf(buf + 1) = 0
iResult = WSAStartup(&H202, wsaData)
If iResult <> 0 Then
MsgBox ("WSAStartup failed: " & iResult)
Exit Sub
End If
send_sock = f_socket(iFamily, iType, iProtocol)
If send_sock = INVALID_SOCKET Then
Errno = WSAGetLastError()
Exit Sub
End If
iResult = sendto(send_sock, SendBuf, Len(Message), 0, RecvAddr, Len(RecvAddr)) ' BufLen, 0, RecvAddr, Len(RecvAddr))
If iResult = -1 Then
MsgBox ("sendto failed with error: " & WSAGetLastError())
closesocket (send_sock)
Call WSACleanup
Exit Sub
End If
iResult = closesocket(send_sock)
If iResult <> 0 Then
MsgBox ("closesocket failed with error : " & WSAGetLastError())
Call WSACleanup
End If
End Sub
Private Sub CommandButton1_Click()
Call SendPacket("aaa", "192.168.1.55", 1000)
End Sub更新:根据雷米·莱博的建议,我做了以下修改:
Private Declare Function sendto Lib "Ws2_32.dll" (ByVal socket As Long, ByVal buf As LongPtr, ByVal length As Long, ByVal flags As Long, ByRef toaddr As sockaddr_in, tolen As Long) As Long用ByRef buf() As Byte改变ByVal buf As LongPtr,
Private Declare PtrSafe Function VarPtrArray Lib "VBE7" Alias "VarPtr" (Var() As Any) As LongPtr
...
iResult = sendto(send_sock, VarPtrArray(SendBuf) + 12, Len(Message), 0, RecvAddr, Len(RecvAddr))将SendBuf改为VarPtrArray(SendBuf) + 12。
但我还是能拿到垃圾。
更新2:成功:
已添加
Private Declare PtrSafe Function VarPtrArray Lib "VBE7" Alias "VarPtr" (Var() As Any) As LongPtr已修改
iResult = sendto(send_sock, VarPtr(SendBuf(0)), Len(Message), 0, RecvAddr, Len(RecvAddr))发布于 2018-02-21 23:41:40
您在buf参数sendto()中传递了错误的内存地址,因此它从错误的内存中检索字节。这就是为什么在数据包有效负载中看到“垃圾”的原因。
将ByRef buf() as Byte用于sendto()的buf参数是错误的。sendto()期望一个指针直接指向要发送的实际字节。但是您的SendBuf变量是一个动态数组(它是包含指向实际字节的指针的COM SAFEARRAY的包装器)。通过传递SendBuf as-is使用ByRef,您实际上是在传递sendto() -- SendBuf变量本身的内存地址,而不是SendBuf引用的字节数据的内存地址(位于内存的其他地方)。
来自VBA内部:变量中的内容
VBA中的数组至少由3个指针构建。首先,对数组变量调用
VarPtrArray()将获得变量内容的地址。如果直接读取变量内容,就会得到另一个指针--指向SAFEARRAY结构的开始。最后,如果直接从SAFEARRAY的字节偏移量12 (SAFEARRAY字段)读取数据,您将得到一个指向数组元素数据开始的指针。
最后一个值(“指向数组元素数据开始的指针”)是您需要传递给buf参数sendto()的内存地址。因此,将buf参数更改为LongPtr,然后使用VarPtrArray()和CopyMemory()的组合从SendBuf的内部SAFEARRAY中提取指向字节数据的指针。
请参阅VBA内部:获取指针 (它根据您的Office版本为VarPtrArray()提供了适当的声明)和VBA内部:数组变量和深度指针 (它向您展示了如何使用VarPtrArray()从数组变量中获取内部数据指针)。
例如:
Public Declare PtrSafe Function VarPtrArray Lib "VBE7" Alias "VarPtr" (Var() As Any) As LongPtr
' Public Declare Function VarPtrArray Lib "VBE6" Alias "VarPtr" (Var() As Any) As Long
...
Private Declare Function sendto Lib "Ws2_32.dll" (ByVal socket As Long, ByVal buf As LongPtr, ByVal length As Long, ByVal flags As Long, ByRef toaddr As sockaddr_in, tolen As Long) As Long
...
Dim SendBuf(0 To 1023) As Byte
Dim ptrToArrayVar As LongPtr
Dim ptrToSafeArray As LongPtr
Dim ptrToArrayData As LongPtr
Dim uSAFEARRAY As SAFEARRAY_VECTOR
...
' Get pointer to array *variable*
ptrToArrayVar = VarPtrArray(SendBuf)
' Get the pointer to the *SAFEARRAY* by directly
' reading the variable's address
CopyMemory ptrToSafeArray, ByVal ptrToArrayVar, PTR_LENGTH
' Read the SAFEARRAY struct
CopyMemory uSAFEARRAY, ByVal ptrToSafeArray, LenB(uSAFEARRAY)
' Get the pointer to the actual vector of bytes
ptrToArrayData = uSAFEARRAY.pvData
iResult = sendto(send_sock, ptrToArrayData, buf + 1, 0, RecvAddr, Len(RecvAddr))Update:显然,您根本不需要直接访问SAFEARRAY。VarPtr()能够获取数组变量的特定元素的内存地址。因此,您可以使用以下方法获取SendBuf中第一个字节的内存地址(这实际上与内部SAFEARRAY所指向的内存地址相同):
iResult = sendto(send_sock, VarPtr(SendBuf(0)), buf + 1, 0, RecvAddr, Len(RecvAddr))发布于 2018-02-22 06:48:21
sendto方法获取缓冲区中数据开头的地址。
使用ByRef buffer As Any声明参数
Private Declare PtrSafe Function sendto Lib "Ws2_32.dll" ( _
ByVal socket As Long, _
ByRef buffer As Any, _
ByVal length As Long, _
ByVal flags As Long, _
ByRef toaddr As Any, _
ByVal tolen As Long) As Long并通过参考提供第一个要素:
Dim buffer() As Byte, size As Long
buffer = StrConv(Message, vbFromUnicode) ' UTF-16 2 bytes to ANSI 1 byte
size = UBound(buffer) + 1
iResult = sendto(send_sock, buffer(0), size, 0, RecvAddr, Len(RecvAddr))https://stackoverflow.com/questions/48917030
复制相似问题