При вызове функций wininet происходит случайное исключение NullReferenceException - PullRequest
1 голос
/ 30 октября 2019

Не знаю, почему, но наугад при вызове функции 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);

Вот исключение:

enter image description here

И нет, CheckHandle() не является виновником, поскольку все, что он делает, это проверяет, является ли _handle нулем или нет, или недействительным.

Кроме того, если не это, то после загрузки всех данных и попытки закрыть приложение, грехи я настроил так, что все ручки закрываются до закрытия приложения, вызов InternetCloseHandle выбрасывает нулевой refисключение, хотя, как и в случае с 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, возникает только после первого вызова, поэтому первый из них в порядке, но все последующие могут вызвать исключение.

Ответы [ 2 ]

1 голос
/ 31 октября 2019

Единственное, на что я не указал, что явилось причиной исключения из нулевого ссылки, было то, что при выполнении InternetOpen я мгновенно назначаю дескриптор обратному вызову состояния через InternetSetStatusCallback, просто выполняя InternetSetStatusCallback(handle, CallbackMethod);Очевидно, что происходило то, что GC собрал делегата, потому что он предположительно не использовался, обратите внимание, что когда InternetQueryDataAvailable вызывается, статусы INTERNET_STATUS_RECEIVING_RESPONSE и INTERNET_STATUS_RESPONSE_RECEIVED действительно передаются обратному вызову, поэтому я не уверен, почемуGC собрал делегата, но это было причиной нулевого реф. Не то чтобы InternetQueryDataAvailable выбрасывал исключение, как некоторые подозревали. Решением для этого было создание поля, которому назначен делегат, например, что сборщик мусора не будет собирать его из-за того, что класс, в котором он находится, всегда жив и никогда не выходит за рамки.

0 голосов
/ 31 октября 2019

Обратите внимание, что исключение, которое выдается после вызова InternetQueryDataAvailable, возникает только после первого вызова, поэтому первый вариант в порядке, но все последующие могут вызвать исключение.

Этого следовало ожидать. Это восстановление данных. Они могут всегда сталкиваться с экзогенными исключениями. Не имеет значения, если эта функция оборачивается вокруг доступа к файлу или сетевой операции, проходящей через половину планеты - оба этих сценария получили экзогенный потенциал исключения в пики.

Конечно, конкретное исключение все еще странно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...