Excel/VBA - 检测服务器是否可访问

AZh*_*Zhu 6 excel vba remote-server

在我的工作地点,不同的计算机位于不同的子网中,如果PC与Samba服务器位于同一子网中,我可以通过转到文件服务器\\myserv\MyFolder,但是对于PC在不同的子网中,唯一的方法是我通过使用IP到达服务器(i.e., \\1.2.3.4\MyFolder).

我只是想知道VBA,如果我有任何办法可以说:

如果我能找到使用的服务器\\myserv,那么使用myserv,否则使用1.2.3.4

不幸的是我根本无法调整网络,我想设置这种方式,以便至少在IP更改时,我的大多数用户仍然可以通过访问来使用该工具\\myserv\MyFolder.

Cub*_*ase 7

这是我用来检查服务器可访问性的一些代码.它使用Windows winsock32 API,我没有遇到任何问题.我不必担心权利,所以我不知道它是如何处理的.

我已经对代码进行了相当的评论,所以希望你能理解,如果你需要调整代码,你会发生什么.它按照我使用的示例子工作.我会让你在检查网络路径后执行设置文件夹的代码;)

这不是一项微不足道的任务,但这是一个棘手的问题,所以我很乐意分享代码.从您调用的函数开始进行检查 - 注意如何定义路径.我已经在我的网络上测试了这些并且它们都工作了,Diskstation通过其网络名称及其IP进行检查:

