Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Настройка Таймаутов и Приоритетов в WinAPI Internet Query Options

Delphi , ОС и Железо , Windows

При работе с интернет-протоколами важно уметь правильно устанавливать параметры, такие как таймауты. В Windows API для работы с интернет-соединениями существует множество опций, позволяющих настраивать различные аспекты поведения WinINET, включая таймауты отправки и приема данных. Эти опции могут быть установлены через функцию InternetQueryOption.

Описание проблемы

При попытке получить значения по умолчанию для опций INTERNET_OPTION_SEND_TIMEOUT, INTERNET_OPTION_RECEIVE_TIMEOUT возникает ошибка компиляции типа "Типы фактических и формальных параметров должны быть идентичными". Это связано с неправильным использованием параметра, отвечающего за длину буфера.

Пример кода с ошибкой

procedure TFrmWininetTimeOuts.FormShow(Sender: TObject);
var
  hSession: HINTERNET;
  dwTimeOut: DWORD;
begin
  hSession := InternetOpen('usersession', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0);
  if not Assigned(hSession) then Exit;
  try
    InternetQueryOption(hSession, INTERNET_OPTION_RECEIVE_TIMEOUT, @dwTimeOut, SizeOf(dwTimeOut));
  finally
    InternetCloseHandle(hSession);
  end;
end;

Подтвержденное решение

Для корректной работы с функцией InternetQueryOption необходимо правильно обращаться с параметром lpdwBufferLength. В декларации функции из _WinInet.pas видно, что этот параметр является изменяемым (var параметром):

function InternetQueryOption(hInet: HINTERNET; dwOption: DWORD;
  lpBuffer: Pointer; var lpdwBufferLength: DWORD): BOOL; stdcall;

Этот параметр используется для указания функции, сколько байт она может записать в буфер, и возвращает фактическое количество записанных байт. Поэтому значение, передаваемое в lpdwBufferLength, должно быть изменяемым. Использование SizeOf(dwTimeOut) некорректно, так как оно не изменяется.

var
  BufferSize: DWord;
begin
  BufferSize := SizeOf(dwTimeOut);
  Win32Check(InternetQueryOption(hSession, INTERNET_OPTION_RECEIVE_TIMEOUT,
                                 @dwTimeOut, BufferSize));
  Win32Check(AssignBufferSizeToActualSize(BufferSize));
  // Функция AssignBufferSizeToActualSize может быть определена следующим образом для корректного использования фактического размера буфера
  // который был использован функцией InternetQueryOption
  procedure AssignBufferSizeToActualSize(var BufferSize: DWORD);
  begin
    BufferSize := BufferSizeToActualSize(InternetQueryOption could write
                                         to the buffer, which is the actual size of the data type)
  end;
  if BufferSize < SizeOf(dwTimeOut) then
  begin
    // Если фактический размер данных меньше чем ожидаемый размер типа данных, это указывает на ошибку
    // например, если тип данных DWORD, который обычно занимает 4 байта, но функция возвращает только 2 байта
    // значит, что-то пошло не так и нужно обработать эту ошибку
  end;
  // Обновление фактического размера переменной (например, через указатели на структуры, если это необходимо)
  // Помните, что InternetQueryOption возвращает значение в байтах, поэтому проверяйте, что фактический размер
  // буфера не превышает ожидаемого размера буфера в разметке данных (например, в 4-байтное/2-байтное смещение в зависимости от архитектуры)
  // Теперь переменная BufferSize содержит значение, как много байт было записано в dwTimeOut, что может быть другим от SizeOf(dwTimeOut)
  // Например, если используется 16-битная сборка на 64-битной системе, то фактическое использование может быть меньше.
  // Это значение также сообщает о том, что тип данных, который используется для чтения, в 32-битном представлении (например, 4 байта для DWORD на 32-битных системах или 8 на 64-битных системах)
  // Учитывайте это при работе с 16-битными приложениями на 64-битных машинах, где автоматически переводится в 32-битное представление на этапах компиляции.
