Condividi tramite


Funzioni comuni (Windows Internet)

I diversi protocolli Internet (ad esempio ftp e http) usano diverse funzioni WinINet per gestire le informazioni su Internet. Queste funzioni comuni gestiscono le loro attività in modo coerente, indipendentemente dal protocollo specifico a cui vengono applicate. Le applicazioni possono usare queste funzioni per creare funzioni per utilizzo generico che gestiscono le attività tra i diversi protocolli , ad esempio la lettura di file per ftp e http.

Le funzioni comuni gestiscono le attività seguenti:

Uso di funzioni comuni

Nella tabella seguente sono elencate le funzioni comuni incluse nelle funzioni WinINet. Le funzioni comuni possono essere usate su diversi tipi di handle HINTERNET o possono essere usati durante diversi tipi di sessioni.

Funzione Descrizione
InternetFindNextFile Continua l'enumerazione file o la ricerca. Richiede un handle creato dalla funzione FtpFindFirstFile o InternetOpenUrl .
InternetLockRequestFile Consente all'utente di inserire un blocco nel file usato. Questa funzione richiede un handle restituito dalla funzione FtpOpenFile, HttpOpenRequest o InternetOpenUrl .
InternetQueryDataAvailable Recupera la quantità di dati disponibili. Richiede un handle creato dalla funzione FtpOpenFile o HttpOpenRequest .
InternetQueryOption Recupera l'impostazione di un'opzione Internet.
InternetReadFile Legge i dati DELL'URL. Richiede un handle creato dalla funzione InternetOpenUrl, FtpOpenFile o HttpOpenRequest.
InternetSetFilePointer Imposta la posizione per la lettura successiva in un file. Richiede un handle creato da InternetOpenUrl (solo in un URL HTTP) o un handle creato da HttpOpenRequest usando il verbo HTTP GET.
Internetsetoption Imposta un'opzione Internet.
InternetSetStatusCallback Imposta una funzione di callback che riceve informazioni sullo stato. Assegna una funzione di callback all'handle HINTERNET designato e a tutti gli handle derivati.
InternetUnlockRequestFile Sblocca un file bloccato usando la funzione InternetLockRequestFile .

 

La lettura dei file, la ricerca del file successivo, la modifica delle opzioni e la configurazione delle operazioni asincrone sono comuni alle funzioni che supportano diversi protocolli e tipi di handle JSONNET .

Lettura di file

La funzione InternetReadFile viene usata per scaricare le risorse da un handle HINTERNET restituito dalla funzione InternetOpenUrl, FtpOpenFile o HttpOpenRequest .

InternetReadFile accetta una variabile puntatore void che contiene l'indirizzo di un buffer e un puntatore a una variabile contenente la lunghezza del buffer. La funzione restituisce i dati nel buffer e la quantità di dati scaricati nel buffer.

Le funzioni WinINet forniscono due tecniche per scaricare un'intera risorsa:

InternetQueryDataAvailable accetta l'handle HINTERNET creato da InternetOpenUrl, FtpOpenFile o HttpOpenRequest (dopo che HttpSendRequest è stato chiamato nell'handle) e restituisce il numero di byte disponibili. L'applicazione deve allocare un buffer uguale al numero di byte disponibili, più 1 per il carattere Null terminante e usare tale buffer con InternetReadFile. Questo metodo non funziona sempre perché InternetQueryDataAvailable controlla le dimensioni del file elencate nell'intestazione e non il file effettivo. Le informazioni nel file di intestazione potrebbero essere obsolete o il file di intestazione potrebbe essere mancante, poiché non è attualmente necessario in tutti gli standard.

Nell'esempio seguente viene letto il contenuto della risorsa a cui si accede dall'handle hResource e visualizzato nella casella di modifica indicato da intCtrlID.

