Windows Mobile下非同步使用WinInet庫下載資料

hcxhy_only發表於2010-12-27

現在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函式。

相關文章