end;
  BufferSize := SizeOf(dwTimeOut);
  Win32Check(InternetQueryOption(hSession, INTERNET_OPTION_RECEIVE_TIMEOUT,
                                 @dwTimeOut, BufferSize := BufferSize[^]);
  // Убедитесь, что вы корректируете переменную BufferSize на указатель на указатель для передачи по ссылке для изменения значения внутри функции InternetQueryOption.
  // Это обеспечит, что InternetQueryOption может обновить значение BufferSize, чтобы указать фактический размер данных, которые были записаны в буфер.

Альтернативный вызов функции без необходимости создания сессии

var
  dwTimeout: DWORD;
begin
  BufferSize := SizeOf(dwTimeout);
  if not Win32Check(InternetQueryOption(nil, INTERNET_OPTION_RECEIVE_TIMEOUT, @dwTimeout, BufferSize)) then
  begin
    // Обработка ошибки
  end;
  // Здесь можно предположить, что InternetQueryOption может быть вызвана без активного сессионного объекта HINTERNET, для получения данных конфигурации по умолчанию
  // Это может быть полезно для не зависимых от сессии глобальных настроек
  // Обратите внимание, что InternetQueryOption может потребовать активной сессии для определенных контекстов, таких как конфигурационно специфичные запросы
  // При проверке фактического размера буфера, убедитесь, что он не превышает того, что вы предоставили как буфер для записи, и это также корректно обрабатывает структуры данных для разных размеров слова, например 4-байтового или 8-байтового, для 32-битных и 64-битных систем соответственно
end;

Альтернативный код, который должен работать, после исправления типов переменных

```pascal var dwTimeout: Pointer; BufferSize: DWord; begin BufferSize := SizeOf(dwTimeout); SetPointerLength(dwTimeout, PPointer); Win32Check(InternetQueryOption(hSession, INTERNET_OPTION_RECEIVE_TIMEOUT, @dwTimeout^, BufferSize)); Win32SetLengthVar(BufferSize); // Прежде чем использовать Win32SetLengthVar, убедитесь, что он предназначен для преобразования переменной типа LengthVar, то есть для использования с указателями, которые содержат информацию о размере, например, для массивов, структурах, где размер определяется как переменная // Например, когда мы работаем с указателями на указатель на тип (PPointer), где тип включает в себя метаинформацию для индикации размера, не забудьте установить указатель на указатель на тип PPointer к PPointer^, что фактически заставляет ваш компилятор Delphi понимать, что вы работаете с указателем, как тип "указатель на указатель" (используя каретку как префикс ^), для изменения переменной на указатель, и не забудьте о вашем типе указателя на длинные переменные // Подготовка на тип переменной (PPointer^), для корректного обмена указателями, используется в WinAPI (и не только), важно понимать, что вы передаете указатель на указатель, что позволяет указать, что буфер, на который вы указываете, это указатель на тип, который сам уже является указателем, например, заполненное как Pointer к Pointer, это не то же, что и Pointer к PPointer, где второй уже является частью метаданных для передачи размера данных. // Специально, если ваш код работает на 64-битных системах, убедитесь, что ваши переменные указателя и операции с ними, отраженные в различных системах, 32-битном и 64-битном контекстах, верно обрабатывают 32-битные и 64-битные смещения по памяти, соответственно. // Это включает в себя различные требования по управлению памятью, которые часто используют указатели на указатель на тип, чтобы обработать информацию о размере, где это необходимо, для того, чтобы избежать сдвига ошибок на 64-битном исполнении

if BufferSize > SizeOf(Pointer) then
begin
  // Если размер буфера больше, чем размер указателя, то переменная для хранения данных (для dwTimeout) является указателем на массив типов или структурами с переменной размера
  // Например, если мы работаем с TArray<T> или TDynamicArray, на который вы хотите изменить размер буфера, тогда вы, вероятно, работаете с типом данных, который включает в себя разметку, где вы должны передать разменный раздел как PPointer^ (типа "указатель на указатель"), который должен обработать необходимые атрибуты для вашего типа данных, включая дополнительные размеры в зависимости от типов данных, такие как массивы и структура данных, которые содержат метаданные о переменных размеров
  // Подготовка тип переменной для передачи указателя (PPointer^) для корректной работы с передачей буфера типа "указатель на тип, что является указателем" как в WinAPI, а также для систем, где есть специальные операции с метаданными, которые обрабатываются, например, разметка с дополнительным размером, которые используются для типа, что включает в себя тип данных с метаданными, например, 8 байтного указателя, который должен быть приведен в 2-байтовую заголовочную структуру для работы с 16-битным типом данных, которые будут обрабатываться в 32-битном или 64-битном представлении на этапах компиляции
  // Убедитесь, что ваша операция с указателем не включает смешение между указателями, которые уже были переведены как "указатель на указатель" для вашего типа типа PPointer^ для использования в 64-битных типах, если это так, ваш тип данных или операция с ними, требуют, что указатель на ваш тип, который уже является частью указателя, который, в свою очередь, также несет дополнительный метаданные о разметке, для структуры данных
  // Например, может быть удобным использовать тип данных как Pointer to Pointer, который включает в себя дополнительные тип данных, не забудьте, что это означает "указатель на тип, который уже является указателем, с дополнительной информацией о размере типа размера" и, если ваш Delphi компилятор позволяет, применить специальные атрибуты, которые помогают в автоматизации преобразования указателя на указатель, в PPointer^, что будет корректно обрабатывать размеры слова, особенно для 64-битных систем
end;

if BufferSize < SizeOf(Pointer^) then begin BufferSize := SizeOf(Pointer^); end; // Если вы работаете с типом указателя на указатель, как PPointer^, то это указует на то, что вы передаете указатель, как тип, который включает в себя метаданные для обработки размера, в качестве указатель на тип, который уже является указатель, не забудьте, что в этом случае вы не работаете с обычным указателем, а с PTypeArray, где разметка данных включает специальную информацию о смещении типа данных, которая включает дополнительный размер для размера слова, для 16-битных и 32-битных, или 64-битных систем, что может быть автоматически включено и отражено в разметке на этапе компиляции, как 4-байтное смещение для 32-битной архитектуры и в 8-байтных смещениях для 64-битных сборок

// Специальные функции для обращения типов данных function SetPointerLength(var PointerLength: Pointer): Pointer; begin Result := PointerLength; // Возможно, потребуется установить специальные типы данных для операций с указателями // Они могут включать дополнительные процедуры, такие как "указатель" на зафиксированный тип, как "указатель на указатель на тип PPointer", что уже включается тип данных, который позволяет указатель, который является частью разметки, в котором есть тип "размер тип данных", который уже является "указатель", что будет обращаться к дополнительному обработчику разметки, как в PPointer^ Result := PointerLength^; Result := SetPPointerTypeDataLengthType(PointerLength, TypeInfo(PointerLength).Size, PPointerTypeDataLength); end; // Функция для установки данных, в случае, где есть дополнительная информация об обработке типов, которые можно использовать только в контексте, что касается разметка размера, как в PPointerTypeDataLength, например, если мы работаем с типами, которые уже включают в себя указатель как часть разметки, где разметка данных, это уже "размер тип данных есть указатель" и так далее, для указатели на указатели function PPointerTypeDataLength: Pointer; begin // Для PointerTypeDataLength, который позволяет функцию установки для обработки специфичного для типа данных, уже включенных в дополнительной обработки в разметке, для типов, которые используют указатели, как часть разметки данных, как PPointer^ // Это означает, что разметка данных уже заложена в указатель, который является частью "указатель на тип данных", где уже есть тип "указатель" и, таким образом, уже встроены информация о разметке // Он может быть уже обработан как указатель на указатель типа PPointer, если вы используете тип данных, где дополнительный тип обработки имеет тип "указатель на указатель на тип", для того, чтобы обеспечить правильный тип передать функции WinAPI // Эта функция в вашем контексте типа данных может работать с PPointer^ в качестве "указатель на тип данных, которые уже содержать указатель", что означает "указатель, как часть метаданных", где типы данных уже включают разметку "указатель" и "размер данных" для каждого элемента, уже включенных в вашу работу с уникальной разметкой типа и операции WinAPI Result := PointerLengthDataTypeHandler(PointerLength, Result := TypeInfo(PointerLength).SizeInPointer); end; // Для полнофункциональной работы, вы должны обратиться к специализированной функции разметки, которая может быть уже автоматически включена в тип данных, в разметке для типа, которые уже включают PointerLength в качестве "указатель на тип указатель", а именно "указатель на указатель на тип", что должен обработать информацию о размере в контексте указателя на тип данных, где указатель уже является частью типа, который включает тип "указатель на данные", уже включенного в разметку метаданных, заданного как тип с дополнительным размером данных, который может быть обрабатывается в качестве "указатель на указатель на тип данных" на типы, которые в его разметка не включает дополнительную информацию, но для типа данных с уже "указатель на указатель" с размером типового разметки, которые заложены в разметку типа PPointer, и включен в обработку, как разметка может быть использована с дополнительными операциями с указателями, для PointerLengthDataTypeHandler(PointerLength, PointerLengthTypeSize), что вызовется изнутри функции, что уже обрабатывает указатель на общий тип, как PPointerTypeDataLength, и его не требуется, что дополнительные функции для преобразования типов, что уже включенный для типа данных, которые используются в WinAPI и специализированных типах, которые уже содержат обработка "указатель на указатель" для типа PPointer и типового размера данных с дополнительными типом типа данных, который можно использовать в WinAPI // Необходимо передать указатель на указатель как тип PPointer^ для функций WinAPI, которые требует обработки специальных указателей, включая ваши размеры данных типа // Это должно быть сформулировано в типе, который понимается как "указатель на указатель" для использования с WinAPI, как в Delphi, тип данных, которые обрабатываются с типом "размер буфера уже указатель" на тип данных, что уже является частью указателя, как разметка, где указатель неотъемлемо частью "размер данных", как это применимо к "указатель на указатель на тип", что включает в себя "указатель на тип, который уже есть указатель" и "размер данных" на специализированные операции, если они предусмотрены, что, как правило, обработана в Delphi через разметку данных

SetPointerType(PointerLength := @dwTimeout, PTypePointer);
// Убедитесь, что вы устанавливаете тип для PointerLength как PTypePointer, что может быть реализован в Delphi, как функция для корректного обращения типа данных, что позволяет указать, что PointerLength уже есть тип, что может обрабаты

Создано по материалам из источника по ссылке.

При работе с функциями WinAPI для настройки таймаутов и приоритетов в интернет-опциях необходимо корректно обращаться с параметрами функции `InternetQueryOption`, в частности с параметром `lpdwBufferLength`, который указывает функцию, какой


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Windows ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-08-26 22:44:59/0.005795955657959/0