?
Solved

Retrieve content size using WinInet

Posted on 2005-04-14
17
Medium Priority
?
3,892 Views
Last Modified: 2008-01-09
Hiya, I am trying to use the following code found on EE but I cannot get it to work and it is hopefully something simple I have messed up!
The FileSize retrieved does not seem to be accurate, for example I tried to get the size of http://www.google.co.uk/search?hl=en&safe=off&q=test&meta= but it said it was 1359176 bytes?? am i missing something here?

uses WinInet

procedure TForm1.Button2Click(Sender: TObject);
var
  hSession: HINTERNET;
  hService: HINTERNET;
  FileSize: Longint;
  dwSize, Reserved: DWORD;
  buf: String;
begin
  hSession := InternetOpen( 'MyApp', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0 );
  if Assigned( hSession ) then
  begin
    hService := InternetOpenUrl(hSession, PChar(edit1.text), nil, 0, 0, 0);
    if Assigned( hService ) then
    begin
      dwSize := sizeof(FileSize); //what does this do? FileSize isn't anything yet is it??
      Reserved := 0;
      HttpQueryInfo(hService, HTTP_QUERY_CONTENT_LENGTH or HTTP_QUERY_FLAG_NUMBER,
                    @FileSize, dwSize, Reserved); //get the size
      buf := Format('FileSize:%d', [FileSize]); //convert to a string
      form1.Memo1.Lines.Add( buf ); //add the size to TMemo
    end;
    InternetCloseHandle( hService );
  end;
  InternetCloseHandle( hSession );
end;

Thanks for any help, it's driving me mad, trying to avoid Indy which I was using previously as this seems to be faster.
Regards,
Justin Willis.
0
Comment
Question by:JustinWillis
  • 9
  • 6
  • 2
17 Comments
 
LVL 1

Author Comment

by:JustinWillis
ID: 13783685
Points Increased.
0
 
LVL 1

Author Comment

by:JustinWillis
ID: 13784392
And Again!
0
 
LVL 26

Expert Comment

by:Eddie Shipman
ID: 13791366
Your call to get the content length is failing and you aren't initializing FileSize.
That is why you get spurious results. Initialize FileSize to -1 and modify it like
this to catch the error:

if HttpQueryInfo(hService, HTTP_QUERY_CONTENT_LENGTH or HTTP_QUERY_FLAG_NUMBER,
                       @FileSize, dwSize, Reserved) then
begin
  buf := Format('FileSize:%d', [FileSize]); //convert to a string
  form1.Memo1.Lines.Add( buf ); //add the size to TMemo
end
else
begin
  err := SysErrorMessage(GetLastError);
  Memo1.Lines.Add(err);
end;

However, I was unable to get the error message, it came back blank for
error #317.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 26

Expert Comment

by:Eddie Shipman
ID: 13791476
Another thing is that I think you have to have an HTTPOpenRequest in order to retrieve the content length with HTTPQueryInfo
which you are not doing.
0
 
LVL 26

Expert Comment

by:Eddie Shipman
ID: 13791527
Well, I put my foot in my mouth, didn't I. You used code that I posted. I did however, find this from RLibby in another post:
"It is possible that the servers on these sites do not generate the "Content-Length:" header item. This is not a required header,
though most sites do return it."

It seems that that URL isn't returning that information to you and you are just out of luck there.
0
 
LVL 1

Author Comment

by:JustinWillis
ID: 13791993
Ok thanks, I will give this a try tonight and let you know.  It makes sense although I am not sure what you mean by using HTTPOpenRequest, sorry! I have been so use to using the nice n simple Indy components!

Oh and btw the code example I am using came from you I think in another thread, so it's all your fault!  ;-)

Cheers,
Just.
0
 
LVL 26

Expert Comment

by:Eddie Shipman
ID: 13792178
Well, seeing as the content you are trying to retrieve is dynamically generated, it is possible
that the server can not pass the content-length to you.
0
 
LVL 1

Author Comment

by:JustinWillis
ID: 13792372
hmm, that's a thought, but surely the server would generate the file first before accepting commands like this otherwise you could access the magical google script? will play with it to see if initializing FileSize solves it, I did try other static urls too so probably right on this one. Trying now..

Just.
0
 
LVL 1

Author Comment

by:JustinWillis
ID: 13792455
Sorry to be stupid Eddie but I just can't get this working, how do I initialize FileSize? I tried using Initialize(FileSize,-1) and FileSize := -1 already.
I also need to get the content type now (text/html) etc maybe you would be kind enough to show me how to retrieve this while i'm getting the FileSize, i imagine this is just one or two more lines of code added?

