Безопасно ли предполагать, что InternetCloseHandle () не потерпит неудачу, тем самым разрешая более чистый код? - PullRequest
4 голосов
/ 05 июля 2011

Вот процедура для выполнения HTTP-запроса с использованием WinINet и либо возврата извлеченной строки, либо выдачи исключения:

function Request(const pConnection: HINTERNET; const localpath: string): string;
var Buffer: packed Array[1..5000] of Char; BytesRead: Cardinal; pRequest: HINTERNET;     sent: boolean;
begin
Result := '';
pRequest := HTTPOpenRequest(pConnection, 'GET', pchar(localpath), nil, nil, nil, 0, 0);
if pRequest <> nil then
  begin
  sent := HTTPSendRequest(pRequest, nil, 0, nil, 0);
  if sent then
    while InternetReadFile(pRequest, @Buffer, SizeOf(Buffer)-1 {leave room for terminator}, BytesRead) do
      begin
      Buffer[BytesRead+1] := #0;
      Result := Result + buffer;
      end;
  InternetCloseHandle(pRequest);
  if not sent then RaiseLastOSerror; // HTTPSendRequest failed
  end
else RaiseLastOSerror; // HTTPOpenRequest failed
end;

Если InternetCloseHandle (pRequest) может завершиться ошибкой, даже если pRequest был успешно назначен, GetLastError ()вернет код ошибки для InternetCloseHandle () вместо HTTPSendRequest ().Исправление, которое потребовало бы кода вроде:

function Request(const pConnection: HINTERNET; const localpath: string): string;
var Buffer: packed Array[1..5000] of Char; BytesRead: Cardinal; pRequest: HINTERNET;
begin
Result := '';
pRequest := HTTPOpenRequest(pConnection, 'GET', pchar(localpath), nil, nil, nil, 0, 0);
if pRequest <> nil then
  begin
  if HTTPSendRequest(pRequest, nil, 0, nil, 0) then
    while InternetReadFile(pRequest, @Buffer, SizeOf(Buffer)-1 {leave room for terminator}, BytesRead) do
      begin
      Buffer[BytesRead+1] := #0;
      Result := Result + buffer;
      end
  else
    begin
    InternetCloseHandle(pRequest);
    RaiseLastOSerror; // HTTPSendRequest failed
    end;
  InternetCloseHandle(pRequest);
  end
else RaiseLastOSerror; // HTTPOpenRequest failed
end;

, но на первый взгляд это выглядит намного уродливее и запутаннее.

Можно ли предположить, что InternetCloseHandle () не удастся, что позволитболее простой код?

Ответы [ 4 ]

4 голосов
/ 05 июля 2011

Прежде всего этот код не полезен:

raise Exception.Create(IntToStr(GetLastError))

Используйте это вместо:

RaiseLastOsError; // This raises an exception with the description of the error

Поскольку вы используете исключения в своем коде, как насчет вызова такой функции, чтобы она вызывала исключение, если дескриптор не может быть закрыт?

Win32Check(InternetCloseHandle(H))
2 голосов
/ 05 июля 2011

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

Я думаю, что вы хотите что-то вроде этого:

Result := '';
pRequest := HTTPOpenRequest(pConnection, 'GET', pchar(localpath), nil, nil, nil, 0, 0);
if pRequest=nil then
  RaiseLastOSerror;
try
  CheckWin32Error(HTTPSendRequest(pRequest, nil, 0, nil, 0));
  while InternetReadFile(pRequest, @Buffer, SizeOf(Buffer)-1, BytesRead) do begin
    Buffer[BytesRead+1] := #0;
    Result := Result + buffer;
  end;
  if GetLastError<>0 then
    RaiseLastOSerror;
finally
  CheckWin32Error(InternetCloseHandle(pRequest));
end;

Обратите внимание, что вы не включили проверку ошибок для InternetReadFile.Я пытался написать это для вас.

1 голос
/ 05 июля 2011

Вы должны убедиться, что дескриптор «закрыт», если он успешно создан. То есть вы должны сделать

hReq := HTTPOpenRequest(...);
if hReq <> 0 then
  try      
    // Do stuff
  finally
    InternetCloseHandle(hReq);
  end;
0 голосов
/ 05 июля 2011

Глядя на SOAPHTTPTrans, есть много звонков в InternetCloseHandle. Несмотря на то, что многие из них появляются в пределах блоков Except, ни один из них не защищен одним. Похоже, что Codegear (у меня D2006) предполагает, что он не выйдет из строя.

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