调用 wininet 函数时随机出现 NullReferenceException

When calling wininet functions random NullReferenceException occur

不知道为什么,但是在调用函数时随机 InternetQueryDataAvailable 没有明显的原因发生 null ref 异常,因为它接受的参数不能为空:

[DllImport(Dlls.Wininet, SetLastError = true)]
public static extern bool InternetQueryDataAvailable([In] IntPtr hFile, [Out] out int numberOfBytesAvailable, [Optional, In] int reserved0, [Optional, In] IntPtr reserved1);

例外情况:

不,CheckHandle() 不是罪魁祸首,因为它所做的只是检查 _handle 是否为零,即无效。

此外,如果不是这样,那么在下载所有数据并尝试关闭应用程序之后,我将其设置为在应用程序关闭之前关闭所有句柄,对 InternetCloseHandle 的调用将抛出空引用即使是例外,就像 InternetQueryDataAvailable 一样,所有参数都不能为空,它只接受一个 IntPtr:

[DllImport(Dlls.Wininet, SetLastError = true)]
public static extern bool InternetCloseHandle([In] IntPtr hInternet);

我不确定发生了什么,因为在极少数情况下一切正常,我能够下载所有数据并关闭句柄而不会抛出随机异常。

对于那些想知道带有 InternetCloseHandle 的函数是什么样子的人,它只是:

public void Dispose()
{
    if (_handle != IntPtr.Zero)
    {
        if (!WinINet.InternetCloseHandle(_handle))
        {
            throw new Win32Exception();
        }
        _handle = IntPtr.Zero;
    }

}

请注意,调用InternetQueryDataAvailable后抛出的异常只在第一次调用后发生,所以第一次调用没问题,但之后的所有调用都有机会触发异常。

Note that the exception which is thrown after calling InternetQueryDataAvailable only occurs after the first call, so the first is fine but all the ones after have a chance of triggering the exception.

这是意料之中的事情。这是一个数据检索。那些可以 always 运行 进入外生异常。该函数是否环绕文件访问或覆盖半个地球的网络操作并不重要——这两种情况都具有外生异常的可能性。

当然具体异常还是奇数

我没有指出的是导致此空引用异常的原因是,当执行 InternetOpen 时,我立即通过 InternetSetStatusCallback 将句柄分配给状态回调通过只做 InternetSetStatusCallback(handle, CallbackMethod);,显然发生的事情是 GC 收集了委托,因为它应该没有被使用,请注意当 InternetQueryDataAvailable 被称为状态 INTERNET_STATUS_RECEIVING_RESPONSEINTERNET_STATUS_RESPONSE_RECEIVED 确实会传递给回调,所以我不确定为什么 GC 会收集委托,但这就是空引用的原因。并不是像某些人怀疑的那样 InternetQueryDataAvailable 抛出了异常。 对此的解决方案是创建一个分配给委托的字段,这样 GC 就不会收集它,因为 class 容纳它始终处于活动状态并且永远不会超出范围。