HOWTO: Control Connection Timeout Value by Creating Second Thread

ID: Q224318


The information in this article applies to:


SUMMARY

This acticle shows a workaround to the InternetSetOption API bug on setting timeout values by creating a second thread. For information about the bug, please see the following article in the Microsoft Knowledge Base:

Q176420 InternetSetOption Does Not Set Timeout Values


MORE INFORMATION

The following sample code controls how long to wait while connecting to the FTP server in WinInet. It creates a worker thread to call the blocking WinInet APIs. If the connection takes longer time than the specified timeout value, the original thread will call InternetCloseHandle to release the blocking WinInet function. For HTTP communications the same idea applies. In the case of HTTP, the actual connection occurs in the call to HttpSendRequest.


#include <windows.h>
#include <wininet.h>
#include <iostream.h>

DWORD WINAPI WorkerFunction( LPVOID ); 
HINTERNET g_hOpen, g_hConnect;

typedef struct 
{
    CHAR* pHost;
    CHAR* pUser;
    CHAR* pPass;
} PARM;

void main()
{
    CHAR    szHost[] = "servername";
    CHAR    szUser[] = "username";
    CHAR    szPass[] = "password";
    CHAR    szLocalFile[] = "localfile";
    CHAR    szRemoteFile[] = "remotefile";
    DWORD   dwExitCode;
    DWORD   dwTimeout;
    PARM    threadParm;

    g_hOpen = 0;
    if ( !( g_hOpen = InternetOpen ( "FTP sample", 
                                     LOCAL_INTERNET_ACCESS, 
                                     NULL, 
                                     0, 
                                     0 ) ) )
    {         
        cerr << "Error on InternetOpen: " << GetLastError() << endl;
        return ;
    }

    // Create a worker thread 
    HANDLE   hThread; 
    DWORD    dwThreadID;
    threadParm.pHost = szHost;
    threadParm.pUser = szUser;
    threadParm.pPass = szPass;

    hThread = CreateThread(
                  NULL,            // Pointer to thread security attributes 
                  0,               // Initial thread stack size, in bytes 
                  WorkerFunction,  // Pointer to thread function 
                  &threadParm,     // The argument for the new thread
                  0,               // Creation flags 
                  &dwThreadID      // Pointer to returned thread identifier 
              );	

    // Wait for the call to InternetConnect in worker function to complete
    dwTimeout = 10000; // in milliseconds
    if ( WaitForSingleObject ( hThread, dwTimeout ) == WAIT_TIMEOUT )
    {
        cout << "Can not connect to server in " 
             << dwTimeout << " milliseconds" << endl;
        if ( g_hConnect )
            InternetCloseHandle ( g_hConnect );
        // Wait until the worker thread exits
        WaitForSingleObject ( hThread, INFINITE );
        cout << "Thread has exited" << endl;
        return ;
    }
	
    // The state of the specified object (thread) is signaled
    dwExitCode = 0;
    if ( !GetExitCodeThread( hThread, &dwExitCode ) )
    {
        cerr << "Error on GetExitCodeThread: " << GetLastError() << endl;
        return ;
    }

    CloseHandle (hThread);
    if ( dwExitCode )
    // Worker function failed
       return ;
	
    if ( !FtpGetFile ( g_hConnect, 
                       szRemoteFile,
                       szLocalFile,
                       FALSE,INTERNET_FLAG_RELOAD, 
                       FTP_TRANSFER_TYPE_ASCII,
                       0 ) )
    {
        cerr << "Error on FtpGetFile: " << GetLastError() << endl;
        return ;
    }

    if ( g_hConnect )
        InternetCloseHandle( g_hConnect );
    if ( g_hOpen )
        InternetCloseHandle( g_hOpen );

    return ;
}

/////////////////// WorkerFunction ////////////////////// 
DWORD WINAPI 
WorkerFunction(
    IN LPVOID vThreadParm
)
/*
Purpose:
    Call InternetConnect to establish a FTP session  
Arguments:
    vThreadParm - points to PARM passed to thread
Returns:
    returns 0  
*/ 
{
    PARM* pThreadParm;
    // Initialize local pointer to void pointer passed to thread
    pThreadParm = (PARM*)vThreadParm;
    g_hConnect = 0;
	
    if ( !( g_hConnect = InternetConnect (
                             g_hOpen, 
                             pThreadParm->pHost,
                             INTERNET_INVALID_PORT_NUMBER,
                             pThreadParm->pUser,
                             INTERNET_SERVICE_FTP, 
                             0,
                             0 ) ) )
    {
        cerr << "Error on InternetConnnect: " << GetLastError() << endl;
        return 1; // failure
    }
    
    return 0;  // success
} 

Additional query words:


Keywords          : kbIE400 kbIE401 kbIE401sp1 kbIE401sp2 kbIE500 
Version           : WINDOWS:4.0,4.01,4.01 SP1,4.01 SP2,5.0
Platform          : WINDOWS 
Issue type        : kbhowto 

Last Reviewed: May 20, 1999