Common Functions(Windows Internet)

ftp 및 http와 같은 다양한 인터넷 프로토콜은 동일한 여러 WinINet 함수를 사용하여 인터넷에서 정보를 처리합니다. 이러한 일반적인 함수는 적용 중인 특정 프로토콜에 관계없이 일관된 방식으로 작업을 처리합니다. 애플리케이션은 이러한 함수를 사용하여 다양한 프로토콜(예: ftp 및 http용 파일 읽기)에서 작업을 처리하는 범용 함수를 만들 수 있습니다.

일반적인 함수는 다음 작업을 처리합니다.

Common Functions 사용

다음 표에서는 WinINet 함수에 포함된 일반적인 함수를 나열합니다. 공통 함수는 다양한 유형의 HINTERNET 핸들에서 사용하거나 다양한 유형의 세션 중에 사용할 수 있습니다.

함수 Description
InternetFindNextFile 파일 열거 또는 검색을 계속합니다. FtpFindFirstFile 또는 InternetOpenUrl 함수에서 만든 핸들이 필요합니다.
InternetLockRequestFile 사용자가 사용 중인 파일에 잠금을 배치할 수 있습니다. 이 함수에는 FtpOpenFile, HttpOpenRequest 또는 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 함수는 전체 리소스를 다운로드하는 두 가지 기술을 제공합니다.

InternetQueryDataAvailableInternetOpenUrl, FtpOpenFile 또는 HttpOpenRequest에서 만든 HINTERNET 핸들을 사용하고(핸들에서 HttpSendRequest가 호출된 후) 사용 가능한 바이트 수를 반환합니다. 애플리케이션은 사용 가능한 바이트 수와 동일한 버퍼를 할당하고 종료 되는 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 지정되었더라도 작업이 동기적으로 완료됩니다.

상태 표시는 호스트 이름 확인, 서버에 연결 및 데이터 수신과 같은 네트워크 작업의 진행률에 대한 애플리케이션 피드백을 제공합니다. 핸들에 대한 세 가지 특수 목적 상태 표시를 만들 수 있습니다.

  • 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 핸들 닫기

InternetCloseHandle 함수를 사용하여 모든 HINTERNET 핸들을 닫을 수 있습니다. 클라이언트 애플리케이션은 핸들에서 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 이 실패합니다.

참고

WinINet은 서버 구현을 지원하지 않습니다. 또한 서비스에서 사용하지 않아야 합니다. 서버 구현 또는 서비스의 경우 WinHTTP(Microsoft Windows HTTP 서비스)를 사용합니다.