Partager via


Fonctions courantes (Windows Internet)

Les différents protocoles Internet (tels que ftp et http) utilisent plusieurs des mêmes fonctions WinINet pour gérer les informations sur Internet. Ces fonctions courantes gèrent leurs tâches de manière cohérente, quel que soit le protocole particulier auquel elles sont appliquées. Les applications peuvent utiliser ces fonctions pour créer des fonctions à usage général qui gèrent des tâches sur les différents protocoles (par exemple, la lecture de fichiers pour ftp et http).

Les fonctions courantes gèrent les tâches suivantes :

Utilisation de fonctions communes

Le tableau suivant répertorie les fonctions courantes incluses dans les fonctions WinINet. Les fonctions courantes peuvent être utilisées sur différents types de handles HINTERNET ou peuvent être utilisées pendant différents types de sessions.

Fonction Description
InternetFindNextFile Poursuit l’énumération ou la recherche de fichiers. Nécessite un handle créé par la fonction FtpFindFirstFile ou InternetOpenUrl .
InternetLockRequestFile Permet à l’utilisateur de placer un verrou sur le fichier utilisé. Cette fonction nécessite un handle retourné par la fonction FtpOpenFile, HttpOpenRequest ou InternetOpenUrl .
InternetQueryDataAvailable Récupère la quantité de données disponibles. Nécessite un handle créé par la fonction FtpOpenFile ou HttpOpenRequest .
InternetQueryOption Récupère le paramètre d’une option Internet.
InternetReadFile Lit les données d’URL. Nécessite un handle créé par la fonction InternetOpenUrl, FtpOpenFile ou HttpOpenRequest .
InternetSetFilePointer Définit la position de la lecture suivante dans un fichier. Nécessite un handle créé par InternetOpenUrl (sur une URL HTTP uniquement) ou un handle créé par HttpOpenRequest à l’aide du verbe HTTP GET.
InternetSetOption Définit une option Internet.
InternetSetStatusCallback Définit une fonction de rappel qui reçoit des informations status. Affecte une fonction de rappel au handle HINTERNET désigné et à tous les handles dérivés de celui-ci.
InternetUnlockRequestFile Déverrouille un fichier qui a été verrouillé à l’aide de la fonction InternetLockRequestFile .

 

La lecture des fichiers, la recherche du fichier suivant, la manipulation des options et la configuration d’opérations asynchrones sont communes aux fonctions qui prennent en charge différents protocoles et types de handle HINTERNET .

Lecture de fichiers

La fonction InternetReadFile permet de télécharger des ressources à partir d’un handle HINTERNET retourné par la fonction InternetOpenUrl, FtpOpenFile ou HttpOpenRequest .

InternetReadFile accepte une variable de pointeur void qui contient l’adresse d’une mémoire tampon et un pointeur vers une variable qui contient la longueur de la mémoire tampon. La fonction retourne les données dans la mémoire tampon et la quantité de données téléchargées dans la mémoire tampon.

Les fonctions WinINet fournissent deux techniques pour télécharger une ressource entière :

InternetQueryDataAvailable prend le handle HINTERNET créé par InternetOpenUrl, FtpOpenFile ou HttpOpenRequest (une fois que HttpSendRequest a été appelé sur le handle) et retourne le nombre d’octets disponibles. L’application doit allouer une mémoire tampon égale au nombre d’octets disponibles, plus 1 pour le caractère null de fin, et utiliser cette mémoire tampon avec InternetReadFile. Cette méthode ne fonctionne pas toujours, car InternetQueryDataAvailable vérifie la taille de fichier répertoriée dans l’en-tête et non le fichier réel. Les informations contenues dans le fichier d’en-tête peuvent être obsolètes, ou le fichier d’en-tête peut être manquant, car il n’est pas requis actuellement dans toutes les normes.

L’exemple suivant lit le contenu de la ressource accessible par le handle hResource et affiché dans la zone d’édition indiquée par 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 retourne zéro octet lu et se termine correctement lorsque toutes les données disponibles ont été lues. Cela permet à une application d’utiliser InternetReadFile dans une boucle pour télécharger les données et quitter lorsqu’elle retourne zéro octet lu et se termine correctement.

L’exemple suivant lit la ressource à partir d’Internet et affiche la ressource dans la zone d’édition indiquée par intCtrlID. Le handle HINTERNET , hInternet, a été retourné par InternetOpenUrl, FtpOpenFile ou HttpOpenRequest (après avoir été envoyé par 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;
}

Recherche du fichier suivant

La fonction InternetFindNextFile permet de rechercher le fichier suivant dans une recherche de fichiers, à l’aide des paramètres de recherche et du handle HINTERNET de FtpFindFirstFile ou d’InternetOpenUrl.

Pour effectuer une recherche de fichiers, continuez à appeler InternetFindNextFile à l’aide du handle HINTERNET retourné par FtpFindFirstFile ou InternetOpenUrl jusqu’à ce que la fonction échoue avec le message d’erreur étendu ERROR_NO_MORE_FILES. Pour obtenir les informations d’erreur étendues, appelez la fonction GetLastError .

