2017-04-04 19 views
1

我創建了下面的Excel VBA代碼,它使用Winsock API連接到IP地址,從Excel單元格發送文本字符串,並接收文本字符串返回。VBA Winsock無法使用更長的端口長度(sin_port)

我的代碼最初是指向IP地址127.0.0.1端口80,並沒有問題。不過,我必須將目標端口更新爲60401,這也需要將端口輸入變量sin_port更改爲長,因爲新端口超過了VBA整數的最大長度。這些更新後代碼仍然編譯,但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 
+1

您無法更改這些結構中的類型。這些結構的重點在於它們是一個明確定義的二進制接口。將其更改回Integer。 –

+0

而且你的人也是錯的。它在16位類型上運行。缺少未簽名的類型對您不方便。你將需要更好地掌握二進制表示,字節順序,二進制補碼等。 –

+0

@MajorCoder你在哪裏找到了添加到項目中的引用?我無法在我的項目PC(W7-64 Bit)上找到它。 – Jaberwocky

回答

1

你改變你的sockaddr_in定義使用較大的數據類型爲sin_port領域。你不能那樣做。您需要恢復原始定義以與Winsock保持兼容。

您對htons()的定義也是錯誤的。 ws2_32中的實際htons()函數以您所定義的16位數字而不是32位數字運行(htonl()以32位數字運行)。

你正在運行到真正的問題是,VBA的Integer類型是簽署,它可以容納32767如果您嘗試使用較高的值,它會換到負的最高值。

的Winsock的實際sockaddr_in結構(和htons()功能)使用16位無符號類型sin_port字段。 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十六進制0xEBF1。這與簽署的號碼-5135的值相同。當字節互換htons()時,它變成0xF1EB(-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")