共通関数 (Windows インターネット)

異なるインターネット プロトコル (ftp や http など) では、インターネット上の情報を処理するために、同じ WinINet 関数のいくつかが使用されます。 これらの一般的な関数は、適用される特定のプロトコルに関係なく、一貫した方法でタスクを処理します。 アプリケーションでは、これらの関数を使用して、さまざまなプロトコル (ftp および http 用のファイルの読み取りなど) 全体のタスクを処理する汎用関数を作成できます。

共通関数は、次のタスクを処理します。

共通関数の使用

次の表に、WinINet 関数に含まれる一般的な関数を示します。 共通関数は、異なるタイプの HINTERNET ハンドルで使用することも、異なるタイプのセッション中に使用することもできます。

機能 説明
InternetFindNextFile ファイルの列挙または検索を続行します。 FtpFindFirstFile 関数または InternetOpenUrl 関数によって作成されたハンドルが必要です。
InternetLockRequestFile ユーザーが使用されているファイルにロックを設定できるようにします。 この関数には、 FtpOpenFileHttpOpenRequest、または InternetOpenUrl 関数によって返されるハンドルが必要です。
InternetQueryDataAvailable 使用可能なデータの量を取得します。 FtpOpenFile 関数または HttpOpenRequest 関数によって作成されたハンドルが必要です。
InternetQueryOption インターネット オプションの設定を取得します。
InternetReadFile URL データを読み取ります。 InternetOpenUrl、FtpOpenFile、または HttpOpenRequest 関数によって作成されたハンドルが必要です。
InternetSetFilePointer ファイル内の次の読み取りの位置を設定します。 InternetOpenUrl によって作成されたハンドル (HTTP URL のみ) または GET HTTP 動詞を使用して HttpOpenRequest によって作成されたハンドルが必要です。
InternetSetOption インターネット オプションを設定します。
InternetSetStatusCallback 状態情報を受け取るコールバック関数を設定します。 指定された HINTERNET ハンドルと、そこから派生したすべてのハンドルにコールバック関数を割り当てます。
InternetUnlockRequestFile InternetLockRequestFile 関数を使用してロックされたファイルのロックを解除します。

 

ファイルの読み取り、次のファイルの検索、オプションの操作、非同期操作の設定は、さまざまなプロトコルと HINTERNET ハンドルの種類をサポートする関数に共通です。

ファイルの読み取り

InternetReadFile 関数は、InternetOpenUrl、FtpOpenFile、または HttpOpenRequest 関数によって返される HINTERNET ハンドルからリソースをダウンロードするために使用されます。

InternetReadFile は 、バッファーのアドレスとバッファーの長さを含む変数へのポインターを含む void ポインター変数を受け入れます。 関数は、バッファー内のデータと、バッファーにダウンロードされたデータの量を返します。

WinINet 関数には、リソース全体をダウンロードするための 2 つの手法が用意されています。

InternetQueryDataAvailable は、InternetOpenUrlFtpOpenFile、または HttpOpenRequest (ハンドルで HttpSendRequest が呼び出された後) によって作成された HINTERNET ハンドルを受け取り、使用可能なバイト数を返します。 アプリケーションでは、使用可能なバイト数と等しいバッファーと終端 の null 文字に 1 を割り当て、そのバッファーを InternetReadFile と共に使用する必要があります。 InternetQueryDataAvailable は、実際のファイルではなくヘッダーに一覧表示されているファイル サイズをチェックしているため、このメソッドは常に機能するとは限りません。 ヘッダー ファイル内の情報が古くなっているか、ヘッダー ファイルが見つからない可能性があります。これは、現在、すべての標準では必須ではないためです。

次の例では、hResource ハンドルによってアクセスされ、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 は 0 バイトの読み取りを返し、使用可能なすべてのデータが読み取られた場合に正常に完了します。 これにより、アプリケーションは InternetReadFile をループ内で使用してデータをダウンロードし、読み取り 0 バイトを返して正常に完了したときに終了できます。

次の例では、インターネットからリソースを読み取り、intCtrlID で示される編集ボックスにリソースを表示します。 HINTERNET ハンドル hInternet は、InternetOpenUrl、FtpOpenFile、または HttpOpenRequest (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;
}

次のファイルの検索

InternetFindNextFile 関数は、FtpFindFirstFile または InternetOpenUrl の検索パラメーターと HINTERNET ハンドルを使用して、ファイル検索で次のファイルを検索するために使用されます。

ファイル検索を完了するには、関数が拡張エラー メッセージ ERROR_NO_MORE_FILESで失敗するまで、FtpFindFirstFile または InternetOpenUrl によって返される HINTERNET ハンドルを使用して InternetFindNextFile を呼び出し続けます。 拡張エラー情報を取得するには、 GetLastError 関数を呼び出します。