int WINAPI Dumper(HWND hX, int intCtrlID, HINTERNET hResource)
{
    LPTSTR    lpszData;           // buffer for the data
    DWORD     dwSize;             // size of the data available
    DWORD     dwDownloaded;       // size of the downloaded data
    DWORD     dwSizeSum=0;        // size of the data in the text box
    LPTSTR    lpszHolding;        // buffer to merge the text box 
                                  // data and buffer

    // Set the cursor to an hourglass.
    SetCursor(LoadCursor(NULL,IDC_WAIT));

    // This loop handles reading the data.  
    do
    {
        // The call to InternetQueryDataAvailable determines the
        // amount of data available to download.
        if (!InternetQueryDataAvailable(hResource,&dwSize,0,0))
        {
            ErrorOut(hX,GetLastError(),TEXT("InternetReadFile"));
            SetCursor(LoadCursor(NULL,IDC_ARROW));
            return FALSE;
        }
        else
        {    
            // Allocate a buffer of the size returned by
            // InternetQueryDataAvailable.
            lpszData = new TCHAR[dwSize+1];

            // Read the data from the HINTERNET handle.
            if(!InternetReadFile(hResource,(LPVOID)lpszData,
                                 dwSize,&dwDownloaded))
            {
                ErrorOut(hX,GetLastError(),TEXT("InternetReadFile"));
                delete[] lpszData;
                break;
            }
            else
            {
                // Add a null terminator to the end of the 
                // data buffer.
                lpszData[dwDownloaded]='\0';

                // Allocate the holding buffer.
                lpszHolding = new TCHAR[dwSizeSum + dwDownloaded + 1];
                    
                // Check if there has been any data written to 
                // the text box.
                if (dwSizeSum != 0)
                {
                    // Retrieve the data stored in the text 
                    // box, if any.
                    GetDlgItemText(hX,intCtrlID,
                                   (LPTSTR)lpszHolding, 
                                   dwSizeSum);
                         
                    // Add a null terminator at the end of 
                    // the text box data.
                    lpszHolding[dwSizeSum]='\0';
                }
                else
                {
                    // Make the holding buffer an empty string. 
                    lpszHolding[0]='\0';
                }

                size_t cchDest = dwSizeSum + dwDownloaded + 
                                 dwDownloaded + 1;
                LPTSTR pszDestEnd;
                size_t cchRemaining;

                // Add the new data to the holding buffer.
                HRESULT hr = StringCchCatEx(lpszHolding, cchDest, 
                                            lpszData, &pszDestEnd, 
                                            &cchRemaining, 
                                            STRSAFE_NO_TRUNCATION);
                if(SUCCEEDED(hr))
                {
                    // Write the holding buffer to the text box.
                    SetDlgItemText(hX,intCtrlID,(LPTSTR)lpszHolding);

                    // Delete the two buffers.
                    delete[] lpszHolding;
                    delete[] lpszData;

                    // Add the size of the downloaded data to 
                    // the text box data size.
                    dwSizeSum = dwSizeSum + dwDownloaded + 1;

                    // Check the size of the remaining data.  
                    // If it is zero, break.
                    if (dwDownloaded == 0)
                    {
                        break;
                    }                    
                    else
                    {
                        //  Insert error handling code here.
                    }
                }
            }
        }
    }
    while(TRUE);

    // Close the HINTERNET handle.
    InternetCloseHandle(hResource);

    // Set the cursor back to an arrow.
    SetCursor(LoadCursor(NULL,IDC_ARROW));

    // Return.
    return TRUE;
}

InternetReadFile restituisce zero byte di lettura e viene completato correttamente quando tutti i dati disponibili sono stati letti. Ciò consente a un'applicazione di usare InternetReadFile in un ciclo per scaricare i dati e uscire quando restituisce zero byte letti e completati correttamente.

L'esempio seguente legge la risorsa da Internet e visualizza la risorsa nella casella di modifica indicata da intCtrlID. L'handle HINTERNET , hInternet, è stato restituito da InternetOpenUrl, FtpOpenFile o HttpOpenRequest (dopo essere stato inviato da HttpSendRequest).

