Solved

Is there an Inet Reference Library?

Posted on 2000-02-16
7
1,718 Views
Last Modified: 2008-03-06
Hi,

I want to access the functionality of the Inet Control inside a project with no visual interface. Is there a library I could reference? Like the one that Inet control wraps?

Thanks
0
Comment
Question by:BabyFace
7 Comments
 
LVL 69

Expert Comment

by:Éric Moreau
ID: 2529392
You can add a dummy form to a project (that will never be shown to the user), add the Inet control to this form and use this instance of the control.
0
 
LVL 3

Expert Comment

by:MTroutwine
ID: 2529401
You can add a reference to the control by going to Projects->References and then clicking the Browse button.  Change the file types to *.ocx and you will the Inet ocx at C:\Winnt\System32\MSInet.ocx (if you have NT) or C:\Windows\System\MSInet (for 9x).  Highlight it and click okay.  You now can access the components functionality without adding to a form.  You can declare an object of Inet with something like this:

Dim obj As InetCtlsObjects.Inet
Set obj = CreateObject("InetCtlsObjects.Inet")

obj will not have all of the methods, events and properties avaiable to it!

:>)

0
 
LVL 1

Author Comment

by:BabyFace
ID: 2529683

I want the reference library, not the component.
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 6

Expert Comment

by:VBGuru
ID: 2530065
WinInet.dll
0
 
LVL 6

Expert Comment

by:VBGuru
ID: 2530068
Win32 Internet HTTP Functions in Visual Basic
James Braum
Microsoft Developer Network Technology Group

September 1996

Click to open or copy the files in the VBHTTP sample application for this technical article.

Abstract
Visual Basic® lets you leverage the power of the Microsoft® Win32® Internet (WinInet for short) Software Development Kit (SDK) in a number of useful ways. The WinInet general Internet functions allow you to easily read files from the Internet. This article is a successor to "Visual Basic and the WinInet SDK," which shows you the basics of these general functions. This technical article lets you dig a little deeper into the WinInet bag of tricks, showing you HTTP functions that will allow to do such things as determine a file size before reading it, examine and modify HTTP request headers, and look at HTTP response headers. A sample Visual Basic application (called VBHTTP) shows request and response headers that are exchanged between a client and an HTTP server during a transaction. You can do exciting things with WinInet, so I encourage you to read on for some ideas and examples of what can be done.

Introduction
The Microsoft Win32 Internet (WinInet) application programming interface (API) allows you to quickly create Internet-aware applications using a wealth of functions for working with HTTP, FTP, and Gopher protocols. Without the API, you would be overwhelmed with having to know the specifics of HTTP, TCP/IP, FTP, Windows® Sockets, and so on. Fortunately, the WinInet API makes life significantly easier. With Visual Basic, you can use the functionality that WinInet exposes in a number of useful ways. This article sheds some light on HTTP request and response headers, and how you can use them. A small sample (VBHTTP) illustrates the headers and shows how you can use this information to customize your HTTP server requests.