次の例では、lstDirectory で示されるリスト ボックスに FTP ディレクトリの内容を表示します。 HINTERNET ハンドル hConnect は、FTP セッションを確立した後に InternetConnect 関数によって返されるハンドルです。

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

オプションの操作

InternetSetOptionInternetQueryOption は、WinINet オプションを操作するために使用されます。

InternetSetOption は 、設定するオプションを示す変数、オプション設定を保持するバッファー、およびバッファーの長さを含む変数のアドレスを含むポインターを受け取ります。

InternetQueryOption は、取得するオプションを示す変数、オプション設定を保持するバッファー、およびバッファーの長さを含む変数のアドレスを含むポインターを受け取ります。

非同期操作の設定

既定では、WinINet 関数は同期的に動作します。 アプリケーションは、InternetOpen 関数の呼び出しで INTERNET_FLAG_ASYNC フラグを設定することで、非同期操作を要求できます。 InternetOpen から返されるハンドルから派生したハンドルに対して今後行われる呼び出しはすべて、非同期的に行われます。

非同期操作と同期操作の根拠は、シングルスレッド アプリケーションがネットワーク I/O の完了を待たずに CPU の使用率を最大化できるようにすることです。 したがって、要求によっては、操作が同期的または非同期的に完了する場合があります。 アプリケーションはリターン コードをチェックする必要があります。 関数が FALSE または NULL を返し、 GetLastError が ERROR_IO_PENDINGを返す場合、要求は非同期的に行われ、関数の完了時にアプリケーションはINTERNET_STATUS_REQUEST_COMPLETEで呼び戻されます。

非同期操作を開始するには、アプリケーションが InternetOpen の呼び出しで INTERNET_FLAG_ASYNC フラグを設定する必要があります。 その後、アプリケーションは InternetSetStatusCallback を使用して有効なコールバック関数を登録する必要があります。

コールバック関数がハンドルに登録されると、ハンドルの作成時に指定されたコンテキスト値が 0 でなかった場合、そのハンドルに対するすべての操作で状態インジケーターを生成できます。 コンテキスト値を 0 に設定すると、InternetOpenINTERNET_FLAG_ASYNCが指定されていても、操作は強制的に同期的に完了します。

状態表示は、ホスト名の解決、サーバーへの接続、データの受信など、ネットワーク操作の進行状況に関するアプリケーションのフィードバックを提供します。 ハンドルには、次の 3 つの特殊な目的の状態を示すことができます。

  • INTERNET_STATUS_HANDLE_CLOSINGは、ハンドルに対して行われる最後の状態を示します。
  • INTERNET_STATUS_HANDLE_CREATEDは、ハンドルが最初に作成されるタイミングを示します。
  • INTERNET_STATUS_REQUEST_COMPLETEは、非同期操作が完了したことを示します。

アプリケーションは、INTERNET_ASYNC_RESULT構造体をチェックして、INTERNET_STATUS_REQUEST_COMPLETEの指示を受け取った後に操作が成功したか失敗したかを判断する必要があります。

次の例は、コールバック関数の例と、コールバック関数として関数を登録するための InternetSetStatusCallback の呼び出しを示しています。

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

HINTERNET ハンドルを閉じる

すべての HINTERNET ハンドルは、 InternetCloseHandle 関数を使用して閉じることができます。 クライアント アプリケーションは、ハンドルで InternetCloseHandle を呼び出す前に、閉じようとしている HINTERNET ハンドルから派生したすべての HINTERNET ハンドルを閉じる必要があります。

次の例は、ハンドル階層を示しています。

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

リソースのロックとロック解除

InternetLockRequestFile 関数を使用すると、アプリケーションは、渡された HINTERNET ハンドルに関連付けられているキャッシュされたリソースがキャッシュから消えないようにすることができます。 ロックされたファイルと同じ URL を持つリソースを別のダウンロードでコミットしようとすると、キャッシュは安全な削除を行うことでファイルの削除を回避します。 アプリケーションが InternetUnlockRequestFile 関数を呼び出した後、ファイルを削除するためのアクセス許可がキャッシュに付与されます。

INTERNET_FLAG_NO_CACHE_WRITEまたはINTERNET_FLAG_DONT_CACHE フラグが設定されている場合、ハンドルが https リソースに接続されていない限り、InternetLockRequestFile は拡張子 TMP を持つ一時ファイルを作成します。 関数が https リソースにアクセスし、INTERNET_FLAG_NO_CACHE_WRITE (またはINTERNET_FLAG_DONT_CACHE) が設定されている場合、 InternetLockRequestFile は 失敗します。

Note

WinINet では、サーバーの実装はサポートされていません。 また、サービスから使用しないでください。 サーバーの実装またはサービスの場合は、 Microsoft Windows HTTP サービス (WinHTTP) を使用します。