int WINAPI Dump(HWND hX, int intCtrlID, HINTERNET hResource)
{
     DWORD dwSize = 0;
     LPTSTR lpszData;
     LPTSTR lpszOutPut;
     LPTSTR lpszHolding = TEXT("");
     int nCounter = 1;
     int nBufferSize = 0;
     DWORD BigSize = 8000;

     // Set the cursor to an hourglass.
     SetCursor(LoadCursor(NULL,IDC_WAIT));

     // Begin the loop that reads the data.
     do
     {
          // Allocate the buffer.
          lpszData =new TCHAR[BigSize+1];

          // Read the data.
          if(!InternetReadFile(hResource,
                              (LPVOID)lpszData,
                              BigSize,&dwSize))
          {
               ErrorOut(hX,GetLastError(),TEXT("InternetReadFile"));
               delete []lpszData;
               break;
          }
          else
          {
               // Add a null terminator to the end of the buffer.
               lpszData[dwSize]='\0';

               // Check if all of the data has been read.  This should
               // never get called on the first time through the loop.
               if (dwSize == 0)
               {
                    // Write the final data to the text box.
                    SetDlgItemText(hX,intCtrlID,lpszHolding);

                    // Delete the existing buffers.
                    delete [] lpszData;
                    delete [] lpszHolding;
                    break;
               }

               // Determine the buffer size to hold the new data and
               // the data already written to the text box (if any).
               nBufferSize = (nCounter*BigSize)+1;

               // Increment the number of buffers read.
               nCounter++;               

               // Allocate the output buffer.
               lpszOutPut = new TCHAR[nBufferSize];

               // Make sure the buffer is not the initial buffer.
               if(nBufferSize != int(BigSize+1))
               {
                    // Copy the data in the holding buffer.
                    StringCchCopy(lpszOutPut,nBufferSize,lpszHolding);
                    // Add error handling code here.

                    // Concatenate the new buffer with the 
                    // output buffer.
                    StringCchCat(lpszOutPut, nBufferSize, lpszData);
                    // Add error handling code here.
     
                    // Delete the holding buffer.
                    delete [] lpszHolding;
               }
               else
               {
                    // Copy the data buffer.
                    StringCchCopy(lpszOutPut, nBufferSize, lpszData);
                    // Add error handling code here.
               }

               // Allocate a holding buffer.
               lpszHolding = new TCHAR[nBufferSize]; 

               // Copy the output buffer into the holding buffer.
               memcpy(lpszHolding,lpszOutPut,nBufferSize);

               // Delete the other buffers.
               delete [] lpszData;
               delete [] lpszOutPut;

          }

     }
     while (TRUE);

     // Close the HINTERNET handle.
     InternetCloseHandle(hResource);

     // Set the cursor back to an arrow.
     SetCursor(LoadCursor(NULL,IDC_ARROW));

     // Return.
     return TRUE;
}

Ricerca del file successivo

La funzione InternetFindNextFile viene usata per trovare il file successivo in una ricerca di file usando i parametri di ricerca e l'handle JSONNET da FtpFindFirstFile o InternetOpenUrl.

Per completare una ricerca di file, continuare a chiamare InternetFindNextFile usando l'handle JSONNET restituito da FtpFindFirstFile o InternetOpenUrl fino a quando la funzione non riesce con il messaggio di errore esteso ERROR_NO_MORE_FILES. Per ottenere le informazioni sull'errore estese, chiamare la funzione GetLastError .

Nell'esempio seguente viene visualizzato il contenuto di una directory FTP nella casella di riepilogo indicata da lstDirectory. L'handle HINTERNET , hConnect, è un handle restituito dalla funzione InternetConnect dopo aver stabilito una sessione FTP.