Sub TestMyPaths()
    TestPath ("C:\")
    TestPath ("\\Diskstation\")
    TestPath ("\\192.168.99.5\")
End Sub

Sub TestPath(sServerName As String)
    If sServerName = "" Then Exit Sub

    If Not CheckPath(sServerName) Then
        MsgBox "Cannot find " & sServerName
    Else
        MsgBox "Found " & sServerName
    End If
End Sub


Private Function CheckPath(sfile As String) As Boolean
    'Response Variables
    Dim bResponse As Boolean, bLocal As Boolean
    'File System Variables
    Dim oFS As Object, oDrive As Object, oTemp As Object
    'Variables for chkecing the server
    Dim strIPAddress  As String, Reply As ICMP_ECHO_REPLY, lngSuccess As Long, sServer As String

    If sfile = "" Then Exit Function
    bResponse = False

    On Error GoTo SomeProblem

    ' Determine if drive is local and resolve all remote paths to UNC filenames
    Set oFS = CreateObject("Scripting.FileSystemObject")
    Set oDrive = oFS.Drives
    bLocal = False
    If UCase(VBA.Left(sfile, 1)) Like "[A-Z]" Then
        For Each oDrive In oFS.Drives
            If oDrive.Path = UCase(VBA.Left(sfile, 2)) Then
                If oDrive.DriveType = 3 Then ' Remote Drive
                    sfile = Replace(sfile, (VBA.Left(sfile, 2)), oDrive.ShareName)
                Else
                    bLocal = True
                End If
                Exit For
            End If
        Next oDrive
    End If

    If bLocal Then
        'Allow for checking at the end of this if statement
        bResponse = True
    ElseIf VBA.Left(sfile, 1) <> "\" Then
        ' File Name only specified / Not a valid path
        bResponse = False
    Else
        'Otherwise we are dealing with a server path

        'Get the server name
        sServer = VBA.Mid$(sfile, 3, InStr(3, sfile, "\", vbTextCompare) - 3)

        'Set up networking to check
        If SocketsInitialize() Then
            strIPAddress = GetIPFromHostName(sServer)   'Get the ipaddress of the server name
            lngSuccess = ping(strIPAddress, Reply)      'Ping the IP that is passing the address and get a reply.
            Call WSACleanup                             'Clean up the sockets.
            If lngSuccess = 0 Then bResponse = True     'If we get a ping back we're all good
        End If
    End If

SomeProblem:
    CheckPath = bResponse
    Set oTemp = Nothing
    Set oDrive = Nothing
End Function
Run Code Online (Sandbox Code Playgroud)

然后是API声明(这些声明位于模块的顶部).

    #If Win64 Then
        Private Declare PtrSafe Function gethostbyname Lib "WSOCK32.DLL" (ByVal hostname As String) As Long
        Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (xDest As Any, xSource As Any, ByVal nbytes As Long)
        Private Declare PtrSafe Function WSAStartup Lib "WSOCK32.DLL" (ByVal wVersionRequired As Long, lpWSADATA As WSADATA) As Long
        Private Declare PtrSafe Function WSACleanup Lib "WSOCK32.DLL" () As Long
    #Else
        Private Declare Function gethostbyname Lib "WSOCK32.DLL" (ByVal hostname As String) As Long
        Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (xDest As Any, xSource As Any, ByVal nbytes As Long)
        Private Declare Function WSAStartup Lib "WSOCK32.DLL" (ByVal wVersionRequired As Long, lpWSADATA As WSADATA) As Long
        Private Declare Function WSACleanup Lib "WSOCK32.DLL" () As Long
    #End If

    'NETWORK AND PING API FUNCTIONS
    #If Win64 Then
        Public Declare PtrSafe Function IcmpCreateFile Lib "icmp.dll" () As Long
        Public Declare PtrSafe Function inet_addr Lib "WSOCK32.DLL" (ByVal cp As String) As Long
        Public Declare PtrSafe Function IcmpCloseHandle Lib "icmp.dll" (ByVal IcmpHandle As Long) As Long
        Private Declare PtrSafe Function IcmpSendEcho Lib "icmp.dll" _
           (ByVal IcmpHandle As Long, _
            ByVal DestinationAddress As Long, _
            ByVal RequestData As String, _
            ByVal RequestSize As Long, _
            ByVal RequestOptions As Long, _
            ReplyBuffer As ICMP_ECHO_REPLY, _
            ByVal ReplySize As Long, _
            ByVal Timeout As Long) As Long
    #Else
        Public Declare Function IcmpCreateFile Lib "icmp.dll" () As Long
        Public Declare Function inet_addr Lib "WSOCK32.DLL" (ByVal cp As String) As Long
        Public Declare Function IcmpCloseHandle Lib "icmp.dll" (ByVal IcmpHandle As Long) As Long
        Private Declare Function IcmpSendEcho Lib "icmp.dll" _
           (ByVal IcmpHandle As Long, _
            ByVal DestinationAddress As Long, _
            ByVal RequestData As String, _
            ByVal RequestSize As Long, _
            ByVal RequestOptions As Long, _
            ReplyBuffer As ICMP_ECHO_REPLY, _
            ByVal ReplySize As Long, _
            ByVal Timeout As Long) As Long
    #End If

    Public Const WINSOCK_ERROR = "Windows Sockets not responding correctly."
    Public Const INADDR_NONE As Long = &HFFFFFFFF
    Public Const WSA_SUCCESS = 0
    Public Const GWL_STYLE = -16
    Public Const WS_SYSMENU = &H80000
    Private Const ICMP_SUCCESS As Long = 0
    Private Const WS_VERSION_REQD As Long = &H101
    Private Const MAX_WSADescription As Long = 256
    Private Const MAX_WSASYSStatus As Long = 128

    'PING AND NETWORK ENUMS
    Private Type IP_OPTION_INFORMATION
       Ttl             As Byte
       Tos             As Byte
       Flags           As Byte
       OptionsSize     As Byte
       OptionsData     As Long
    End Type

    Public Type ICMP_ECHO_REPLY
       Address         As Long
       Status          As Long
       RoundTripTime   As Long
       DataSize        As Long
       Reserved        As Integer
       ptrData                 As Long
       Options        As IP_OPTION_INFORMATION
       data            As String * 250
    End Type

    Private Type WSADATA
        wVersion As Integer
        wHighVersion As Integer
        szDescription(0 To MAX_WSADescription) As Byte
        szSystemStatus(0 To MAX_WSASYSStatus) As Byte
        wMaxSockets As Long
        wMaxUDPDG As Long
        dwVendorInfo As Long
    End Type
Run Code Online (Sandbox Code Playgroud)

然后是通用网络功能:

    Public Function GetIPFromHostName(ByVal sHostName As String) As String
        'converts a host name to an IP address.
        Dim ptrHosent As Long  'address of hostent structure
        Dim ptrName As Long    'address of name pointer
        Dim ptrAddress As Long    'address of address pointer
        Dim ptrIPAddress As Long
        Dim sAddress As String
        sAddress = Space$(4)
        ptrHosent = gethostbyname(sHostName & vbNullChar)
        If ptrHosent <> 0 Then
            ptrName = ptrHosent
            ptrAddress = ptrHosent + 12
            'get the IP address
            CopyMemory ptrName, ByVal ptrName, 4
            CopyMemory ptrAddress, ByVal ptrAddress, 4
            CopyMemory ptrIPAddress, ByVal ptrAddress, 4
            CopyMemory ByVal sAddress, ByVal ptrIPAddress, 4
            GetIPFromHostName = IPToText(sAddress)
        End If
    End Function

    Private Function IPToText(ByVal IPAddress As String) As String
        IPToText = CStr(Asc(IPAddress)) & "." & _
                   CStr(Asc(Mid$(IPAddress, 2, 1))) & "." & _
                   CStr(Asc(Mid$(IPAddress, 3, 1))) & "." & _
                   CStr(Asc(Mid$(IPAddress, 4, 1)))
    End Function

    Public Function SocketsInitialize() As Boolean
        Dim WSAD As WSADATA
        SocketsInitialize = WSAStartup(WS_VERSION_REQD, WSAD) = ICMP_SUCCESS
    End Function

    Public Function ping(sAddress As String, Reply As ICMP_ECHO_REPLY) As Long
        'Function to ping an address and see if a response is obtained
        Dim hIcmp As Long, lAddress As Long, lTimeOut As Long, StringToSend As String

        StringToSend = "test"           'Short string of data to send
        lTimeOut = 1000 'ms             'ICMP (ping) timeout
        lAddress = inet_addr(sAddress)  'Convert string address to a long representation

        'If we have a valid response
        If (lAddress <> -1) And (lAddress <> 0) Then

            'Create the handle for ICMP requests.
            hIcmp = IcmpCreateFile()

            If hIcmp Then
                'Ping the destination IP address.
                Call IcmpSendEcho(hIcmp, lAddress, StringToSend, Len(StringToSend), 0, Reply, Len(Reply), lTimeOut)

                'Reply status
                ping = Reply.Status

                'Close the Icmp handle.
                IcmpCloseHandle hIcmp
            Else
                Debug.Print "failure opening icmp handle."
                ping = -1
            End If
        Else
            ping = -1
        End If
    End Function
Run Code Online (Sandbox Code Playgroud)


Jos*_*Lee 4

假设您使用的是 Windows 环境,这里有另一种方法(没有实际代码):

  1. 在 Excel VBA 中,使用 SHELL 函数执行 Net View 函数并将输出发送到文件。IE:
Dim vsFileName
vsFileName = "C:\Temp\RandomFileName.txt"
Shell("Net View \\myServ > " & vsFileName )
Run Code Online (Sandbox Code Playgroud)
  1. 之后,检查输出的文件大小。如果输出文件大小> 0,则表示找到路径。如果找不到路径,则输出文件大小将为 0。

If FileLen( vsFileName ) = 0 Then vsNetworkPath = "1.2.3.4"

  1. 通过以下方式自行清理:Kill( vsFileName )

如果您不想搞乱 win32 函数,这是一个替代方案。每次运行代码时最好随机化文件名以避免冲突。