Here’s a routine to do an HTTP request using WinINet and either return the fetched string or raise an exception:
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;
If InternetCloseHandle(pRequest) can fail even though pRequest was successfully assigned, GetLastError() will return an error code for InternetCloseHandle() instead of HTTPSendRequest(). Fixing that would require code like:
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;
but that seems a lot uglier and more confusing at first glance.
Is it safe to assume InternetCloseHandle() won’t fail, thereby allowing the simpler code?
I think you are going about this the wrong way. You should simply check for errors on each API call and raise an exception as soon as you encounter one. That way you get the error message appropriate to the error that produces the exception. You simply can’t expect to carry on calling other API functions and then raise an exception for an error that happened some time ago.
I think you want something along these lines:
Note that you didn’t include any error checking for
InternetReadFile. I’ve attempted to write it for you.