天天看點

Windows Mobile下異步使用WinInet庫下載下傳資料

現在windows mobile系統雖然開始漸漸淡出人們的視線,我現在也轉到android上了,可是做了這麼些年windows mobile開發總覺得要留下點什麼,是以開始寫點這方面的部落格留個紀念,其實是把以前的東西重新整理回顧一下。

使用WinInet庫進行網絡下載下傳時,通常使用InternetReadFile函數,但它是同步下載下傳,是以當正在下載下傳時網絡突然斷線,程式有可能會卡在這個函數當中,當然也可以設定一個逾時來控制。當程式必須退出時,使用同步方式的話則必須等待函數完成或逾時,而用異步方式則可以友善的控制。 

1、介紹程式下載下傳的流程

//打開Internet,,标記使用異步方式,設定标志位INTERNET_FLAG_ASYNC

m_hSession = ::InternetOpen(AGENTNAME,INTERNET_OPEN_TYPE_DIRECT, NULL, NULL,INTERNET_FLAG_ASYNC);

//設定回調函數AsyncInternetCallback,函數傳回舊的回調函數

INTERNET_STATUS_CALLBACK pOldCallback = InternetSetStatusCallback(m_hSession, AsyncInternetCallback);

//打開一個url位址,最後一個參數系統會傳遞給回調函數

m_hInternetFile = ::InternetOpenUrl(m_hSession, lpszUrl, NULL, NULL, INTERNET_FLAG_RELOAD,(DWORD)this);

//傳回值為NULL,并且得到的錯誤是ERROR_IO_PENDING,則等待,可以從回調函數處得到打//開的句柄值

if(m_hInternetFile == NULL)

{

       if(GetLastError() == ERROR_IO_PENDING)

       {

              //等待在回調函數中取得打開的句柄

       }

       else

       {

              //出錯

       }

}

//開始下載下傳,以下取得資料的代碼可以放在一個循環中,直到取得全部的資料

pBuffer = new BYTE[dwBufferSize];

memset(pBuffer,0,dwBufferSize);

INTERNET_BUFFERS i_buf = {0};

i_buf.dwStructSize = sizeof(i_buf);

i_buf.lpvBuffer = pBuffer;

i_buf.dwBufferLength = dwBufferSize;

//重置讀資料事件

ResetEvent(m_hEventComplete);

BOOL bRead =  ::InternetReadFileExA(m_hInternetFile,(LPINTERNET_BUFFERSA)&i_buf,IRF_ASYNC,(DWORD)this)

//傳回值為FALSE,并且錯誤号為ERROR_IO_PENDING,則說明正在異步取得資料;有時候網絡比較暢通時會傳回TRUE,這時候資料已經取得

if ( !bRead )

{

       DWORD dwError = GetLastError();

       if (ERROR_IO_PENDING == dwError)

       {

              //等待讀取資料的事件被激活

       }

       else

              //出錯

}

else

       資料已經取得

2、介紹回調函數

void AsyncInternetCallback(HINTERNET hInternet,DWORD dwInternetStatus, LPVOID lpvStatusInformation, DWORD dwStatusInformationLength)

{

       switch(dwInternetStatus)

       {

              //句柄被建立

       case INTERNET_STATUS_HANDLE_CREATED:

              m_hInternetFile = (HINTERNET)(((LPINTERNET_ASYNC_RESULT)(lpvStatusInformation))->dwResult);

              break;

              //句柄被關閉

       case INTERNET_STATUS_HANDLE_CLOSING:

       case INTERNET_STATUS_CONNECTION_CLOSED:

              break;

       //一個請求完成,比如一次句柄建立的請求,或者一次讀資料的請求,在這裡激活相應的事件

       case INTERNET_STATUS_REQUEST_COMPLETE:

              if (ERROR_SUCCESS == ((LPINTERNET_ASYNC_RESULT)(lpvStatusInformation))->dwError)

              {

                     //激活等待的事件

              }

              else

              {

                     //激活出錯的事件

              }

              break;

       }

}

注意:調用::InternetReadFileEx有一個需要注意的地方:在Unicode環境下(比如WinCE中),系統會自動轉譯調用InternetReadFileExW函數,這個函數會直接傳回錯誤号120,這時候要使用異步操作必須調用InternetReadFileExA函數。