The WinInet API also provides FTP and Gopher functions; however, the WinInet SDK documentation indicates that these functions are best suited to asynchronous use, and Visual Basic requires third-party tools to use asynchronous functions and callbacks. Therefore, this article focuses on HTTP functions, which can safely be called synchronously. (For a look at how you would use the FTP functions asynchronously using Visual C++®, please refer to Robert Coleridge's article titled "Advanced FTP: Teaching Fido to Phetch."

This article begins with some background on the Hypertext Transfer Protocol (HTTP) and moves into HTTP specifics and the use of request and response headers.

HTTP Primer
What Is HTTP?
The Hypertext Transfer Protocol (HTTP) has been in use since 1990. HTTP is an application-level protocol that is fast and non–resource-intensive. It is the protocol used to transmit Hypertext Markup Language (HTML) files. It can be considered a generic protocol that can be used in a variety of ways.

This article is concerned with HTTP version 1.0, which is in common use today. The next version of HTTP, referred to as HTTP/1.1, is currently being developed by the World Wide Web Consortium (W3C) and the HTTP working group of the Internet Engineering Task Force (IETF). Their Web site at http://www.w3.org/ contains current drafts of specifications and more information about HTTP.

HTTP uses a request-and-response model to transfer information. In a simple case, the user agent (client application) sends a request to the server. The server responds with a message that contains a success or failure code, protocol version, server information, and body content, depending on the request. The user agent can modify the request to provide greater control over the server. The section of this article titled "WinInet HTTP Functions" looks at a WinInet function that will allow us to make such modifications.

HTTP Servers
The WinInet HTTP functions work with HTTP servers that recognize requests in HTTP/1.0. HTTP servers can actually be less complex than a typical user agent because they have an easier job: they just respond to requests. The client, on the other hand, must process the information that it has received in response to a request. In the case of an HTML file, this involves a significant amount of processing. To display an HTML page, for example, multiple threads may be spawned to simultaneously load and display inline .GIF and .JPG files.

HTTP Clients
WinInet is useful for creating HTTP clients. (The client is the application that sends a request to a server.) You can build your own Web browser, create Web-traversing robots, or write your own Internet-aware application for solving some particular problem.

Request Headers
Request headers are sent to the server as part of a request message. You can modify them to develop client applications that have detailed control over the server. If your client application needs caching capabilities, security, and so forth, you can append or modify request headers to do this.

Commonly used HTTP/1.0 request headers are:

Authorization


From


If-Modified-Since


User-Agent
Refer to the Internet Draft (http://www.w3.org/pub/WWW/Protocols/HTTP/1.0/spec.txt), published by the Internet Engineering Task Force in August 1996, for detailed descriptions of request headers.

Response Messages and Headers
HTTP servers respond to client requests in the form of a response message. This message contains a status line, response headers, and entity-header meta-information about the resource (that is, information about the resource itself, not about the information that is contained in the resource) identified in the request message sent by the client. The status line contains the HTTP version number, a status code, and a reason phrase. For instance, "HTTP/1.0 200 OK" is a typical status line returned in a response message from an HTTP server. Table 1 contains status codes and reason phrases.

Table 1. Status Codes and Their Meaning

Status Code Meaning
200 OK
201 Created
202 Accepted
204 No Content
301 Moved Permanently
302 Moved Temporarily
304 Not Modified
400 Bad Request
401 Unauthorized
403 Forbidden
404 Not Found
500 Internal Server Error
501 Not Implemented
502 Bad Gateway
503 Service Unavailable


Two common response headers are:

Location


Server
Entity-header fields that contain meta-information about the file (resource) specified in the request are also returned with the response message. Common entity-header fields are:

Allow


Content-Encoding


Content-Length


Content-Type


Expires


Last-Modified
The VBHTTP sample application groups the entity-header fields under the "Response Headers" tab to make it clearer to read. Instead of differentiating between response headers and entity-header fields, you can think in terms of headers returned in response to a request. This oversimplifies the issue somewhat, but this article is concerned with making things easy.

OK, enough background theory. Let's look at some actual Visual Basic code that lets us both view and modify our requests.

WinInet HTTP Functions
We will dive in with some sample code that requests a page, then looks at the content length of that page:

Dim hInternetSession       As Long
Dim hInternetConnect       As Long
Dim hHttpOpenRequest       As Long
Dim sBuffer               As String * 1024
Dim lBufferLength         As Long
lBufferLength = Len(sBuffer)
hInternetSession = InternetOpen(scUserAgent, _
         INTERNET_OPEN_TYPE_PRECONFIG, vbNullString, vbNullString, 0)
hInternetConnect = InternetConnect(hInternetSession, _
         "www.microsoft.com", INTERNET_DEFAULT_HTTP_PORT, _
         vbNullString, vbNullString, INTERNET_SERVICE_HTTP, 0, 0)
hHttpOpenRequest = HttpOpenRequest(hInternetConnect, "GET", _
         vbNullString,"HTTP/1.0", vbNullString, 0, _
         INTERNET_FLAG_RELOAD, 0)
HttpSendRequest hHttpOpenRequest, vbNullString, 0, 0, 0
HttpQueryInfo hHttpOpenRequest, HTTP_QUERY_CONTENT_LENGTH, _
         ByVal sBuffer, lBufferLength, 0
Debug.Print sBuffer
InternetCloseHandle (hInternetSession)

It doesn't take much code to examine the HTTP response headers before taking further action in your code. This example opens "www.microsoft.com" using the access parameters contained in the registry, then sends a request to retrieve the file. After sending the request, we examine the response from the server. The buffer contains the length of the file. (To keep things clear, the code does not check for errors.) Not all servers will provide file length for you. After examining the response header for content length, you can decide if you want to retrieve the file, using the InternetReadFile function.

Notice that there is only one call to InternetCloseHandle. This function allows you to close entire handle subtrees. Closing the root handle will close all subsequent handles you may have opened up.

This is the type of functionality that the WinInet HTTP functions provide that you can't get with the Internet functions. You will still use some Internet functions to open the connection and actually read the file.

The following sections examine these WinInet functions: InternetOpen, InternetConnect, HttpOpenRequest, HttpAddRequestHeaders, HttpSendRequest, HttpQueryInfo, InternetReadFile, and InternetCloseHandle.

InternetOpen
InternetOpen initializes our application's use of WinInet functions. A long handle is returned. Below are the two constants you can use to call the function, as well as the declaration you will need:

Public Const scUserAgent = "my wininet app"
Public Const INTERNET_OPEN_TYPE_PRECONFIG = 0
Public Declare Function InternetOpen Lib "wininet.dll" Alias _
   "InternetOpenA" (ByVal sAgent As String, ByVal lAccessType _
   As Long, ByVal sProxyName As String, ByVal sProxyBypass As _
   String, ByVal lFlags As Long) As Long

The Win32 Internet functions do not currently provide support for Unicode. However, support will be provided in future versions. Therefore, all the functions are aliased to call the ANSI version.

InternetConnect
InternetConnect returns a handle to an HTTP session. The two constants tell the function to listen on port 80, the default port that HTTP servers listen to, before establishing the connection. Here are the declaration and two constants that you will need:

Public Declare Function InternetConnect Lib "wininet.dll" Alias _
   "InternetConnectA" (ByVal  InternetSession As Long, _
   ByVal sServerName As String, ByVal nServerPort As Integer, _
   ByVal sUsername As String, ByVal sPassword As String, _
   ByVal lService As Long, ByVal lFlags As Long, _
   ByVal lContext As Long) As Long
Public Const INTERNET_DEFAULT_HTTP_PORT = 80
Public Const INTERNET_SERVICE_HTTP = 3

HttpOpenRequest
HttpOpenRequest returns an HTTP request handle. Here are the declaration and a constant you will need:

Public Declare Function HttpOpenRequest Lib "wininet.dll" Alias _
      "HttpOpenRequestA" (ByVal hHttpSession As Long, ByVal sVerb As _
      String, ByVal sObjectName As String, ByVal sVersion As String, _
      ByVal sReferer As String, ByVal something As Long, ByVal lFlags _
      As Long, ByVal lContext As Long) As Long
Public Const INTERNET_FLAG_RELOAD = &H80000000

HttpOpenRequest takes eight parameters (described below) and returns the HTTP request handle, if successful. The handle holds the request until you send it with HttpSendRequest, which stores the HTTP headers to be sent as part of the request.

hHttpSession is the handle returned from a previous call to InternetConnect.


sVerb is a string that contains a method, or verb, to use for the request. Two common HTTP 1.0 verbs (methods) are GET and POST. These verbs are case-sensitive. GET retrieves a file. POST tells the server to accept some information that you are passing to it—for example, when you are submitting a response to a form. If the sVerb parameter is NULL, GET will be used.
If the If-Modified-Since header field is used, the GET becomes a conditional get. It will only retrieve the file if the file has been modified since a particular date specified in the header field. You can structure your requests to only retrieve the file if it has been changed since some predetermined point in time. An example of this will be illustrated below.

sObjectName is the object we are interested in. This is usually a file, but it can also be a search specifier or an executable.


sVersion is the HTTP version. Leaving this NULL is equivalent to specifying HTTP/1.0.


sReferer is a string that contains a URL of a document containing a URL in the sObjectName. This parameter can be left NULL to specify no "referer" [sic].


sAcceptTypes is a string containing a list of valid acceptance types. Leaving this NULL will indicate that only text documents will be accepted.


lFlags is an action flag. Use the INTERNET_FLAG_RELOAD flag to instruct the function to retrieve data from the server even if it is locally cached.


lContext is an application-defined value. For the simple examples presented here, just use 0.
HttpAddRequestHeaders
The HttpAddRequestHeaders function allows you to add or modify headers before sending them to the server. Here are the declaration and three constants you need:

Public Declare Function HttpAddRequestHeaders Lib "wininet.dll" Alias _
      "HttpAddRequestHeadersA" (ByVal hHttpRequest As Long, _
      ByVal sHeaders As String, ByVal lHeadersLength As Long, ByVal _
      lModifiers As Long) As Integer
Public Const HTTP_ADDREQ_FLAG_ADD_IF_NEW = &H10000000
Public Const HTTP_ADDREQ_FLAG_ADD = &H20000000
Public Const HTTP_ADDREQ_FLAG_REPLACE = &H80000000

hHttpRequest is the handle returned from the call to HttpOpenRequest. This is contrary to the WinInet SDK documentation, which indicates that this is the handle returned from the call to InternetConnect. So please note that you should pass the handle returned from the HttpOpenRequest call, or the function call will return NULL.


The sHeaders parameter contains the headers you want to append to the request. Each header must be terminated with a carriage return/line feed (CR/LF) pair. You can send more than one header with this string. A common header that you can send is the "If-Modified-Since" header, which will add conditional behavior to the GET verb specified in the HttpOpenRequest function. After opening a request, you can append a header that tells the server not to return the contents of the file in the body of the message if the file has not been modified since a certain date (see note below). This is how a Web browser could manage caching pages: Before sending the request, the client looks to see if it already has a copy of the page. If it does, it checks the time that it was loaded into the cache directory. The browser then appends the appropriate request header. If the file has not been updated since the last time it was cached on the client's machine, the server will respond with status code 304, which indicates "not modified." The browser then displays the page by reading it from the cache instead of bringing it across the wire.
Note   All HTTP/1.0 dates are represented as Greenwich Mean Time (GMT). An HTTP Date in augmented Backus-Naur Form (BNF) is:

HTTP-date      = rfc1123-date | rfc850-date | asctime-date
rfc1123-date   = wkday "," SP date1 SP time SP "GMT"
rfc850-date    = weekday "," SP date2 SP time SP "GMT"
asctime-date   = wkday SP date3 SP time SP 4DIGIT
date1          = 2DIGIT SP month SP 4DIGIT
                 ; day month year (e.g., 02 Jun 1982)
date2          = 2DIGIT "-" month "-" 2DIGIT
                 ; day-month-year (e.g., 02-Jun-82)
date3          = month SP ( 2DIGIT | ( SP 1DIGIT ))
                 ; month day (e.g., Jun  2)
time           = 2DIGIT ":" 2DIGIT ":" 2DIGIT
                 ; 00:00:00 - 23:59:59
wkday          = "Mon" | "Tue" | "Wed"
               | "Thu" | "Fri" | "Sat" | "Sun"
weekday        = "Monday" | "Tuesday" | "Wednesday"
               | "Thursday" | "Friday" | "Saturday" | "Sunday"
month          = "Jan" | "Feb" | "Mar" | "Apr"
               | "May" | "Jun" | "Jul" | "Aug"
               | "Sep" | "Oct" | "Nov" | "Dec"

(See also: http://www.w3.org/)

lHeadersLength is the length of the sHeaders string.


lModifiers are several different flags you can use to modify the behavior of the function. The constants are defined above. You can add the flags together to get the desired action. Here are three flags that you can use:
HTTP_ADDREQ_FLAG_REPLACE is used to remove existing headers or overwrite them with new ones. If the header already exists and the value you are specifying is empty, that header will be removed. If you are supplying a new value to an existing header, this new value will replace the old value.


HTTP_ADDREQ_FLAG_ADD adds the header to the request message if it does not already exist.


HTTP_ADDREQ_FLAG_ADD_IF_NEW adds a header. If a header already exists, however, the function will return an error.
There are three other flags that can be used if you are interested in coalescing headers. Refer to the WinInet SDK documentation (http://www.microsoft.com/intdev/sdk/docs/wininet) if this interests you.

HttpSendRequest
After you have opened your request and added request headers, if any, you are ready to send your request to the server. The HttpSendRequest function does exactly what you would expect: It sends your request. It also lets you append additional request headers before you send it, so you do not have to make an additional call to HttpAddRequestHeaders. (I would, however, recommend using HttpAddRequestHeaders so you can explicitly check the return value to ensure that the request headers were successfully appended or modified.) After the request is sent, the status line, response headers, and any entity header meta-information are read. You can interrogate these with the HttpQueryInfo function, which is discussed below.

The declaration for HttpSendRequest is:

Public Declare Function HttpSendRequest Lib "wininet.dll" Alias _
      "HttpSendRequestA" (ByVal hHttpRequest As Long, ByVal sHeaders _
      As String, ByVal lHeadersLength As Long, sOptional As Any, _
      ByVal  lOptionalLength As Long) As Integer

The function will return TRUE if the request was successfully sent.

hHttpRequest is the handle returned from HttpOpenRequest.


sHeaders and lHeadersLength are two parameters that can be used for appending additional headers to the request, instead of making a separate call to HttpAddRequestHeaders.


sOptional and lOptionalLength are parameters for sending additional data along with the request. This is not used for GET requests, so we leave these two parameters NULL in our sample application.
HttpQueryInfo
This function lets you look at the status line, response headers, and entity header meta-information returned from the request sent by HttpSendRequest.

The declaration is:

Public Declare Function HttpQueryInfo Lib "wininet.dll" _
   Alias "HttpQueryInfoA" (ByVal hHttpRequest As Long, _
   ByVal lInfoLevel As Long, ByRef sBuffer As Any, _
   ByRef lBufferLength As Long, ByRef lIndex As Long) As Integer
Public Const HTTP_QUERY_FLAG_REQUEST_HEADERS = &H80000000

The function returns TRUE if successful.

As usual, hHttpRequest is the handle returned from the call to HttpOpenRequest.


lInfoLevel is the response header or entity-header metainformation we are interested in interrogating, along with a request modifier flag. If you do not include an optional flag, the response headers will be queried. The sample application contains a number of constants you can use for querying these attributes. HTTP_QUERY_CONTENT_LENGTH is one such constant that can be used to get metainformation about the resource identified in the request.


sBuffer is the buffer into which the results are copied. Notice that the declaration specifies that the parameter will be passed by reference. When you actually call the function, you can call it by value with the ByVal keyword in front of the variable in the function call.


lBufferlength is the length of the buffer. When the function successfully returns strings, this value will be set to the actual length of the response that was copied into the buffer. If the function fails, this parameter indicates the size that the buffer must actually be in order to receive the string.


lIndex is used when you have multiple headers with the same name. Leave this set to 0 unless you have some need for using multiple headers.
InternetReadFile
InternetReadFile is the function that will start reading the file once you have sent the request and decided to actually retrieve the body content.

Public Declare Function InternetReadFile Lib "wininet.dll" _
      (ByVal hFile  As Long, ByVal sBuffer As String, _
      ByVal lNumberOfBytesToRead As Long, lNumberOfBytesRead As Long) _
      As Integer

hFile is the handle returned from the call to HttpOpenRequest.


sBuffer is the buffer.


lNumberOfBytesToRead is the number of bytes returned; lNumberOfBytesRead is the actual number of bytes that were read.
InternetCloseHandle
The InternetCloseHandle function closes handles and frees resources associated with WinInet functions. The function returns TRUE if the handle is successfully closed. This is the declaration:

Public Declare Function InternetCloseHandle Lib "wininet.dll" _
   (ByVal hInet As Long) As Integer

hInet is the handle you want to close.
VBHTTP Sample Application
This sample application lets you examine the request and response headers that are exchanged between the client and the HTTP server during a typical transaction. The following screen shot, from our sample, is what you will see when you run it (Figure 1).


Figure 1. Response view

The screen contains results sent back from the request sent to www.microsoft.com. We are looking at the status message, response headers, and entity header meta-information about the resource content.

From this we can determine that the content length is 10,447 bytes, the status code is 200 (which means "OK"), and the content expires on Wednesday, September 11, 1996, at 16:19:02 GMT. With this, your Internet-aware application can determine if the content is still valid, verify that the content type is correct, and set up a progress meter so that when the resource is read the progress can be displayed.

Let's take a look at the request headers that were sent to the server (Figure 2).


Figure 2. Request view

We can see that GET is the request method, "http sample" is the user agent (this is typically more useful product information), and the Pragma is "No-Cache," which tells the server to send the page regardless of whether or not the client has it cached. You can also see that we sent a cookie—"MC1=GUID=3986c31df6ce11cfbcee0000f84a13db"—to the server.

These are just to give you an idea of what information is available with simple calls to the WinInet functions.

How Is This Useful to Me?
You can add a request header instructing the server to send the content of the resource only if it was updated after a certain time. This way the application only retrieves the content if it has changed since the last time it was retrieved.

For instance, a call to the WinInet HttpAddRequestHeaders function adds a request header that indicates to the server that we are only interested in seeing the content of the resource specified in the HttpOpenRequest call if that resource has been modified since August 24, 1996. The following example shows how this request header is added. You would insert the following code just after you open your HTTP request using the handle returned from that call.

Dim sHeaders    As String
Dim lLength    As Long
Dim iRetVal    As Integer
           
sHeaders = "If-Modified-Since: Sat, 24 Aug 1996 17:38:52 GMT" & vbCrLf
lLength = Len(sHeaders)
iRetVal = HttpAddRequestHeaders(hInternetConnect, sHeaders, lLength, _
            HTTP_ADDREQ_FLAG_ADD Or HTTP_ADDREQ_FLAG_REPLACE)

Check the return value to make sure that it successfully added the request.

If the file has not been modified since the date specified, the status code in the response message will be 304, "Not Modified." You can check for this, then opt to not call the InternetReadFile function to retrieve the contents.

DLL Version
It is easy to check which version of the WinInet DLL you are using. Add these declarations to your project:

Public Declare Function InternetQueryOption Lib "wininet.dll" _
      Alias "InternetQueryOptionA" (ByVal hInternet As Long, _
      ByVal lOption As Long, ByRef sBuffer As Any, ByRef lBufferLength _
      As Long) As Integer
Public Const INTERNET_OPTION_VERSION = 40
Public Type tWinInetDLLVersion
    lMajorVersion As Long
    lMinorVersion As Long
End Type

InternetQueryOption is a WinInet function that lets you check option settings on a specified handle. INTERNET_OPTION_VERSION will return the version of the DLL that you are currently using.

This is how you call the function:

dim vDllVersion As tWinInetDLLVersion
dim iRetVal    As Integer
iRetVal = InternetQueryOption (hInternetSession, _
         INTERNET_OPTION_VERSION, vDllVersion, Len(vDllVersion))
Debug.Print vDllVersion.lMajorVersion
Debug.Print vDllVersion.lMinorVersion

You can use this function to check for the length of time before a connection attempt will time out, or to return the parent handle of the connection, and so forth.

Conclusion
As you can see, the WinInet HTTP functions provide you with more flexibility than the general WinInet Internet functions. Using these functions will allow you to build slick Internet-aware applications that have more sophisticated control over the requests they send to the server.


--------------------------------------------------------------------------------
Send feedback to MSDN.Look here for MSDN Online resources.
0
 
LVL 6

Accepted Solution

by:
VBGuru earned 50 total points
ID: 2530073
Visual Basic and the Win32 Internet SDK
James Braum
Microsoft Developer Network Technology Group

September 5, 1996

Click to open or copy the files in the VBNetGet sample application for this technical article.

Abstract
This article examines a variety of Microsoft® Win32® Internet (WinInet) functions and illustrates how to use them in a Visual Basic® application. Declaring and using these WinInet functions in a class module allows you to leverage the power of the Win32 Internet API, facilitating rapid development of slick Internet-aware applications in any language. This article does not provide in-depth coverage of the API functions; for that refer to the Microsoft Win32 Internet Programmer's Reference at http://www.microsoft.com/intdev/sdk/docs/wininet/.

In this article, I develop a sample application (NetGet) that lets you download and view the contents of a Uniform Resource Locator (URL). The application uses a reusable class that is developed along the way. This class encapsulates the calls to the WinInet functions, making it convenient to use in your own projects. (If you are interested in looking at a Visual C++® implementation of the WinInet functions, refer to the article "The Internet API (or How to Get from Here to There)" by Robert Coleridge, elsewhere on this CD.) The raw HTML is put into a text box, and the list of references and images are parsed and loaded into two different list box controls. A third list box control contains the files you can download.

Introduction
Several third-party tools and controls are available for developing Internet-aware applications, including the Microsoft Internet Control Pack, (information available from http://www.microsoft.com/icp/icpmain.htm). It is often more convenient to write straight to an application programming interface (API) to get exactly the functionality you need rather than to plug in a control, because you can pick and choose exactly the set of functions you need to get a particular job done. Programming with the Win32 Internet (WinInet) API gives you just this level of control. Finding the functions you need and placing them in a class module makes sense because you end up with a reusable and robust object. After you have tested the object, you can safely use it in other projects. That's what this article demonstrates.

WinInet provides a wealth of functionality. Functions for working with Gopher, File Transfer Protocol (FTP), and Hypertext Transfer Protocol (HTTP) abstract the complexities of working with these protocols into an easy-to-use API that can be called from almost any language. Knowledge of Transmission Control Protocol/Internet Protocol (TCP/IP), Windows® Sockets, the inner workings of HTTP, and so forth are not required to use this API. Additionally, because this API offers an abstraction from the actual implementation, you can be sure that as protocols evolve you will not have to rewrite your applications; only the WinInet DLL will need upgrading.

Consider this article a starting point. Take the ideas presented and apply them to your solution set. If the sample class contains the functionality you need, simply drop it into your project and go to work.

The WinInet Functions
This article examines four WinInet functions: InternetOpen, InternetOpenUrl, InternetReadFile, and InternetCloseHandle.

Let's dive right in and look at some sample code. The following code reads the contents of a URL into a buffer. It does not take reams of code to get the contents of a URL—you simply open the connection using InternetOpen, call InternetOpenUrl with a URL you would like to read (http://www.microsoft.com/ in this case, but I am sure that you can come up with one on your own), progressively read the file using InternetReadFile, and close both connections with InternetCloseHandle.

Dim hInternetSession       As Long      
Dim hUrlFile               As Long
Dim sReadBuffer            As String * 4096     ' Grab 4k at a time
Dim sBuffer                As String
Dim lNumberOfBytesRead     As Long
Dim bDoLoop                As Boolean
hInternetSession = InternetOpen("My VB App!", _
         INTERNET_OPEN_TYPE_PRECONFIG, vbNullString, vbNullString, 0)
hUrlFile = InternetOpenUrl(hInternetSession, _
         "http://www.microsoft.com/", vbNullString, 0, INTERNET_FLAG_RELOAD, 0)
bDoLoop = True
While bDoLoop
   sReadBuffer = scBlankStr
      bDoLoop = InternetReadFile(hUrlFile, sReadBuffer, _
                  Len(sReadBuffer), lNumberOfBytesRead)
      sBuffer = sBuffer & Left$(sReadBuffer, lNumberOfBytesRead)
If Not Cbool(lNumberOfBytesRead) Then bDoLoop = False
Wend
InternetCloseHandle(hUrlFile)
InternetCloseHandle(hInternetSession)

InternetOpen
This function returns a handle that subsequent WinInet function calls use. The declaration looks like this:

Private Declare Function InternetOpen Lib "wininet.dll" _
      Alias "InternetOpenA" (ByVal sAgent As String, _
      ByVal lAccessType As Long, ByVal sProxyName As String, _
      ByVal sProxyBypass As String, ByVal lFlags As Long) As Long

The InternetOpen function takes five parameters and returns a handle if successful. Look at the LastDLLError property of the Err object if the call fails for a specific error code. Check the Error Codes section in the Microsoft Win32 Internet Programmer's Reference (http://www.microsoft.com/intdev/sdk/docs/wininet/) for relevant information corresponding to the error codes.

The sAgent parameter specifies the name of the application or entity calling the Internet functions. This is the user agent in the HTTP protocol. This could be a value such as "My Internet Application" or "Microsoft Internet Explorer." Some Web servers look at this to autodetect the type of client you are using. Think of this as the way you identify yourself to the HTTP server.

The lAccessType parameter indicates the type of access needed.

Use INTERNET_OPEN_TYPE_PRECONFIG to instruct the function to interrogate the registry for access information. The registry is automatically configured when you run Microsoft Internet Explorer. Add this declaration to your class module:
Private Const INTERNET_OPEN_TYPE_PRECONFIG = 0

The INTERNET_OPEN_TYPE_DIRECT flag specifies local resolution of host names.


INTERNET_OPEN_TYPE_PROXY allows you to specify a proxy. This leads us to a discussion of the next two parameters: sProxyName and sProxyBypass.
sProxyName is a string specifying the proxy server (or servers) to use if requested. To interrogate the registry for proxy server details, leave this parameter NULL and set the lAccessType to INTERNET_OPEN_TYPE_PROXY.

sProxyBypass is a string containing a list of hosts or Internet Protocol (IP) addresses known locally so they are not passed through to the proxy server. To interrogate the registry for local IP addresses, leave this parameter NULL and use the INTERNET_OPEN_TYPE_PROXY for the lAccessType.

lFlags specifies if you want asynchronous or synchronous behavior from subsequent WinInet function calls derived from this handle. To get synchronous behavior, you must specify 0 for this flag.

InternetOpenUrl
This function returns a handle to the URL if the connection succeeds. This is the function that actually begins to read from the URL.

It is important to note that you can use these functions today with Gopher, FTP, and HTTP protocols; they are essentially all-purpose Internet functions. For opening and reading Hypertext Markup Language (HTML) from a HTTP URL, these functions are more than adequate. However, if you need additional functionality, such as querying for the number of bytes the URL will return, look at the HTTP WinInet functions in the Microsoft Win32 Internet Programmer's Reference.

The declaration looks like this:

Private Declare Function InternetOpenUrl Lib "wininet.dll" _
   Alias "InternetOpenUrlA" (ByVal hInternetSession As Long, _
   ByVal sUrl As String, ByVal sHeaders As String, _
   ByVal lHeadersLength As Long, ByVal lFlags As Long, _
   ByVal lContext As Long) As Long

InternetOpenUrl takes six parameters and, if successful, returns a handle. After you have finished with the handle returned from this function, close it with the InternetCloseHandle function.

hInternetSession is the handle obtained from calling InternetOpen.

sUrl is a string with the URL that you wish to read. The function will parse the URL for you, so just specify the complete URL.

sHeaders is a string that contains optional headers you may want to send to a HTTP server. lHeadersLength is the length of the optional headers string (if you use one). The request-header fields in HTTP allow the client to pass additional information about the request, and about the client itself, to the server. For example, you could specify a Transfer-Encoding scheme and request that the data be sent in that particular format.

lFlags is an action flag for the function—it tells the function how to behave. It can be one of these values:

The INTERNET_FLAG_RELOAD flag directs the function to read data from the remote service even if it is locally cached.


Use INTERNET_FLAG_DONT_CACHE when you don't want to cache data locally.


Use INTERNET_FLAG_RAW_DATA to return WIN32_FIND_DATA data structures if you are reading data from an FTP URL. The function defaults to returning HTML.


INTERNET_FLAG_SECURE specifies use of Secure Sockets Layer (SSL) for secure HTTP requests with authentication by RSA Data Security, Inc.


INTERNET_FLAG_EXISTING_CONNECT tells the function to reuse existing connections if possible.
lContext is passed to callback functions along with the returned handle. Just use 0 for this flag because you are using these functions synchronously.

InternetReadFile
Once you have a handle from InternetOpenUrl you can start reading data. You pass this function a buffer to read the data into and a value indicating the length of the buffer. The function returns TRUE if successful, and FALSE otherwise. An out parameter, lNumberOfBytesRead, indicates how much data was read from the call. If the function returns TRUE and the out parameter indicating the number of bytes read is 0, the function has read all the data corresponding to the URL.

Here is the declaration:

Private Declare Function InternetReadFile Lib "wininet.dll" _
   (ByVal hFile As Long, ByVal sBuffer As String, _
   ByVal lNumberOfBytesToRead As Long, _
   lNumberOfBytesRead As Long) As Integer

hFile is the handle returned from the call to InternetOpenUrl.

sBuffer is a string that serves as the buffer. For reading HTML data, this buffer must be large enough to contain the complete HTML headers. Also, if you are reading directories in HTML format, the buffer must be large enough to hold the entire contents of the directory. A 32K buffer will be large enough in most cases.

lNumberOfBytesToRead specifies the number of bytes you want to read in one call to the function. Make this equal to the length of the buffer, unless you only want to fill a portion of the buffer for each read.

Finally, lNumberOfBytesRead is the number of bytes the function actually read. It is an out parameter, so this variable will be set by the function.

InternetCloseHandle
This function closes handles opened with WinInet functions and frees resources associated with these functions. If there are outstanding operations on handles that are about to be closed, they will be canceled and the data will be lost.

The function returns TRUE if the handle was closed successfully, and FALSE otherwise. This is the declaration:

Private Declare Function InternetCloseHandle Lib "wininet.dll" _
      (ByVal hInet As Long) As Integer

The NetGet Sample Application
Now let's look at the sample Visual Basic® application, which allows us to view the raw HTML from a specified URL and download files. The sample application uses a class module that will encapsulate the WinInet API calls discussed above. You can drop this class into your project and go to work developing Internet-aware applications, or you can copy the declare statements and use the functions in your own classes or modules.

The NetGet application lets you specify a URL, then view the HTML, references, and images associated with this URL. Double-clicking an image will place a copy of the image in the files list box on the right. The files will be saved to the app.path when you click the Save Files button. The application does some simplistic parsing of the HTML to get the references and images. To find the references, it looks for "<A HREF=", and to find images it looks for "<IMG SRC="; it then continues to read until it reaches the end of the tag.


Figure 1. NetGet References/Images/Files View

NetGet consists of one form and one class module. When the application starts it instantiates an instance of the CNetGet class. You can use this one instance of the object to read multiple URLs.

How to Use CNetGet
The CNetGet object exposes the following methods and properties:

Methods Properties  
ReadURL GetRawHTML
ParseHTML GetLastError
Init SetStatusWindow
Term SetUserAgent


The ReadURL method calls the WinInet functions and reads the URL into a private buffer. The method returns TRUE if it successfully allocates a session handle, reads the data, and closes the handles. If there are problems along the way, the method returns FALSE.


ParseHTML adds items to a collection object that you pass in with the references, images, or whatever you told it to parse. You can see some of the code corresponding to this method below.


Init and Term are the initialize and terminate methods of the object. Once you instantiate the object, invoke the Init method. When you are done with the object, invoke the Term method.


SetStatusWindow takes an object where status messages are to be displayed. The method sets the default property of the object passed to it. For instance, you may want the status messages to go to a Status Bar control, so you set the property like this:
objNetGet.SetStatusWindow = StatusBar1.Panels(1)

·GetLastError returns the last DLL error from a WinInet function call. If the object receives an error from calling one of the WinInet functions, you can check the error text corresponding to the error message with the property.


SetUserAgent allows you to set the user agent property of the object.


GetRawHTML returns the HTML that was read from the call to the ReadURL method.
As you can see, the object exposes a few easy-to-use methods and properties that facilitate quick and easy development of Internet-aware applications. Using the object is easy. All it takes is some code like this:

Dim objNetGet    As New CNetGet
Dim cRefs        As New Collection
Dim vRef         As Variant
objNetGet.Init
If objNetGet.ReadURL("http://www.microsoft.com/") Then
If objNetGet.ParseHTML("A HREF=""", CRefs, " "" > ? # ") Then  
For Each vRef In cRefs
   debug.print vRef
Next vRef
End If
End If
objNetGet.Term
Set objNetGet = Nothing

The GetRawHTML property exposes the interface to the HTML. Clicking the HTML tab gives you a view of the HTML:


Figure 2. NetGet raw HTML view

Implementation of the CNetGet Class Module
Now that you have seen the interface to the object, let's look at the implementation.

The general declarations section of the class module contains the WinInet declarations as well as the following private constants and variables:

Private Const INTERNET_OPEN_TYPE_PRECONFIG = 0
Private Const INTERNET_FLAG_RELOAD = &H80000000
Private hInternetSession    As Long
Private hUrlFile            As Long
Private sContents           As String
Private sLastError          As String
Private sStatus             As String
Private objWindow           As Object

The flags and the user agent constant have already been discussed. The other two private variables are for the handles returned from the calls to InternetOpen and InternetOpenUrl. objWindow is the window that you want the object to update. sContents contains the HTML read from the URL.

The ReadURL method calls the functions necessary to open, read data from, and close an Internet connection.

Public Function ReadUrl(ByVal sUrl As String, Optional vFileName As _
                        Variant) As Boolean
Dim sReadBuffer         As String * 2048 ' Bytes to read from one call
Dim lNumberOfBytesRead  As Long       ' Bytes read from call to InternetReadFile
Dim lTotalBytesRead     As Long       ' Total bytes read
Dim bDoLoop             As Boolean    ' Return value from InternetReadFile
Dim bReadInternetFile   As Boolean
Dim bWriteToFile        As Boolean
On Error GoTo errReadUrl
Screen.MousePointer = vbHourglass
SetStatus "Opening Url..."
If Not IsMissing(vFileName) Then
    Dim iFileNum As Integer
    iFileNum = FreeFile
    Open CStr(vFileName) For Binary As iFileNum
    bWriteToFile = True
End If
hUrlFile = InternetOpenUrl(hInternetSession, sUrl, vbNullString, 0,_
                           INTERNET_FLAG_RELOAD, 0)
If CBool(hUrlFile) Then
    sContents = scBlankStr
    bDoLoop = True
    While bDoLoop
        sReadBuffer = scBlankStr
        bDoLoop = InternetReadFile(hUrlFile, sReadBuffer, Len(sReadBuffer), _
                           lNumberOfBytesRead)
        If Not CBool(bDoLoop) Then CheckError
        lTotalBytesRead = lTotalBytesRead + lNumberOfBytesRead
        SetStatus "Reading Url: " & CStr(lTotalBytesRead) & " Bytes read..."
        If CBool(lNumberOfBytesRead) Then
            If bWriteToFile Then
                Put #iFileNum, , sReadBuffer
            Else
                sContents = sContents & Left$(sReadBuffer,lNumberOfBytesRead)
            End If
        Else
            bDoLoop = False
            bReadInternetFile = True
        End If
    Wend
    InternetCloseHandle (hUrlFile)
    ReadUrl = True
Else
    CheckError
End If
If bWriteToFile Then Close
SetStatus "Ready"
Screen.MousePointer = vbDefault
Exit Function
errReadUrl:
sLastError = Error$(Err)
Screen.MousePointer = vbDefault
Exit Function
End Function

This function illustrates the order in which you call the WinInet functions.

If the ReadURL function returns FALSE, check the GetLastError property of the object for a meaningful error message.

ParseHTML takes a token to search for, such as <A HREF="", a collection, and an optional string that contains a list of delimiters. When the token is found (<A HREF="" in this case) the method scans until it reaches one of the delimiter characters in the delimiter string. Here is a look at a portion of the method:

    lStartPos = 1
    lPosInStr = InStr(lStartPos, sContents, sToken, 1)
    While CBool(lPosInStr)
        iCounter = 0
        lPosInStr = lPosInStr + Len(sToken)
        Do
            iRetVal = InStr(1, sUseDelimiter, Mid$(sContents, lPosInStr + _
                  iCounter, 1), 1)
            iCounter = iCounter + 1
        Loop While Not CBool(iRetVal)
        sAddItem = StripChars(Mid$(sContents, lPosInStr, iCounter - 1))
        If Len(sAddItem) Then colItems.Add sAddItem, sAddItem
        lStartPos = lPosInStr + iCounter
        lPosInStr = InStr(lStartPos, sContents, sToken, 1)
    Wend

The StripChars function removes linefeeds and other unnecessary characters from the strings  recognized by the routine.

This should give you an idea of what you can do once you have read an HTML page. I can think of a number of applications where you would want to read a HTML page and parse the contents. For example, with the references parsed from each page you could construct a Web-traversing robot that could go out and recursively search for pages that contain some particular text.

Conclusion
It is amazingly simple to develop Internet-aware applications using the WinInet functions. Keep in mind that the functions presented in this article are quite generic. The InternetReadUrl function, for instance, is a wrapper to other WinInet functions. If you need to work with the specifics of a particular protocol, such as HTTP or FTP, you should use the more appropriate HTTP or FTP WinInet functions. For reading files from the Internet, however, these functions are very well suited to the task.


--------------------------------------------------------------------------------
Send feedback to MSDN.Look here for MSDN Online resources.
0
 

Expert Comment

by:Simone_Italia
ID: 6255879
Good suggestion, MTroutwine!!!
Simone
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

When trying to find the cause of a problem in VBA or VB6 it's often valuable to know what procedures were executed prior to the error. You can use the Call Stack for that but it is often inadequate because it may show procedures you aren't intereste…
When designing a form there are several BorderStyles to choose from, all of which can be classified as either 'Fixed' or 'Sizable' and I'd guess that 'Fixed Single' or one of the other fixed types is the most popular choice. I assume it's the most p…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…

743 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

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now