假设InternetCloseHandle()不会失败,从而允许更清晰的代码是否安全?

时间:2011-07-05 13:51:11

标签: delphi wininet

这是使用WinINet执行HTTP请求并返回获取的字符串或引发异常的例程:

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;

如果成功分配了pRequest,InternetCloseHandle(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 个答案:

答案 0 :(得分:4)

首先,这种代码没有帮助:

raise Exception.Create(IntToStr(GetLastError))

请改用:

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

由于你在代码中使用异常,如何调用这样的函数,如果句柄无法关闭会引发异常?

Win32Check(InternetCloseHandle(H))

答案 1 :(得分:2)

我认为你这是错误的做法。您应该只检查每个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进行任何错误检查。我试图为你写它。

答案 2 :(得分:1)

如果句柄成功创建,则需要确保句柄“已关闭”。也就是说,你应该做

hReq := HTTPOpenRequest(...);
if hReq <> 0 then
  try      
    // Do stuff
  finally
    InternetCloseHandle(hReq);
  end;

答案 3 :(得分:0)

查看SOAPHTTPTrans,有很多对InternetCloseHandle的调用。虽然很多都出现在Except块中,但没有一个被一个人保护。因此,Codegear(我的是D2006)似乎认为它不会失败。