WinHttpReadData |
Description
The WinHttpReadData function reads data from a handle opened by the WinHttpOpenRequest function.
C/C++ Syntax
PowerBASIC Syntax
Parameters
hRequest
[in] Valid HINTERNET handle returned from a previous call to WinHttpOpenRequest. WinHttpReceiveResponse or WinHttpQueryDataAvailable must have been called for this handle and must have completed before WinHttpReadData is called. Although calling WinHttpReadData immediately after completion of WinHttpReceiveResponse avoids the expense of a buffer copy, doing so requires that the application use a fixed-length buffer for reading.
lpBuffer
[out] Pointer to a buffer that receives the data read. Make sure that this buffer remains valid until WinHttpReadData has completed.
dwNumberOfBytesRead
[in] Unsigned long integer value that contains the number of bytes to read.
lpdwNumberOfBytesRead
[out] Pointer to an unsigned long integer variable that receives the number of bytes read. WinHttpReadData sets this value to zero before doing any work or error checking. When using WinHTTP asynchronously, always set this parameter to NULL and retrieve the information in the callback function; not doing so can cause a memory fault.
Return Value
Returns a valid session handle if successful, or NULL otherwise. To retrieve extended error information, call GetLastError. Among the error codes returned are:
Remarks
Even when WinHTTP is used in asynchronous mode (that is, when WINHTTP_FLAG_ASYNC has been set in WinHttpOpen), this function can operate either synchronously or asynchronously. If this function returns FALSE, this function failed and you can call GetLastError to get extended error information. If this function returns TRUE, use the WINHTTP_CALLBACK_STATUS_READ_COMPLETE completion to determine whether this function was successful and the value of the parameters. The WINHTTP_CALLBACK_STATUS_REQUEST_ERROR completion indicates that the operation completed asynchronously, but failed.
Warning When WinHTTP is used in asynchronous mode, always set the lpdwNumberOfBytesRead parameter to NULL and retrieve the bytes read in the callback function; otherwise, a memory fault can occur.
When the read buffer is very small, WinHttpReadData might complete synchronously. If the WINHTTP_CALLBACK_STATUS_READ_COMPLETE completion triggers another call to WinHttpReadData, the situation can result in a stack overflow. In general, it is best to use a read buffer that is comparable in size, or larger than the internal read buffer used by WinHTTP, which is 8 KB.
If you are using WinHttpReadData synchronously, and the return value is TRUE and the number of bytes read is zero, the transfer has been completed and there are no more bytes to read on the handle. This is analogous to reaching end-of-file in a local file. If you are using the function asynchronously, the WINHTTP_CALLBACK_STATUS_READ_COMPLETE callback is called with the dwStatusInformationLength parameter set to zero when the end of a response is found.
Use the return value of WinHttpReadData rather than that of WinHttpQueryDataAvailable to determine whether the end of the response has been reached, because an improperly terminated response can cause WinHttpQueryDataAvailable to continue to indicate that more data is available even when the response has been completely read.
The buffer pointed to by lpBuffer is not always filled by calls to the WinHttpReadData function; sufficient data might not have arrived from the server.
For HINTERNET handles created by the WinHttpOpenRequest function and sent by WinHttpSendRequest, a call to WinHttpReceiveResponse must be made on the handle before WinHttpReadData can be used.
Single byte characters retrieved with WinHttpReadData are not converted to multi-byte characters.
When the read buffer is very small, WinHttpReadData may complete synchronously, and if the WINHTTP_CALLBACK_STATUS_READ_COMPLETE completion then triggers another call to WinHttpReadData, a stack overflow can result. It is best to use a read buffer that is 8 Kilobytes or larger in size.
If sufficient data has not arrived from the server, WinHttpReadData does not entirely fill the buffer pointed to by lpBuffer. The buffer must be large enough at least to hold the HTTP headers on the first read, and when reading HTML encoded directory entries, it must be large enough to hold at least one complete entry.
If a status callback function has been installed by using WinHttpSetStatusCallback, then those of the following notifications that have been set in the dwNotificationFlags parameter of WinHttpSetStatusCallback indicate progress in checking for available data:
Example Code [PowerBASIC]
The following example shows how to use secure transaction semantics to download a resource from an Secure Hypertext Transfer Protocol (HTTPS) server. The sample code initializes the WinHTTP application programming interface (API), selects a target HTTPS server, then opens and sends a request for this secure resource. WinHttpQueryDataAvailable is used with the request handle to determine how much data is available for download, then WinHttpReadData is used to read that data. This process repeats until the entire document has been retrieved and displayed.
#COMPILE EXE #DIM ALL #INCLUDE "WIN32API.INC" #INCLUDE "WINHTTP.INC"
FUNCTION PBMAIN () AS LONG
LOCAL dwSize AS DWORD LOCAL dwDownloaded AS DWORD LOCAL bResults AS LONG LOCAL hSession AS DWORD LOCAL hConnect AS DWORD LOCAL hRequest AS DWORD LOCAL strUserAgent AS STRING LOCAL strServerName AS STRING LOCAL strVerb AS STRING LOCAL strOutBuffer AS STRING
dwSize = 4 ' size of a DWORD
' Use WinHttpOpen to obtain a session handle. strUserAgent = UCODE$("A WinHTTP Example Program/1.0" & $NUL) hSession = WinHttpOpen(STRPTR(strUserAgent), _ %WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, _ %WINHTTP_NO_PROXY_NAME, _ %WINHTTP_NO_PROXY_BYPASS, _ 0)
' Specify an HTTP server. IF hSession THEN strServerName = UCODE$("www.microsoft.com" & $NUL) hConnect = WinHttpConnect(hSession, _ STRPTR(strServerName), _ %INTERNET_DEFAULT_HTTP_PORT, _ 0) END IF
' Create an HTTP Request handle. IF hConnect THEN strVerb = UCODE$("GET" & $NUL) hRequest = WinHttpOpenRequest(hConnect, _ STRPTR(strVerb), _ %NULL, _ %NULL, _ %WINHTTP_NO_REFERER, _ BYVAL %WINHTTP_DEFAULT_ACCEPT_TYPES, _ 0) END IF
' Send a Request. ' Note: The Microsoft C example uses WINHTTP_FLAG_SECURE for the last ' parameter, but I have changed it to 0 because, otherwise, it returns ' error 12175 (ERROR_WINHTTP_SECURE_FAILURE) IF hRequest THEN bResults = WinHttpSendRequest(hRequest, _ %WINHTTP_NO_ADDITIONAL_HEADERS, _ 0, _ %WINHTTP_NO_REQUEST_DATA, _ 0, _ 0, _ 0) END IF
' End the request. IF bResults THEN bResults = WinHttpReceiveResponse(hRequest, %NULL) END IF
' Keep checking for data until there is nothing left. IF bResults THEN DO ' Check for available data. dwSize = 0 IF ISFALSE WinHttpQueryDataAvailable(hRequest, dwSize) THEN PRINT "Error " GetLastError " in WinHttpQueryDataAvailable." EXIT DO ELSE ' Allocate space for the buffer. strOutBuffer = STRING$(dwSize + 1, $NUL) ' Read the data. IF ISFALSE WinHttpReadData(hRequest, STRPTR(strOutBuffer), _ dwSize, dwDownloaded) THEN PRINT "Error " GetLastError " in WinHttpReadData." ELSE STDOUT strOutBuffer END IF END IF LOOP WHILE dwSize > 0 END IF
' Report any errors. IF ISFALSE bResults THEN PRINT "Error " GetLastError " has occurred." END IF
' Close open handles. IF hRequest THEN WinHttpCloseHandle(hRequest) IF hConnect THEN WinHttpCloseHandle(hConnect) IF hSession THEN WinHttpCloseHandle(hSession)
WAITKEY$
END FUNCTION
Example Code [C++]
DWORD dwSize = 0; DWORD dwDownloaded = 0; LPSTR pszOutBuffer; BOOL bResults = FALSE; HINTERNET hSession = NULL, hConnect = NULL, hRequest = NULL;
// Use WinHttpOpen to obtain a session handle. hSession = WinHttpOpen( L"WinHTTP Example/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
// Specify an HTTP server. if (hSession) hConnect = WinHttpConnect( hSession, L"www.microsoft.com", INTERNET_DEFAULT_HTTPS_PORT, 0);
// Create an HTTP request handle. if (hConnect) hRequest = WinHttpOpenRequest( hConnect, L"GET", NULL, NULL, WINHTTP_NO_REFERER, WINHTTP_DEFAULT_ACCEPT_TYPES, WINHTTP_FLAG_SECURE);
// Send a request. if (hRequest) bResults = WinHttpSendRequest( hRequest, WINHTTP_NO_ADDITIONAL_HEADERS, 0, WINHTTP_NO_REQUEST_DATA, 0, 0, 0);
// End the request. if (bResults) bResults = WinHttpReceiveResponse( hRequest, NULL);
// Keep checking for data until there is nothing left. if (bResults) do {
// Check for available data. dwSize = 0; if (!WinHttpQueryDataAvailable( hRequest, &dwSize)) printf( "Error %u in WinHttpQueryDataAvailable.\n", GetLastError());
// Allocate space for the buffer. pszOutBuffer = new char[dwSize+1]; if (!pszOutBuffer) { printf("Out of memory\n"); dwSize=0; } else { // Read the Data. ZeroMemory(pszOutBuffer, dwSize+1);
if (!WinHttpReadData( hRequest, (LPVOID)pszOutBuffer, dwSize, &dwDownloaded)) printf( "Error %u in WinHttpReadData.\n", GetLastError()); else printf("%s", pszOutBuffer);
// Free the memory allocated to the buffer. delete [] pszOutBuffer; }
} while (dwSize>0);
// Report any errors. if (!bResults) printf("Error %d has occurred.\n",GetLastError());
// Close any open handles. if (hRequest) WinHttpCloseHandle(hRequest); if (hConnect) WinHttpCloseHandle(hConnect); if (hSession) WinHttpCloseHandle(hSession);
|