Thanks for your help, and sorry again for being so stupid.

Just.
0
 
LVL 1

Author Comment

by:JustinWillis
ID: 13792553
Also worth mentioning I think is that I am using Delphi 5 Pro, i think this has some bearing on the buffer side doesn't it? not that I know what i'm talking about..
0
 
LVL 26

Assisted Solution

by:Eddie Shipman
Eddie Shipman earned 750 total points
ID: 13792937
FileSize := -1 is correct.

However, found that the error that is being returned by the code is:
12150: ERROR_HTTP_HEADER_NOT_FOUND

Which means that the server is not passing the headers. I will install Ethereal and take a look
at the packets. I will get back to you.
0
 
LVL 1

Author Comment

by:JustinWillis
ID: 13793368
Ok, cheers man.  Appreciate your help.
0
 
LVL 26

Accepted Solution

by:
Russell Libby earned 750 total points
ID: 13807148
Justin,
In the example you gave:

 http://www.google.co.uk/search?hl=en&safe=off&q=test&meta=

In fact, this is the header set that is returned:

HTTP/1.0 200 OK
Cache-Control: private
Content-Type: text/html
Set-Cookie: PREF=ID= XXXXXX // removed
Server: GWS/2.1
Date: Mon, 18 Apr 2005 15:14:32 GMT
Connection: Close


The server DOES NOT return a content length, so as Eddie has already stated, the call is failing (which your code did not check for). There really isn't any need to init the filesize either, as the call will either succeed (and the value is good), or it will fail... and the value in filesize should NOT be evaluated. The only way to get the content size in this scenario is to perform the full download which will then give you the total.

Regards,
Russell



0
 
LVL 1

Author Comment

by:JustinWillis
ID: 13807378
Thanks for clarrifying Russell, I didn't realise that, it is probably best if I avoid trying to retrieve the size at all then incase the server does not pass it sometimes.  Seems only fair to split points, hope this is ok.

I am also wondering how easy it is to modify the code I am using to get Content-Type: text/html instead? or should this be a new question?

Thanks for your help,
JustinWillis.
0
 
LVL 26

Expert Comment

by:Eddie Shipman
ID: 13807980
Getting COntent-Type:

var
  hSession: HINTERNET;
  hService: HINTERNET;
  CType: String;
  dwSize, Reserved: DWORD;
  err: string;
begin
  hSession := InternetOpen( 'MyApp', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0 );
  if Assigned( hSession ) then
  begin
    hService := InternetOpenUrl(hSession, PChar('http://www.google.co.uk/search?hl=en&safe=off&q=test&meta='), nil, 0, 0, 0);
    if Assigned( hService ) then
    begin
      SetLength(CType, 256);
      dwSize  := 256;
      Reserved := 0;
      if HttpQueryInfo(hService, HTTP_QUERY_CONTENT_TYPE,
                             @CType[1], dwSize , Reserved) then
      begin
        Memo1.Lines.Add( CType);
      end
      else
      begin
        err := SysErrorMessage(GetLastError);
        Memo1.Lines.Add(err);
      end;
    end;
    InternetCloseHandle( hService );
  end;
  InternetCloseHandle( hSession );
end;
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 13808023
Being that you are already using wininet, and have gone though the steps of generating a request, it would make sense just to use HttpQueryInfo with the flag of HTTP_QUERY_CONTENT_TYPE.

eg:

var
  lpBuffer:      Array [0..1024] of Char;

  dwSize:=Pred(SizeOf(lpBuffer));
  if HttpQueryInfo(hService,  HTTP_QUERY_CONTENT_TYPE, @lpBuffer, dwSize, Reserved) then
  begin
     // lpBuffer contains the content type
     // ...
  end;

-----------

Russell


0
 
LVL 1

Author Comment

by:JustinWillis
ID: 13808046
Cheers guys,

Will play with this using your examples but I am sure it will work fine.

Thanks again,
JustinWillis.
0

Featured Post

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
When cloud platforms entered the scene, users and companies jumped on board to take advantage of the many benefits, like the ability to work and connect with company information from various locations. What many didn't foresee was the increased risk…
Is your organization moving toward a cloud and mobile-first environment? In this transition, your IT department will encounter many challenges, such as navigating how to: Deploy new applications and services to a growing team Accommodate employee…
Suggested Courses
Course of the Month8 days, 13 hours left to enroll

621 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question