L’exemple suivant affiche le contenu d’un répertoire FTP dans la zone de liste indiquée par lstDirectory. Le handle HINTERNET , hConnect, est un handle retourné par la fonction InternetConnect après qu’elle a établi une session 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);
     
}

Manipulation des options

InternetSetOption et InternetQueryOption sont utilisés pour manipuler les options WinINet.

InternetSetOption accepte une variable qui indique l’option à définir, une mémoire tampon pour contenir le paramètre d’option et un pointeur qui contient l’adresse de la variable qui contient la longueur de la mémoire tampon.

InternetQueryOption accepte une variable qui indique l’option à récupérer, une mémoire tampon pour contenir le paramètre d’option et un pointeur qui contient l’adresse de la variable qui contient la longueur de la mémoire tampon.

Configuration des opérations asynchrones

Par défaut, les fonctions WinINet fonctionnent de manière synchrone. Une application peut demander une opération asynchrone en définissant l’indicateur INTERNET_FLAG_ASYNC dans l’appel à la fonction InternetOpen . Tous les appels futurs effectués sur des handles dérivés du handle retourné par InternetOpen sont effectués de manière asynchrone.

La logique d’une opération asynchrone ou synchrone est de permettre à une application monothread d’optimiser son utilisation du processeur sans avoir à attendre la fin des E/S réseau. Par conséquent, selon la demande, l’opération peut se terminer de manière synchrone ou asynchrone. L’application doit case activée le code de retour. Si une fonction retourne FALSE ou NULL et que GetLastError retourne ERROR_IO_PENDING, la demande a été effectuée de façon asynchrone et l’application est rappelée avec INTERNET_STATUS_REQUEST_COMPLETE lorsque la fonction est terminée.

Pour commencer l’opération asynchrone, l’application doit définir l’indicateur INTERNET_FLAG_ASYNC dans son appel à InternetOpen. L’application doit ensuite inscrire une fonction de rappel valide à l’aide d’InternetSetStatusCallback.

Une fois qu’une fonction de rappel est inscrite pour un handle, toutes les opérations sur ce handle peuvent générer des indications status, à condition que la valeur de contexte qui a été fournie lors de la création du handle n’était pas égale à zéro. La fourniture d’une valeur de contexte zéro force une opération à se terminer de manière synchrone, même si INTERNET_FLAG_ASYNC a été spécifié dans InternetOpen.

Les indications d’état fournissent à l’application des commentaires sur la progression des opérations réseau, telles que la résolution d’un nom d’hôte, la connexion à un serveur et la réception de données. Trois indications de status à usage spécial peuvent être faites pour un handle :

  • INTERNET_STATUS_HANDLE_CLOSING est la dernière indication status faite pour un handle.
  • INTERNET_STATUS_HANDLE_CREATED indique quand le handle est initialement créé.
  • INTERNET_STATUS_REQUEST_COMPLETE indique qu’une opération asynchrone est terminée.

L’application doit case activée la structure INTERNET_ASYNC_RESULT pour déterminer si l’opération a réussi ou échoué après avoir reçu une indication INTERNET_STATUS_REQUEST_COMPLETE.

L’exemple suivant montre un exemple de fonction de rappel et un appel à InternetSetStatusCallback pour inscrire la fonction en tant que fonction de rappel.

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); 

Fermeture des handles HINTERNET

Tous les handles HINTERNET peuvent être fermés à l’aide de la fonction InternetCloseHandle . Les applications clientes doivent fermer tous les handles HINTERNET dérivés du handle HINTERNET qu’elles tentent de fermer avant d’appeler InternetCloseHandle sur le handle.

L’exemple suivant illustre la hiérarchie de 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);

Verrouillage et déverrouillage des ressources

La fonction InternetLockRequestFile permet à une application de s’assurer que la ressource mise en cache associée au handle HINTERNET qui lui a été transmis ne disparaît pas du cache. Si un autre téléchargement tente de valider une ressource qui a la même URL que le fichier verrouillé, le cache évite de supprimer le fichier en effectuant une suppression sécurisée. Une fois que l’application a appelé la fonction InternetUnlockRequestFile , le cache est autorisé à supprimer le fichier.

Si l’indicateur INTERNET_FLAG_NO_CACHE_WRITE ou INTERNET_FLAG_DONT_CACHE a été défini, InternetLockRequestFile crée un fichier temporaire avec l’extension TMP, sauf si le handle est connecté à une ressource https. Si la fonction accède à une ressource https et que INTERNET_FLAG_NO_CACHE_WRITE (ou INTERNET_FLAG_DONT_CACHE) a été défini, InternetLockRequestFile échoue.

Notes

WinINet ne prend pas en charge les implémentations de serveur. En outre, il ne doit pas être utilisé à partir d’un service. Pour les implémentations de serveur ou les services, utilisez Microsoft Windows HTTP Services (WinHTTP).