WinInet: Enable HTTP Communication in Windows-Based Client Applications This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links. WinInet: Enable HTTP Communication in Windows-Based Client Applications | | Todd Meister | | This article assumes you�re familiar with HTTP and Visual Basic | | Level of Difficulty 1 2 3 | | Download the code for this article: UseMon.exe (43KB) | | Browse the code for this article at Code Center: UseMon | | SUMMARY The Internet provides the infrastructure for applications to communicate, and that can include non-UI communication between Win32-based applications. If you think beyond the standard browser usage of HTTP, you can use this protocol to retrieve information from Win32-based applications and save it to a Web server. After explaining how HTTP can be used in this way, this article shows how to use Microsoft SQL Server, ASP, IIS, WinInet, and Visual Basic to implement two examples. The first reports usage data—how often an application is used and by whom. The second monitors application errors and reports error details for use by helpdesk staff or engineers in the debugging process. | TTP is a versatile protocol because it not only provides a way for Web browsers and Web servers to communicate, it can also be used as a way for Windows®-based client applications to communicate with Web servers. This is a simple concept, but it's underutilized. Many people assume HTTP can only be used for browser-based communications. However, there are several benefits to using HTTP as your communication protocol. Before describing these benefits, let me first describe two scenarios that could benefit from communications using HTTP. The sample applications for this article are built around these two scenarios. The first scenario is tracking an application's usage. You could track many kinds of information, including simple statistics such as when your application was started and when it was exited. You could even track what users do with your application to see which features are used most frequently. The second scenario involves tracking application errors. Generally, if an error occurs in an application, the user receives a dialog box indicating the error type and description. Additionally, depending on the severity, an event may be generated in the user's Event Log. It would be great if your helpdesk personnel knew the details of the error before the client even called to request help. Tracking the errors and sending the information to your Web server allows you to do this. And it would be even better if your helpdesk could call the user when the error occurred and be able to present a solution immediately. Over time you may even notice the same type of error occurring. Details about this error beyond what was displayed to the user or logged in the Event Log could be sent to the helpdesk, thereby benefiting the debugging process. This type of service could be an added feature to your app that sets you apart from your competition. Now let's take a look at why HTTP is the right protocol to use and how you can use it in your monitoring application. Later, I'll walk through the two sample applications I've written to show you how HTTP was used. Finally, I'll talk about the use of the WinInet functions in these examples and share some tips I learned during the course of development of these applications.
Benefits of HTTP There are many benefits to using HTTP rather than creating your own protocol. Unfortunately, I learned this the hard way. An important advantage of HTTP is that it promotes scalability. For example, if your application begins to generate a great deal of traffic, you can add more servers to handle the load. (Windows 2000 Server comes with load-balancing functionality.) HTTP also works well with firewalls. To implement this type of solution, you just need an existing Web server with access through the firewall. If, on the other hand, you create your own protocol, you have to specify a port for it. If you use HTTP, you can use Microsoft Internet Information Services (IIS) as your server instead of creating your own. It would take years of development to match the performance and reliability that IIS already provides, plus you can use WinInet, the set of functions that provide access to the Internet. Using IIS and the WinInet functions will be discussed later in this article. Finally, since you're using IIS, you can employ your knowledge of ASP, ActiveX® Data Objects (ADO), and VBScript to create your listening application faster and easier. Communication Using HTTP When you create a Web-based application using a standard HTML form, your form's action attribute tells your browser where to send the form's input. When developing on IIS, your form's action is usually pointed to an ASP file, though there are many other file types that will work. The action you specify dictates how the information on the form is submitted back to the server. The METHOD attribute of the <FORM> tag specifies how the information will be sent to the server. Setting the METHOD attribute to GET sends the information in the query string to the ASP file (so it can be extracted using the Request object's QueryString collection). The GET attribute submits the information by passing the parameters in the query string. Each parameter/value pair is separated by an ampersand, as shown in the following URL.
GetUsers.asp?FirstName=Bill&LastName=Smith
This URL will pass the FirstName and LastName variables to GetUsers.asp. Setting the METHOD attribute to POST sends information as part of the HTTP header (so it can be extracted using the Forms collection of the server Request object). POST adds the variables from your form to the header of your request. The POST method is more robust than GET. It allows more data to be sent because passing data in the query string imposes length restrictions while POST has essentially no length restrictions. If you knew the parameters that the ASP page was expecting, you could avoid the form and submit the values directly on the query string. This is how the solutions in this article work. Submitting information to the Web in this fashion is much like calling a standard function in Visual Basic®. When you call a function in Visual Basic, you specify the function name, which serves the same role as the ASP file does here. When calling a function, you usually pass parameters to the function. In ASP code, the parameters are passed in the query string. Functions return values, and in ASP, return values are the data that is passed back from your ASP file. If you are familiar with programming with Active Server Pages, you'll find the ASP pages shown in this article to be even easier than those you might find in regular ASP development. You normally need to create a form before you write the ASP code that allows the user to interact with the application. In my examples, the ASP file contains no HTML code. The pages are requested, then do an insert on a database, adding the information passed from the client. For each of these applications, I have IIS, Microsoft SQL Server™, and the client application running on the same computer. If you have SQL Server running on a different computer, you will need to change the connection string in the ASP page. If your client application is not on the same computer as your Web server, you will need to change the URL in the application to match the name of the server where IIS is running.
Monitoring Usage with HTTP The first example in the code download includes a simple Visual Basic-based application, a listening ASP file, and uses a back-end data store (in this case a SQL Server table). The Visual Basic-based application makes a request to the ASP page, which in turn adds a record to the SQL Server database every time the client application is run. The ASP page will collect the user's e-mail address, the application name, the application version, the client's local time, and the client's IP address. By monitoring the client's IP address, you can create detailed reports to see which sites and which users use your application most. (Of course, it's good form to let your users know you're going to collect information about them before doing so.) The only form in the application is shown in Figure 1. This is a simple form like one that might be displayed at the start of an application that requires registration. The form has a textbox for the user's e-mail address. Once the user clicks the OK button, the information will be sent to the Web server.
.gif) Figure 1 Input Form
The code in Figure 2 shows the actual Visual Basic implementation. You can see that this code first checks to see if the user has entered any text in the e-mail address. If the user has entered some text, the URL is built and the data the user has provided is collected and sent to the server. The project also includes a standard .bas module, which contains the WinInet functions. This .bas module only contains a few of the functions included in WinInet.dll: a call to open a connection to the Internet, request a Web page, and free the resources. The module allows API calls to be made from within Visual Basic. Your application will be identified as scUserAgent in the Web server's log files. The same .bas module is also used in my second example, as you will see later in this article. The click event uses the InternetOpen and InternetOpenURL functions to interact with the Web server. InternetOpen allows you to specify the name of the application or entity calling the Internet functions. This name is used as the user agent in the HTTP protocol. You can also specify the name of the proxy servers to use if proxy access is necessary. InternetOpenURL actually makes the request to the server. Near the end of the routine a call is made to InternetCloseHandle to free the resources in use by InternetOpen and InternetOpenURL. Additionally, you should check the return values of each of the functions to see if they were successful. The client application requests an ASP page, Listen.asp, located in the virtual directory named Track. For this example, the folder contains only one ASP file. The code for Listen.asp can be found in Figure 3. The source code for the ASP page builds a SQL statement based on the values passed in the query string. I have included the function CheckString, which pads the SQL string delimiter so that the SQL statement won't fail if the user enters a single quote in their e-mail address or in any other field. As an alternative you could use a SQL stored procedure to insert the data. The ASP page also uses a server variable, Request.ServerVariables("REMOTE_ADDR"), for retrieving the IP address of the client computer. An ADO Connection object is created and used to execute the SQL statement. After the data is added to the database, the connection is closed and the object is set to Nothing. Finally, I created a database and table to store the incoming information. I called the database Usage and created the table named UsageLog. UsageLog contains seven fields, including important information like the client's IP address and e-mail address. Running the client application adds a new record to the table that contains both the database's local time and the client's local time. This sample application has shown the basics of implementing communications using HTTP. The following one will show how to trace application errors using HTTP in a similar manner. Error Trapping with HTTP My second example adds a record to a log table each time the monitored client application generates an error. Information logged includes the application name, application version, module name, method name, error message, user name, and severity of the error. The request that is made to the server is similar to the one in the previous example so I did not include it in the article, but you can find it in the download. You could extend this example and log details such as DLL versions, system resources, and system parameters, which would all help debug an application error.
.gif) Figure 4 Order Entry Form
Again, this application uses a Visual Basic-based EXE, a listening ASP page, and SQL Server. I also created a virtual directory named OrderEntry on the Web server for the ASP page. The form for this example is shown in Figure 4. The code for the AddLineItem click event looks like this:
Private Sub cmdAddLineItem_Click()
On Error GoTo ErrorHandler
'Code to add item
Debug.Print 1 / 0
Exit Sub
ErrorHandler:
LogError "frmOrderEntry", "cmdAddLineItem_Click", "Low", _
Err.Number & "-" & Err.Description
MsgBox "There has been an error in the application. " & _
"Technical support has been notified!", vbExclamation, _
"Add Line Item Problem"
End Sub
This code generates an error, which causes the error handler to execute. The error handler calls the LogError subroutine, which takes care of logging the details of the error and sending them to the remote server. LogError also retrieves the user name for the current user, which will be passed as part of the details of the error. After the error has been logged, the user is prompted that an error has occurred. The listening ASP builds the SQL statement based on the query string. It also has a Select Case statement for actions to be taken depending on the severity of the error, as shown in these lines from listen.asp in the second example (see the code download).
<%
Select Case Request("Severity")
Case "Low"
'Send an email to your helpdesk
Case "Mild"
'Send and email to the appropriate developer
Case "Major"
'Page and email appropriate developer
End Select
%>
This is an example of basic routing and could include more detail based on the module in which the error occurred. If an error occurred in a module or method that you created, you would receive the e-mail. The database includes nine fields tracking valuable data such as the error description, date and time, and the severity of the issue. All of the fields are of type varchar with the exception of the identity column and the local date time field. The code in Listen.asp allows for a great deal of flexibility. I included a simple Select Case statement, which could be extended to send e-mail to the developer using Collaboration Data Objects for Windows NT® Server (CDONTS). You could also add the data to SQL Server and create simple Web pages that produce reports for developers and helpdesk staff. While this code is helpful in tracking errors, you may only want to use it in critical areas of your application. A common error could quickly fill your database with information that would not be very helpful. Implementing some type of two-way communication with the listening ASP page could extend the application further. For example, if you were receiving the same error in the logs from a given user, you could edit the ASP file to watch for that user, and the next time he logs on, you could request more information from the client. This type of functionality would have to be coded into the client, but could be accomplished using the WinInet functions.
Using the Right WinInet Functions As mentioned earlier, the examples in this article use the WinInet function InternetOpenURL. This function essentially combines the functionality of InternetConnect, HttpOpenRequest, and HttpSendRequest. But sometimes you may need to use these three functions instead of InternetOpenURL. When using the three API calls, you need to do more work. First, the InternetConnect function requires just the name of the server; no protocol information (in other words, no http://). The protocol is specified as another parameter for InternetConnect. You also should not include information such as the path to the resource you need. This type of information should be included in the HttpOpenRequest call. With InternetOpenURL, the name and protocol information is parsed out for you. After issuing a call to InternetConnect, you will need to use HttpOpenRequest and include the path to the resource that you want. Finally, you will have to use HttpSendRequest to send your request to the server. You could use these functions if you need to Post information to the server or require authentication to access the Web site. In each of these cases, whether you use InternetOpenURL or the three separate API calls, you will use both InternetOpen and InternetCloseHandle for opening and closing your Internet connection. An implementation using the three API calls can be downloaded from http://msdn.microsoft.com/downloads/samples/internet/default.asp?url=/downloads/samples/Internet/networking/vbhttp/default.asp. Best Practices A few years ago I created the first version of this type of application. It was exciting to be able to communicate using the Internet. However, my first implementation had several downfalls. The following are some lessons I learned that you should pay attention to when you are implementing your own HTTP communication solution. Use existing technology In this article, I have shown you how easy it is to use an existing protocol. When I first created my application, I created my own protocol. This meant I had to create my own listening server, which never worked as well as IIS when the load started to increase and scalability became an issue. Use DNS Instead of hardcoding an IP address in your application, use a domain name. This allows you to switch hosting companies or change an IP address without affecting the availability of your listening application. Don't depend on an Internet connection Test your application so that it works with and without an Internet connection. The best route is to just unplug your Ethernet or modem cable or remove TCP/IP from your computer. Store foreign dates and times as a string If you are going to store the user's date and time (using the Visual Basic Now function in your client application), store it as a string in the database. In the past, dates and times from foreign countries have made my SQL statements fail if the database was expecting a date/time data type. It would be better to accept the data and convert it later than to fail on an insert and never receive the data at all. Use a browser for debugging Once your database is created, you will want to set up your ASP page. Instead of trying to use the client application to test your ASP, just use a browser. This will allow you to display the SQL statement in the browser to ensure it is formatted correctly. Additionally, you will be able to test different scenarios quickly without having to launch the client application. Use WinInet I used WinInet because it is very well-documented (see the related articles and background information for this article). It provides a great deal of flexibility and does not incur the overhead of an ActiveX control. There are other features available when using WinInet, such as Secure Sockets Layer and the ability to communicate through a proxy server.
Conclusion You can use HTTP to communicate using the Internet even if you are not developing browser-based solutions. There are many benefits to using existing technology to create new functionality. WinInet provides several ways to accomplish communication using the HTTP protocol. Using IIS, HTTP, ASP, and SQL Server also allows a great deal of functionality, reliability, and scalability.
| For related articles see: Simulating a Post Request For background information see: http://support.microsoft.com/default.aspx?scid=kb;en-us;q168151 http://support.microsoft.com/default.aspx?scid=kb;en-us;q195650
| Todd Meister is a Web developer specializing in Microsoft technologies. Reach him at tmeister@tmeister.com. From the June 2001 issue of MSDN Magazine. |
|
|