bool WINAPI DisplayDir( HWND hX, 
                        int lstDirectory, 
                        HINTERNET hConnect, 
                        DWORD dwFlag )
{
     WIN32_FIND_DATA pDirInfo;
     HINTERNET hDir;
     TCHAR DirList[MAX_PATH];

     // Set the cursor to an hourglass.
     SetCursor(LoadCursor(NULL,IDC_WAIT));

     // Reset the list box.
     SendDlgItemMessage(hX, lstDirectory,LB_RESETCONTENT,0,0);

     // Find the first file.
     hDir = FtpFindFirstFile (hConnect, TEXT ("*.*"), 
                              &pDirInfo, dwFlag, 0);
     if (!hDir)                                     
     {
          // Check if the error was because there were no files.
          if (GetLastError()  == ERROR_NO_MORE_FILES) 
          {
               // Alert user.
               MessageBox(hX, TEXT("There are no files here!!!"), 
                          TEXT("Display Dir"), MB_OK);

               // Close the HINTERNET handle.
               InternetCloseHandle(hDir);

               // Set the cursor back to an arrow.
               SetCursor(LoadCursor(NULL,IDC_ARROW));

               // Return.
               return TRUE;
          }
          else 
          {
               // Call error handler.
               ErrorOut (hX, GetLastError (), TEXT("FindFirst error: "));

               // Close the HINTERNET handle.
               InternetCloseHandle(hDir);

               // Set the cursor back to an arrow.
               SetCursor(LoadCursor(NULL,IDC_ARROW));

               // Return.
               return FALSE;
          }
     }
     else
     {
          // Write the file name to a string.
          StringCchPrintf(DirList, MAX_PATH, pDirInfo.cFileName);

          // Check the type of file.
          if (pDirInfo.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
          {
               // Add <DIR> to indicate that this is 
               // a directory to the user.
               StringCchCat(DirList, MAX_PATH, TEXT(" <DIR> "));
               // Add error handling code here.
          }
       
          // Add the file name (or directory) to the list box.
          SendDlgItemMessage(hX, lstDirectory, LB_ADDSTRING,
                             0, (LPARAM)DirList);
     }
     do
     {
          // Find the next file.
          if (!InternetFindNextFile (hDir, &pDirInfo))
          {
               // Check if there are no more files left. 
               if ( GetLastError() == ERROR_NO_MORE_FILES ) 
               {
                    // Close the HINTERNET handle.
                    InternetCloseHandle(hDir);

                    // Set the cursor back to an arrow.
                    SetCursor(LoadCursor(NULL,IDC_ARROW));

                    // Return.
                    return TRUE;
               }
               else
               {   
                    // Handle the error.
                    ErrorOut (hX, GetLastError(), 
                              TEXT("InternetFindNextFile"));

                    // Close the HINTERNET handle.
                    InternetCloseHandle(hDir);

                    // Set the cursor back to an arrow.
                    SetCursor(LoadCursor(NULL,IDC_ARROW));

                    // Return.
                    return FALSE;
               }
           }
           else
           {
               // Write the file name to a string.
               StringCchPrintf(DirList, MAX_PATH, pDirInfo.cFileName);

               // Check the type of file.
               if(pDirInfo.dwFileAttributes==FILE_ATTRIBUTE_DIRECTORY)
               {
                    // Add <DIR> to indicate that this is a 
                    // directory to the user.
                    StringCchCat(DirList, MAX_PATH, TEXT(" <DIR> "));
                    // Add error handling code here.
               }
     
               // Add the file name (or directory) to the list box.
               SendDlgItemMessage(hX, lstDirectory, LB_ADDSTRING,
                                  0, (LPARAM)DirList);
           }
     }
     while ( TRUE);
     
}

Opzioni di modifica

InternetSetOption e InternetQueryOption vengono usati per modificare le opzioni WinINet.

InternetSetOption accetta una variabile che indica l'opzione da impostare, un buffer per contenere l'impostazione dell'opzione e un puntatore che contiene l'indirizzo della variabile che contiene la lunghezza del buffer.

InternetQueryOption accetta una variabile che indica l'opzione per recuperare, un buffer per contenere l'impostazione dell'opzione e un puntatore che contiene l'indirizzo della variabile che contiene la lunghezza del buffer.

Configurazione di operazioni asincrone

Per impostazione predefinita, le funzioni WinINet operano in modo sincrono. Un'applicazione può richiedere un'operazione asincrona impostando il flag INTERNET_FLAG_ASYNC nella chiamata alla funzione InternetOpen . Tutte le chiamate future effettuate su handle derivati dall'handle restituito da InternetOpen vengono effettuate in modo asincrono.

La logica per l'operazione asincrona e sincrona consiste nell'consentire a un'applicazione a thread singolo di ottimizzare l'utilizzo della CPU senza dover attendere il completamento dell'I/O di rete. Pertanto, a seconda della richiesta, l'operazione potrebbe completare in modo sincrono o asincrono. L'applicazione deve controllare il codice restituito. Se una funzione restituisce FALSE o NULL e GetLastError restituisce ERROR_IO_PENDING, la richiesta è stata effettuata in modo asincrono e l'applicazione viene richiamata con INTERNET_STATUS_REQUEST_COMPLETE al termine della funzione.

Per iniziare l'operazione asincrona, l'applicazione deve impostare il flag di INTERNET_FLAG_ASYNC nella chiamata a InternetOpen. L'applicazione deve quindi registrare una funzione di callback valida usando InternetSetStatusCallback.

Dopo la registrazione di una funzione di callback per un handle, tutte le operazioni su tale handle possono generare indicazioni di stato, purché il valore di contesto specificato al momento della creazione dell'handle non fosse zero. Se si specifica un valore di contesto zero, un'operazione viene eseguita in modo sincrono, anche se INTERNET_FLAG_ASYNC è stata specificata in InternetOpen.

Le indicazioni sullo stato forniscono il feedback dell'applicazione sullo stato di avanzamento delle operazioni di rete, ad esempio la risoluzione di un nome host, la connessione a un server e la ricezione dei dati. Per un handle è possibile effettuare tre indicazioni di stato speciali:

  • INTERNET_STATUS_HANDLE_CLOSING è l'ultima indicazione di stato effettuata per un handle.
  • INTERNET_STATUS_HANDLE_CREATED indica quando viene inizialmente creato l'handle.
  • INTERNET_STATUS_REQUEST_COMPLETE indica che è stata completata un'operazione asincrona.

L'applicazione deve controllare la struttura INTERNET_ASYNC_RESULT per determinare se l'operazione ha avuto esito positivo o non riuscito dopo aver ricevuto un'indicazione di INTERNET_STATUS_REQUEST_COMPLETE .

L'esempio seguente mostra un esempio di funzione di callback e una chiamata a InternetSetStatusCallback per registrare la funzione come funzione di callback.

void CALLBACK InternetCallback(
    HINTERNET hInternet,
    DWORD_PTR dwcontext,
    DWORD dwInternetStatus,
    LPVOID lpvStatusInformation,
    DWORD dwStatusInformationLength
    )
{
    _tprintf(TEXT("%0xd %0xp %0xd %0xp %0xd\n"),
             hInternet,
             dwcontext,
             dwInternetStatus,
             lpvStatusInformation,
             dwStatusInformationLength);
};

INTERNET_STATUS_CALLBACK dwISC =
    InternetSetStatusCallback(hInternet, InternetCallback); 

Chiusura degli handle DI HINTERNET

Tutti gli handle HINTERNET possono essere chiusi usando la funzione InternetCloseHandle . Le applicazioni client devono chiudere tutti gli handle HINTERNET derivati dall'handle HINTERNET che stanno tentando di chiudere prima di chiamare InternetCloseHandle sull'handle.

Nell'esempio seguente viene illustrata la gerarchia di handle.

HINTERNET hRootHandle, hOpenUrlHandle;

hRootHandle = InternetOpen( TEXT("Example"), 
                            INTERNET_OPEN_TYPE_DIRECT, 
                            NULL, 
                            NULL, 0);

hOpenUrlHandle = InternetOpenUrl(hRootHandle, 
    TEXT("https://www.server.com/default.htm"), NULL, 0, 
    INTERNET_FLAG_RAW_DATA,0);

// Close the handle created by InternetOpenUrl so that the
// InternetOpen handle can be closed.
InternetCloseHandle(hOpenUrlHandle); 

// Close the handle created by InternetOpen.
InternetCloseHandle(hRootHandle);

Blocco e sblocco delle risorse

La funzione InternetLockRequestFile consente a un'applicazione di assicurarsi che la risorsa memorizzata nella cache associata all'handle DI HINTERNET passata non scompaia dalla cache. Se un altro download tenta di eseguire il commit di una risorsa con lo stesso URL del file bloccato, la cache evita di rimuovere il file eseguendo un'eliminazione sicura. Dopo che l'applicazione chiama la funzione InternetUnlockRequestFile , la cache viene concessa l'autorizzazione per eliminare il file.

Se il flag INTERNET_FLAG_NO_CACHE_WRITE o INTERNET_FLAG_DONT_CACHE è stato impostato, InternetLockRequestFile crea un file temporaneo con l'estensione TMP, a meno che l'handle non sia connesso a una risorsa https. Se la funzione accede a una risorsa https e INTERNET_FLAG_NO_CACHE_WRITE (o INTERNET_FLAG_DONT_CACHE) è stata impostata, InternetLockRequestFile ha esito negativo.

Nota

WinINet non supporta le implementazioni del server. Inoltre, non deve essere usato da un servizio. Per le implementazioni o i servizi server usano Microsoft Windows HTTP Services (WinHTTP).