So, you need to develop an application that will be able to send and receive some data over the Internet or an intranet from/to remote Web servers. This article set will help you figure out how to do it using WinInet for many common cases. This article will review the initial steps. Let’s say a couple of words regarding which language to use or mainly which environment to use: CF.NET or native C/C++ code. With all the enhancements that CF.NET SP2 has, it still experiences particular troubles with communications; for example, communications through proxy servers requiring NTLM authentication. Native code provides many more opportunities on this topic. Thus, when making your final decision, keep all this in mind. In this article, we will use both C++ and C# for code snippets.
Managing URLs
Prior to establishing any connection, your application should have a valid URL to connect to. WinInet provides a wide set of functions to deal with. First, there are a couple of calls to verify whether there is an opportunity to start communications:
DWORD InternetAttemptConnect(DWORD dwReserved); BOOL InternetCheckConnection(LPCSTR lpszUrl,DWORD dwFlags, DWORD dwReserved);
You can use them to be sure the device is connected to the network and the request may be executed.
Other useful API calls are:
- InternetGetConnectedState—retrieves the connected state of the local system
- InternetGetConnectedStateEx—retrieves the connected state of the specified Internet connection
They show the existing capabilities on a particular system. Via these functions, you may detect whether the system uses a proxy server to establish connection.
The next group of functions helps you deal with URLs. They are listed below:
- InternetCrackUrl
- InternetCreateUrl
- InternetCombineUrl
- InternetCanonicalizeUrl
You may use the above calls to manipulate by URLs. Applications can easily build a target URL from blocks, break the URL into its base and relative parts, replace unsafe characters in the URL, and so forth. Actually, all this is intuitive enough, so we will not dig in too much, just a simple code snippet for an example:
TCHAR szServer[1024]; TCHAR szPath[1024]; URL_COMPONENTS crackedURL; memset(&crackedURL, 0, sizeof(crackedURL)); crackedURL.dwStructSize = sizeof(crackedURL); crackedURL.lpszHostName = szServer; crackedURL.dwHostNameLength = 1024; crackedURL.lpszUrlPath = szPath; crackedURL.dwUrlPathLength = 1024; InternetCrackUrl (pszURL, 0, 0, &crackedURL);
As a result, crackedURL will contain a URL divided into base host address, relative path, port number, and so on. If you’re developing in C#, compact framework classes do such conversions inside, so you don’t need to worry about it in your code.
Initializing the Internet Library
The very first step in working with any library is its initialization. Before using any WinInet functions, your application should call the InternetOpen API to make all required initialization:
HINTERNET WINAPI InternetOpen( LPCTSTR lpszAgent, DWORD dwAccessType, LPCTSTR lpszProxy, LPCTSTR lpszProxyBypass, DWORD dwFlags );
You can specify any string as a lpszAgent value; for example, TEXT(“CeHttp”). This name then will be used as the user agent in HTTP. The dwAccessType parameter is usually equal to INTERNET_OPEN_TYPE_PRECONFIG; in other words, all data is taken from the Registry. In this case, you can leave the next two parameters zeroed. Alternatively, you can specify the desired proxy and proxy bypass list. Note here that an empty string as a proxy name is treated as a legal one, so set lpszProxy to NULL if you don’t need to connect via proxy servers. And finally, dwFlags is 0 or one of the following values:
- Make asynchronous requests only—INTERNET_FLAG_ASYNC
- No network requests at all—INTERNET_FLAG_FROM_CACHE or INTERNET_FLAG_OFFLINE
Thus, a typical initialization call may look like the following:
HINTERNET hOpen = InternetOpen (L"CeHttp", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
Making Simple Connections to Remote Hosts
Once WinInet is initialized, we’re ready to establish connections to the desired URLs. You have two main options:
- Establish the connection to the specified URL through InternetOpenUrl.
- Retrieve the session handle via InternetConnect and then use it to send requests.
In this section, we will discuss the first method—the InternetOpenUrl function. It is quite useful when you need to proceed with some simple operation; for example, to only download data file from a remote host. Thus, the code may look like:
void CWceHttpDlg::OnGo() { HINTERNET hOpen = InternetOpen (L"WceHttp", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0); if ( !hOpen ) { AfxMessageBox(L"Failed to open WinInet"); return; } HINTERNET hOpenUrl = InternetOpenUrl( hOpen,m_sURL, NULL,0, INTERNET_FLAG_PRAGMA_NOCACHE|INTERNET_FLAG_KEEP_CONNECTION, 0); if ( !hOpenUrl ) { DWORD dwErr = GetLastError(); //Handle error ................. AfxMessageBox(L"Failed to open WinInet"); InternetCloseHandle(hOpen); return; } char szBuffer[4096]; DWORD dwNumberOfBytesRead = 0; while ( InternetReadFile(hOpenUrl, szBuffer, 4096, &dwNumberOfBytesRead) && dwNumberOfBytesRead ) { // Do something with received block .................................... } InternetCloseHandle(hOpenUrl); InternetCloseHandle(hOpen); }
InternetOpenUrl internally establishes a connection to the remote host and returns a handle to the Internet session, which may be used later in all I/O operations; for example, InternetReadFile calls. After all, opened handles are released by InternetCloseHandle calls.