RANGE.C
// =========================================================================== 
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
// PARTICULAR PURPOSE. 
// 
// Copyright 1996 Microsoft Corporation.  All Rights Reserved. 
// =========================================================================== 
#include <windows.h> 
#include <urlmon.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include "range.h" 
 
DWORD g_dwThread; 
 
//============================================================================== 
void DumpBytes (PBYTE pBuf, DWORD cbBuf) 
{ 
    DWORD i; 
    for (i=0; i<cbBuf; i++) 
    { 
        switch(pBuf[i]) 
        { 
            case 10:  printf("[LF]"); break; 
            case 13:  printf("[CR]"); break; 
            default:  printf("%c", pBuf[i]); break; 
        } 
    } 
} 
 
//============================================================================== 
void PrintResultCode (HRESULT hr) 
{ 
#define CASEMSG(hr) case hr: printf(#hr); break; 
 
printf ("Done with result "); 
switch (hr) 
{ 
CASEMSG(S_OK) 
CASEMSG(S_FALSE) 
CASEMSG(E_FAIL) 
 
        CASEMSG(INET_E_INVALID_URL) 
CASEMSG(INET_E_NO_SESSION) 
CASEMSG(INET_E_CANNOT_CONNECT) 
CASEMSG(INET_E_RESOURCE_NOT_FOUND) 
CASEMSG(INET_E_OBJECT_NOT_FOUND) 
CASEMSG(INET_E_DATA_NOT_AVAILABLE) 
CASEMSG(INET_E_DOWNLOAD_FAILURE) 
CASEMSG(INET_E_AUTHENTICATION_REQUIRED) 
CASEMSG(INET_E_NO_VALID_MEDIA)   
CASEMSG(INET_E_CONNECTION_TIMEOUT) 
CASEMSG(INET_E_INVALID_REQUEST) 
CASEMSG(INET_E_UNKNOWN_PROTOCOL) 
CASEMSG(INET_E_SECURITY_PROBLEM) 
CASEMSG(INET_E_CANNOT_LOAD_DATA) 
CASEMSG(INET_E_CANNOT_INSTANTIATE_OBJECT) 
 
default: 
    printf ("0x%x", hr); 
} 
printf ("\n"); 
} 
 
//============================================================================== 
BOOL RequestCallback (PHTTP_REQUESTCB_PARAM pCBParam) 
{ 
    printf ("RequestCallback[%d] ", pCBParam->dwRequestCtx); 
 
    switch (pCBParam->CallbackType) 
    { 
        case REQUESTCB_STARTED: 
            printf ("Started\n"); 
            printf ("  Status: %d\n", pCBParam->dwResponseCode); 
            printf ("  Content-Length: %d\n", pCBParam->dwContentLength); 
            if (pCBParam->fdwRequestFlags & HTTP_REQUEST_ACCEPT_RANGES) 
                printf ("  Accept-Ranges: bytes\n"); 
            if (pCBParam->fdwRequestFlags & HTTP_REQUEST_FROM_CACHE) 
                printf ("  From Cache\n"); 
            return TRUE; 
 
        case REQUESTCB_DATA: 
 
    // Dump some bytes so we can verify them. 
    printf ("offset=%5d got %4d bytes:", 
        pCBParam->dwDataOffset, pCBParam->cbDataLength); 
    DumpBytes ((PBYTE) pCBParam->lpDataBuffer, min(pCBParam->cbDataLength, 15)); 
    printf ("\n"); 
    return TRUE; 
 
        case REQUESTCB_DONE: 
            PrintResultCode (pCBParam->hrRequest); 
            // Let the console app thread exit the message loop. 
            PostThreadMessage (g_dwThread, WM_QUIT, 0, 0); 
            return TRUE; 
} 
} 
 
//============================================================================== 
int __cdecl main (int argc, char *argv[]) 
{ 
    MSG msg; 
    HTTP_REQUEST_PARAM Param; 
 
    SYSTEMTIME st; 
    PSTR pszUrl; 
    HTTP_REQUEST_RANGE ranges[10]; 
    DWORD cRanges; 
 
    // Check usage. 
    if (argc<2 || argc%2 || argc>(2*(sizeof(ranges))/sizeof(ranges[0]))) 
    { 
        fprintf (stderr, "Usage:   range <http-url> [<offset1> <size1>]  [<offset2> <size2>]  [<offset3> <size3>]  ...\n"); 
        fprintf (stderr, "Example: range http://www.microsoft.com 2 5 10 52 20 4\n"); 
        exit (1); 
    } 
 
    // Get URL and ranges from command line. 
    pszUrl = argv[1]; 
    cRanges = 0; 
    while (argc -= 2) 
    { 
if (argc <= 0) 
break; 
 
    ranges[cRanges].dwOffset = atoi(argv[2 * cRanges + 2]); 
    ranges[cRanges].dwSize   = atoi(argv[2 * cRanges + 3]); 
        cRanges++; 
    } 
 
    // Pass current time as unless-modified-since time. 
    GetSystemTime (&st); 
     
    // Save the thread ID so the we can post ourselves 
    // WM_QUIT from the callback without creating a window. 
    g_dwThread = GetCurrentThreadId(); 
 
    // Read range depends on URL monikers which depend on COM. 
    if (FAILED(CoInitialize(NULL))) 
        exit (1); 
     
    // Initiate the read range request. 
    ZeroMemory (&Param, sizeof(Param)); 
    Param.cbStruct     = sizeof(Param); 
    Param.pszUrl       = pszUrl; 
    Param.pfnRequestCB = RequestCallback; 
    Param.dwRequestCtx = 15; 
    Param.pRanges      = &ranges[0]; 
    Param.cRanges      = cRanges; 
    Param.pstUnlessModifiedSince = &st; 
       
    if (HttpReadRequest (&Param)) 
    { 
        // Must enter a message loop for the binding to progress. 
        while (GetMessage (&msg, NULL, 0, 0)) 
        { 
            TranslateMessage (&msg); 
            DispatchMessage (&msg); 
        } 
    } 
 
    CoUninitialize(); 
    return 1; 
}