InternetOpenUrl 在第三次和后续调用中挂起并失败

Posted

技术标签:

【中文标题】InternetOpenUrl 在第三次和后续调用中挂起并失败【英文标题】:InternetOpenUrl hangs and fails on third and subsequent calls 【发布时间】:2016-02-16 18:28:49 【问题描述】:

这是一些奇怪但可重现的行为。我可以每个 URL 准确地调用 InternetOpenUrl 两次,并且一切都按我的预期工作。如果我在那之后再次调用它,它会在 60 秒处超时,并且不会返回 Web 资源的句柄。

我创建了以下最小代码示例来演示该问题(这是对AllAPI Mentalis sample 的改编):

Private Const scUserAgent = "API-Guide test program"
Private Const INTERNET_OPEN_TYPE_DIRECT = 1
Private Const INTERNET_FLAG_RELOAD = &H80000000

Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Declare Function InternetOpen _
                          Lib "wininet" Alias "InternetOpenA" _
                              (ByVal sAgent As String, ByVal lAccessType As Long, _
                               ByVal sProxyName As String, ByVal sProxyBypass As String, ByVal lFlags As Long) As Long
Private Declare Function InternetCloseHandle _
                          Lib "wininet" _
                              (ByRef hInet As Long) As Long
Private Declare Function InternetReadFile _
                          Lib "wininet" _
                              (ByVal hFile As Long, ByVal sBuffer As String, _
                               ByVal lNumBytesToRead As Long, lNumberOfBytesRead As Long) As Integer
Private Declare Function InternetOpenUrl _
                          Lib "wininet" Alias "InternetOpenUrlA" _
                              (ByVal hInternetSession As Long, ByVal lpszUrl As String, _
                               ByVal lpszHeaders As String, ByVal dwHeadersLength As Long, _
                               ByVal dwFlags As Long, ByVal dwContext As Long) As Long

Sub TestInternetOpenUrl(sURL As String)
    Dim hOpen As Long, hFile As Long, i As Integer, Start As Long
    For i = 1 To 4
        Start = GetTickCount
        'Create an internet connection
        hOpen = InternetOpen(scUserAgent, INTERNET_OPEN_TYPE_DIRECT, _
                             vbNullString, vbNullString, 0)
        'Open the url
        hFile = InternetOpenUrl(hOpen, sURL, vbNullString, ByVal 0&, _
                                INTERNET_FLAG_RELOAD, ByVal 0&)
        'clean up
        InternetCloseHandle hFile
        InternetCloseHandle hOpen
        Debug.Print i; GetTickCount - Start; " ms elapsed ("; hFile; ")"
        DoEvents
    Next i
End Sub

以下是两次测试运行的结果:

TestInternetOpenUrl "http://www.yahoo.com"
 1  390  ms elapsed ( 13369203 )
 2  187  ms elapsed ( 13369217 )
 3  60000  ms elapsed ( 0 )
 4  60000  ms elapsed ( 0 )

TestInternetOpenUrl "http://www.duckduckgo.com"
 1  203  ms elapsed ( 13369448 )
 2  93  ms elapsed ( 13369460 )
 3  60047  ms elapsed ( 0 )
 4  60047  ms elapsed ( 0 )

【问题讨论】:

【参考方案1】:

我通过更改您关闭手柄的方式来完成这项工作。我能够执行 30 次迭代,而且效果很好。

这是修改后的工作代码。此外,对 InternetCloseHandle 的 API 调用似乎存在问题(使用 ByRef 而不是 ByVal),该问题在下面得到纠正:

Private Const scUserAgent = "API-Guide test program"
Private Const INTERNET_OPEN_TYPE_DIRECT = 1
Private Const INTERNET_FLAG_RELOAD = &H80000000

Private Declare Function GetTickCount Lib "kernel32" () As Long
Private Declare Function InternetOpen _
                          Lib "wininet" Alias "InternetOpenA" _
                              (ByVal sAgent As String, ByVal lAccessType As Long, _
                               ByVal sProxyName As String, ByVal sProxyBypass As String, ByVal lFlags As Long) As Long
Private Declare Function InternetCloseHandle Lib "wininet.dll" (ByVal hInet As Long) As Integer    
Private Declare Function InternetReadFile _
                          Lib "wininet" _
                              (ByVal hFile As Long, ByVal sBuffer As String, _
                               ByVal lNumBytesToRead As Long, lNumberOfBytesRead As Long) As Integer
Private Declare Function InternetOpenUrl _
                          Lib "wininet" Alias "InternetOpenUrlA" _
                              (ByVal hInternetSession As Long, ByVal lpszUrl As String, _
                               ByVal lpszHeaders As String, ByVal dwHeadersLength As Long, _
                               ByVal dwFlags As Long, ByVal dwContext As Long) As Long

Private Sub CloseHandle(ByRef hHandle As Long)
   If (hHandle <> 0) Then
        Call InternetCloseHandle(hHandle)
        hHandle = 0
    End If
End Sub

Sub TestInternetOpenUrl(sURL As String)
    Dim hOpen As Long, hFile As Long, i As Integer, Start As Long
    Dim ret As Boolean: ret = False

    For i = 1 To 4
        Start = GetTickCount
        'Create an internet connection
        hOpen = InternetOpen(scUserAgent, INTERNET_OPEN_TYPE_DIRECT, _
                             vbNullString, vbNullString, 0)
        'Open the url
        hFile = InternetOpenUrl(hOpen, sURL, vbNullString, ByVal 0&, _
                                INTERNET_FLAG_RELOAD, ByVal 0&)

        CloseHandle (hFile)
        CloseHandle (hOpen)

        Debug.Print i; GetTickCount - Start; " ms elapsed ("; hFile; ")"
        DoEvents
    Next i
End Sub

我使用 yahoo 运行了 30 次来快速分析代码。以下是相关的描述性统计数据。每次调用大约需要半秒时间。

【讨论】:

我仍然有这个问题。你能在你的机器上用我的原始代码重现这个问题吗?我在想问题可能出在机器设置上。也就是说,你的机器配置和我的有一些关键的区别。 我看到了问题,对 InternetCloseHandle 的调用不太正确。我抄的是你的电话,而不是我的。查看更新的答案。 是的。 密钥从ByRef 更改为ByVal。我不能再奖励 11 个小时的赏金,但这是你的。谢谢!我不想考虑我在这上面浪费了多少时间......【参考方案2】:

我今天遇到了同样的问题,这是因为在我的代码中没有调用 InternetCloseHandle 函数(虽然我认为是这样)。

您需要检查函数InternetCloseHandle的返回值才能确定。

【讨论】:

我遇到了同样的问题(第 3 次打开,当网站关闭时,它挂起)。这篇文章帮助了我......原来我只是错过了这个特殊案例的 InternetCloseHandle,我没有意识到。

以上是关于InternetOpenUrl 在第三次和后续调用中挂起并失败的主要内容,如果未能解决你的问题,请参考以下文章

导航栏在第二次和后续出现时隐藏在视图控制器上

深入理解TCP协议:三次握手详解

Vaadin 项目点击监听器双击行为

React + Redux:为啥在第三次加载时填充道具?

β版本第三次冲刺

Excel中使用LINEST的二次和三次回归