• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            Benjamin

            靜以修身,儉以養德,非澹薄無以明志,非寧靜無以致遠。
            隨筆 - 397, 文章 - 0, 評論 - 196, 引用 - 0
            數據加載中……

            WinInet編程中如何使用異步

            在WinInet編程中,同步的使用方法如下:
            InternetOpen->InternetOpenUrl->HttpQueryInfo->InternetReadFile->InternetCloseHandle;在InternetOpenUrl和InternetReadFile時會導致程序阻塞,知道操作完成,同步的好處就是比較簡單,調試方便。
            異步的使用方法如下:
            1)InternetOpen,需指定是異步;
            2)InternetSetStatusCallback,設置回調;
            3)InternetOpenUrl,需指定回調參數;
            4)WaitForSingObject或WaitForMultipleObjects,接收信號量;
            5)HttpQueryInfo;
            6)InternetReadFileEx,需指定回調參數(CE或mobile下是InternetReadFileExA);
            7)WaitForSingObject或WaitForMultipleObjects,接收信號量;
            8)InternetSetStatusCallback,卸載回調;
            9)InternetCloseHandle。
            異步比同步要復雜了不少,重點在于回調函數。在回調中,系統會及時返回各種系統定義的HTTP消息,我們根據這些消息來設置某些信號量。在WaitForSingObject或WaitForMultipleObjects里,等待這些信號(當然也可以等待用戶的取消動作)。當有正確的信號返回時,繼續往下的操作。下面一個例子代碼:上面的理論同樣適用于wince或windows mobile平臺

            #include<windows.h>
            #include
            <wininet.h>
            #include
            <iostream.h>

            DWORD dwNumKSent;
            DWORD dwNumKToSend;
            DWORD dwNumBytesComplete 
            = 0;
            char lpOutBuf[1024];
            HANDLE hConnectedEvent, hRequestCompleteEvent;
            HINTERNET hInstance, hConnect, hRequest;
            char *lpszUrl, *lpszServer;

            BOOL bAllDone 
            = FALSE;

            void __stdcall Callback(HINTERNET hInternet,
                          DWORD dwContext,
                          DWORD dwInternetStatus,
                          LPVOID lpStatusInfo,
                          DWORD dwStatusInfoLen);

            void main(int argc, char *argv[])
            {
                
            if (argc != 4)
                {
                    cout 
            << "Usage: sendreqexasync <server> <url> <size in kilobytes>" << endl;
                    cout 
            << "   Example: sendreqexasync www.foo.com /postfolder/upload.exe 256" << endl;
                    
            return;
                }

                lpszServer 
            = argv[1];
                lpszUrl 
            = argv[2];
                dwNumKToSend 
            = atoi(argv[3]);

                FillMemory(lpOutBuf, 
            1024'A');
                hConnectedEvent 
            = CreateEvent(NULL, FALSE, FALSE, NULL);
                hRequestCompleteEvent 
            = CreateEvent(NULL, FALSE, FALSE, NULL);

                hInstance 
            = InternetOpen("sendreqexasync"
                                                   INTERNET_OPEN_TYPE_PRECONFIG,
                                                   NULL,
                                                   NULL,
                                                   INTERNET_FLAG_ASYNC);

                
            if (hInstance == NULL)
                {
                    cout 
            << "InternetOpen failed, error " << GetLastError();
                    
            return;
                }

                
            if (InternetSetStatusCallback(hInstance,
                                              (INTERNET_STATUS_CALLBACK)
            &Callback) == INTERNET_INVALID_STATUS_CALLBACK)
                {
                    cout 
            << "InternetSetStatusCallback failed, error " << GetLastError();
                    
            return;
                }

                hConnect 
            = InternetConnect(hInstance, 
                                           lpszServer, 
                                           INTERNET_DEFAULT_HTTP_PORT,
                                           NULL,
                                           NULL,
                                           INTERNET_SERVICE_HTTP,
                                           
            0,
                                           
            1);
                
            if (hConnect == NULL)
                {
                    
            if (GetLastError() != ERROR_IO_PENDING)
                    {
                        cout 
            << "InternetConnect failed, error " << GetLastError();
                        
            return;
                    }
                    WaitForSingleObject(hConnectedEvent, INFINITE);
                }

                hRequest 
            = HttpOpenRequest(hConnect, 
                                           
            "POST"
                                           lpszUrl,
                                           NULL,
                                           NULL,
                                           NULL,
                                           INTERNET_FLAG_RELOAD 
            | INTERNET_FLAG_NO_CACHE_WRITE,
                                           
            2);
                
            if (hRequest == NULL)
                {
                    
            if (GetLastError() != ERROR_IO_PENDING)
                    {
                        cout 
            << "HttpOpenRequest failed, error " << GetLastError();
                        
            return;
                    }
                    WaitForSingleObject(hRequestCompleteEvent, INFINITE);
                }

                INTERNET_BUFFERS IntBuff;

                FillMemory(
            &IntBuff, sizeof(IntBuff), 0);
                IntBuff.dwStructSize
            = sizeof(IntBuff);
                IntBuff.dwBufferTotal 
            = 1024*dwNumKToSend;
                IntBuff.lpcszHeader 
            = "Content-Type: text/text\r\n";
                IntBuff.dwHeadersLength 
            = lstrlen(IntBuff.lpcszHeader);

                
            if (!HttpSendRequestEx(hRequest, 
                                       
            &IntBuff, 
                                       NULL, 
                                       
            0,
                                       
            2))
                {
                    
            if (GetLastError() != ERROR_IO_PENDING)
                    {
                        cout 
            << "HttpSendRequestEx failed, error " << GetLastError();
                        
            return;
                    }
                    cout 
            << "HttpSendRequestEx called successfully" << endl;
                    cout.flush();

                    WaitForSingleObject(hRequestCompleteEvent, INFINITE);
                }

                
            for (dwNumKSent = 0; dwNumKSent < dwNumKToSend; dwNumKSent++)
                {
                    DWORD dwBytesWritten;

                    
            if(!InternetWriteFile(hRequest,
                                           lpOutBuf,
                                           
            1024,
                                           
            &dwBytesWritten))
                    {
                        
            if (GetLastError() != ERROR_IO_PENDING)
                        {
                            cout 
            << "InternetWriteFile failed, error " << GetLastError();
                            
            return;
                        }
                        
            else
                        {
                            cout 
            << "InternetWriteFile completing asynchronously" << endl;
                            cout.flush();
                            WaitForSingleObject(hRequestCompleteEvent, INFINITE);
                        }
                    }
                }

                cout 
            << "Calling HttpEndRequest" << endl;
                cout.flush();
                
            if (!HttpEndRequest(hRequest, NULL, HSR_INITIATE, 2))
                {
                    
            if (GetLastError() == ERROR_IO_PENDING)
                    {
                        cout 
            << "HttpEndRequest called" << endl;
                        cout.flush();
                        WaitForSingleObject(hRequestCompleteEvent, INFINITE);
                    }
                    
            else
                    {
                        cout 
            << "HttpEndRequest failed, error " << GetLastError() << endl;
                        
            return;
                    }
                }


                cout 
            << "------------------- Read the response -------------------" << endl;
                
            char lpReadBuff[256];

                
            do
                {
                    INTERNET_BUFFERS InetBuff;
                    FillMemory(
            &InetBuff, sizeof(InetBuff), 0);
                    InetBuff.dwStructSize 
            = sizeof(InetBuff);
                    InetBuff.lpvBuffer 
            = lpReadBuff;
                    InetBuff.dwBufferLength 
            = sizeof(lpReadBuff) - 1;
                    
                    cout 
            << "Calling InternetReadFileEx" << endl;
                    cout.flush();

                    
            if (!InternetReadFileEx(hRequest,
                                          
            &InetBuff,
                                          
            02))
                    {
                        
            if (GetLastError() == ERROR_IO_PENDING)
                        {
                            cout 
            << "Waiting for InternetReadFile to complete" << endl;
                            cout.flush();
                            WaitForSingleObject(hRequestCompleteEvent, INFINITE);
                        }
                        
            else
                        {
                            cout 
            << "InternetReadFileEx failed, error " << GetLastError();
                            cout.flush();
                            
            return;
                        }
                    }

                    lpReadBuff[InetBuff.dwBufferLength] 
            = 0;
                    cout 
            << lpReadBuff;
                    cout.flush();

                    
            if (InetBuff.dwBufferLength == 0
                        bAllDone 
            = TRUE;

                } 
            while (bAllDone == FALSE);

                cout 
            << endl << endl << "------------------- Request Complete ----------------" << endl;

            }

            void __stdcall Callback(HINTERNET hInternet,
                          DWORD dwContext,
                          DWORD dwInternetStatus,
                          LPVOID lpStatusInfo,
                          DWORD dwStatusInfoLen)
            {
                cout 
            << "Callback dwInternetStatus: " << dwInternetStatus << " Context: " << dwContext << endl;
                cout.flush();

                
            switch(dwContext)
                {
                
            case 1// Connection handle
                    if (dwInternetStatus == INTERNET_STATUS_HANDLE_CREATED)
                    {
                        INTERNET_ASYNC_RESULT 
            *pRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;
                        hConnect 
            = (HINTERNET)pRes->dwResult;
                        cout 
            << "Connect handle created" << endl;
                        cout.flush();
                        SetEvent(hConnectedEvent);
                    }
                    
            break;
                
            case 2// Request handle
                    switch(dwInternetStatus)
                    {
                    
            case INTERNET_STATUS_HANDLE_CREATED:
                        {
                            INTERNET_ASYNC_RESULT 
            *pRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;
                            hRequest 
            = (HINTERNET)pRes->dwResult;
                            cout 
            << "Request handle created" << endl;
                            cout.flush();
                        }
                        
            break;
                    
            case INTERNET_STATUS_REQUEST_SENT:
                        {
                            DWORD 
            *lpBytesSent = (DWORD*)lpStatusInfo;
                            cout 
            << "Bytes Sent: " << *lpBytesSent << endl;
                            dwNumBytesComplete 
            += *lpBytesSent;
                        }
                        
            break;
                    
            case INTERNET_STATUS_REQUEST_COMPLETE:
                        {
                            INTERNET_ASYNC_RESULT 
            *pAsyncRes = (INTERNET_ASYNC_RESULT *)lpStatusInfo;
                            cout 
            << "Function call finished" << endl;
                            cout 
            << "dwResult: " << pAsyncRes->dwResult << endl;
                            cout 
            << "dwError:  " << pAsyncRes->dwError << endl;
                            cout.flush();
                            SetEvent(hRequestCompleteEvent);
                        }
                        
            break;
                    
            case INTERNET_STATUS_RECEIVING_RESPONSE:
                        cout 
            << "Receiving Response" << endl;
                        cout.flush();
                        
            break;
                    
            case INTERNET_STATUS_RESPONSE_RECEIVED:
                        {
                            DWORD 
            *dwBytesReceived = (DWORD*)lpStatusInfo;
                            cout 
            << "Received " << *dwBytesReceived << endl;
                            cout.flush();
                        }

                    }

                }

            }

            參考的異步類:
             1 include <wininet.h>
             2 #include <mmsystem.h>
             3 
             4 class AsyncWinINet
             5 {
             6 public:
             7    typedef void (*notify_fp)(const StringMap&);
             8   
             9    class thread_info
            10    {
            11    public:
            12     thread_info(const String& _url,     //請求下載的地址(in)
            13      const StringMap& _request_headrs,   //請求頭request_headrs(in)
            14      const notify_fp& _pfp,      //下載進度通知回調函數指針
            15      const StringMap& _pfp_param,
            16      String& _response_headrs,     //返回頭response_headrs(out)  
            17      const String& _saved_filename,    //下載內容保存文件名(in)
            18      String& _response_content,     //返回內容(out)
            19      size_t _read_content_size)     //控制保存在response_content中內容的長度(in)) : 
            20      : request_headrs(_request_headrs), pfp(_pfp),
            21      pfp_param(_pfp_param),      //pfp函數傳回參數
            22      response_headrs(_response_headrs), saved_filename(_saved_filename),
            23      response_content(_response_content), read_content_size(_read_content_size) 
            24     {
            25      this->response_headrs.clear();
            26      this->response_content.clear();
            27      this->url = StringUtil::EncodeURIComponent(_url);
            28      for(int i = 0; i < 3++i)
            29      {
            30       this->hEvent[i] = CreateEvent(NULL,TRUE,FALSE,NULL);
            31      }
            32     }
            33 
            34     HANDLE hThread;
            35     DWORD dwThreadID;
            36     HANDLE hCallbackThread;
            37     DWORD dwCallbackThreadID;
            38     HANDLE hEvent[3];
            39     LPVOID hInternet;
            40     LPVOID hFile;
            41     DWORD dwStatusCode;
            42     DWORD dwContentLength;
            43 
            44     String url;         //請求下載的地址(in)
            45     const StringMap& request_headrs;   //請求頭request_headrs(in)
            46     const notify_fp& pfp;      //下載進度通知回調函數指針
            47     const StringMap& pfp_param;     //pfp函數傳回參數
            48 
            49     String& response_headrs;     //返回頭response_headrs(out)  
            50     const String& saved_filename;    //下載內容保存文件名(in)
            51     String& response_content;     //返回內容(out)
            52     size_t read_content_size;     //控制保存在response_content中內容的長度(in)
            53    };
            54 
            55    /*******************************************************************************
            56    * 函數:download
            57    * 功能:下載,返回WinINet_ERR_CODE值
            58    *   說明:關于notify_fp 類型說明: 函數的參數為StringMap類型,傳回的變量名與變量值
            59    * 2007-12
            60    *******************************************************************************/
            61    static DWORD download(const String& url, //請求下載的地址(in)
            62     const StringMap& request_headrs,   //請求頭request_headrs(in)
            63     const notify_fp& pfp,      //下載進度通知回調函數指針
            64     const StringMap& pfp_param,     //pfp函數傳回參數
            65     String& response_headrs,     //返回頭response_headrs(out)  
            66     const String& saved_filename,    //下載內容保存文件名(in)
            67     String& response_content,     //返回內容(out)
            68     size_t read_content_size = 0);    //控制保存在response_content中內容的長度(in)
            69 
            70 protected:
            71    static BOOL WaitExitEvent(thread_info *p);
            72    static DWORD WINAPI AsyncThread(LPVOID lpParameter);
            73    static DWORD WINAPI AsyncCallbackThread(LPVOID lpParameter);
            74    static VOID CALLBACK AsyncInternetCallback(HINTERNET hInternet,
            75     DWORD dwContext,
            76     DWORD dwInternetStatus,
            77     LPVOID lpvStatusInformation,
            78     DWORD dwStatusInformationLength);
            79 
            80 };
            81 

              1 #include "AsyncWinINet.h"
              2 
              3 #include "stdafx.h"
              4 
              5 #pragma comment(lib, "Winmm.lib")
              6 #pragma comment(lib, "Wininet.lib")
              7 
              8 DWORD AsyncWinINet::download(const Fagex::String &url, const Fagex::StringMap &request_headrs, 
              9    const Fagex::AsyncWinINet::notify_fp &pfp, const Fagex::StringMap &pfp_param, Fagex::String &response_headrs, 
             10    const Fagex::String &saved_filename, Fagex::String &response_content, size_t read_content_size)
             11 {
             12    thread_info info(url, request_headrs, pfp,
             13     pfp_param, response_headrs, saved_filename,
             14     response_content, read_content_size);
             15 
             16    info.hThread = CreateThread(NULL, 
             17     0,
             18     AsyncWinINet::AsyncThread,
             19     &info,
             20     NULL,
             21     &info.dwThreadID);
             22 
             23    WaitForSingleObject(info.hThread, INFINITE); //等待子線程安全退出
             24    CloseHandle(info.hThread);//關閉線程句柄
             25 
             26    return TRUE;
             27 }
             28 
             29 //---------------------------------------------------------------------
             30 DWORD WINAPI AsyncWinINet::AsyncThread(LPVOID lpParameter)
             31 {
             32    thread_info* p = (thread_info*)lpParameter;
             33 
             34    //a. 使用標記 INTERNET_FLAG_ASYNC 初始化 InternetOpen
             35    String user_agent("Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; TencentTraveler ; .NET CLR 2.0.50727)");
             36    StringMap iheadrs(p->request_headrs.begin(), p->request_headrs.end());
             37    StringMap::iterator it = iheadrs.find("User-Agent");
             38    if(it == iheadrs.end()) iheadrs["User-Agent"= user_agent;
             39    else user_agent = it->second;
             40 
             41    p->hInternet = InternetOpen(user_agent.c_str(),
             42     INTERNET_OPEN_TYPE_PRECONFIG,
             43     NULL,
             44     NULL,
             45     INTERNET_FLAG_ASYNC);
             46 
             47    //ResetEvent(p->hEvent[0]);
             48    //p->hCallbackThread = CreateThread(NULL,
             49    // 0,
             50    // AsyncWinINet::AsyncCallbackThread,
             51    // p,
             52    // NULL,
             53    // &p->dwCallbackThreadID);
             54    //WaitForSingleObject(p->hEvent[0], INFINITE);//等待回調函數設置成功事件
             55    InternetSetStatusCallback(p->hInternet, AsyncWinINet::AsyncInternetCallback);
             56 
             57    String sheadrs;
             58    for(it = iheadrs.begin(); it != iheadrs.end(); ++it)
             59    {
             60     sheadrs += it->first + ":" + it->second;
             61     if(it->second.find(StringUtil::enter) == String::npos) { sheadrs += StringUtil::enter; }
             62    }
             63    sheadrs += StringUtil::enter;
             64   
             65    DWORD start_time = timeGetTime();
             66    ResetEvent(p->hEvent[0]); //重置句柄被創建事件
             67    p->hFile = InternetOpenUrl(p->hInternet, p->url.c_str(), sheadrs.c_str(), sheadrs.length(), 
             68     INTERNET_FLAG_DONT_CACHE | INTERNET_FLAG_RELOAD, (DWORD)p);
             69 
             70    FILE *fp = fopen(p->saved_filename.c_str(), "w+");
             71    while(true)
             72    {
             73     if (NULL == p->hFile)
             74     {
             75      DWORD dwError = ::GetLastError();
             76      if (ERROR_IO_PENDING == dwError || ERROR_SUCCESS == dwError)
             77      {
             78       if (WaitExitEvent(p)) { break; }
             79      }
             80      else break;
             81     }
             82 
             83     //讀取返回文件頭
             84     DWORD dwLength = 0;
             85     LPVOID lpOutBuffer = NULL;
             86     while(true//讀取response_headrs數據
             87     {
             88      if(!HttpQueryInfo(p->hFile, HTTP_QUERY_RAW_HEADERS_CRLF,
             89         lpOutBuffer, &dwLength, NULL))
             90      {
             91       DWORD err_code = GetLastError();
             92       if (err_code == ERROR_HTTP_HEADER_NOT_FOUND) break
             93       else if(err_code == ERROR_INSUFFICIENT_BUFFER)
             94       {
             95        lpOutBuffer = new char[dwLength];
             96        continue
             97       }
             98       else break;
             99      }
            100      break;
            101     }
            102     if(lpOutBuffer != NULL)
            103     {
            104      p->response_headrs.append((char*)lpOutBuffer,dwLength);
            105      delete [] lpOutBuffer;
            106     }
            107 
            108     //e. 使用 HttpQueryInfo 分析頭信息 HttpQueryInfo 使用非阻塞方式,所以不用等待
            109     DWORD dwStatusSize = sizeof(p->dwStatusCode);
            110     if (FALSE == HttpQueryInfo(p->hFile, //獲取返回狀態碼
            111      HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
            112      &p->dwStatusCode, &dwStatusSize, NULL)) { break; }
            113    
            114     //判斷狀態碼是不是 200
            115     if (HTTP_STATUS_OK != p->dwStatusCode) break;
            116    
            117     StringMap msgMap(p->pfp_param.begin(), p->pfp_param.end());
            118     msgMap["url"= p->url;
            119 
            120     //獲取返回的Content-Length
            121     //DWORD dwLengthSize = sizeof(p->dwContentLength); 
            122     //if (FALSE == HttpQueryInfo(p->hFile,
            123     //HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
            124     //&p->dwContentLength, &dwLengthSize, NULL)) { p->dwContentLength = 0; }
            125 
            126     //f. 使用標記 IRF_ASYNC 讀數據 InternetReadFileEx
            127     //為了向主線程報告進度,我們設置每次讀數據最多 1024 字節
            128 
            129     char lpvBuffer[1024];
            130     p->dwContentLength = 0//Content-Length: 202749
            131     while(true)
            132     {
            133      INTERNET_BUFFERS i_buf = {0};
            134      i_buf.dwStructSize = sizeof(INTERNET_BUFFERS);
            135      i_buf.lpvBuffer = lpvBuffer;
            136      i_buf.dwBufferLength = 1024;
            137        
            138      //重置讀數據事件
            139      ResetEvent(p->hEvent[0]);
            140      if (FALSE == InternetReadFileEx(p->hFile, &i_buf, IRF_ASYNC, (DWORD)p))
            141      {
            142       if (ERROR_IO_PENDING == ::GetLastError())
            143       {
            144        if (WaitExitEvent(p)) break
            145       }
            146       else break
            147      }
            148      else
            149      {
            150       //在網絡傳輸速度快,步長較小的情況下,InternetReadFileEx 經常會直接返回成功,
            151       //因此要判斷是否發生了用戶要求終止子線程事件。
            152       if (WAIT_OBJECT_0 == WaitForSingleObject(p->hEvent[2], 0))
            153       {
            154        ResetEvent(p->hEvent[2]);
            155        break;
            156       }
            157      }
            158 
            159      if(i_buf.dwBufferLength == 0
            160      {
            161       DWORD time = timeGetTime() - start_time;
            162       if(time != 0)
            163       {
            164        Real speed = (Real)p->dwContentLength;
            165        speed /= ((Real)time)/1000.0f;
            166        speed /= 1024.0f;
            167        msgMap["speed"= StringUtil::toString((DWORD)speed);
            168       }
            169       if(p->pfp) p->pfp(msgMap);
            170       break;
            171      }
            172      if(fp)
            173      {
            174       fwrite(i_buf.lpvBuffer, sizeof(char), i_buf.dwBufferLength, fp);
            175      }
            176      if(p->read_content_size > p->response_content.size())
            177      {
            178       p->response_content.append((char*)i_buf.lpvBuffer, i_buf.dwBufferLength);
            179      }
            180      p->dwContentLength += i_buf.dwBufferLength;
            181     }
            182     break;
            183    }
            184   
            185    if(fp)
            186    {
            187     fflush(fp); fclose(fp); fp = NULL;
            188    }
            189 
            190    if(p->hFile)
            191    {
            192     InternetCloseHandle(p->hFile);//關閉 m_hFile
            193     while (!WaitExitEvent(p)) //等待句柄被關閉事件或者要求子線程退出事件
            194     {
            195      ResetEvent(p->hEvent[0]);
            196     }
            197    }
            198 
            199    //設置子線程退出事件,通知回調線程退出
            200    SetEvent(p->hEvent[2]);
            201   
            202    //等待回調線程安全退出
            203    //WaitForSingleObject(p->hCallbackThread, INFINITE);
            204    //CloseHandle(p->hCallbackThread);
            205   
            206    //注銷回調函數
            207    InternetSetStatusCallback(p->hInternet, NULL);
            208    InternetCloseHandle(p->hInternet);
            209 
            210    return TRUE;
            211 }
            212 
            213 //------------------------------------------------------------------------------------
            214 DWORD WINAPI AsyncWinINet::AsyncCallbackThread(LPVOID lpParameter)
            215 {
            216    thread_info *= (thread_info*)lpParameter;
            217    InternetSetStatusCallback(p->hInternet, AsyncWinINet::AsyncInternetCallback);
            218 
            219    //通知子線程回調函數設置成功,子線程可以繼續工作
            220    SetEvent(p->hEvent[0]);
            221 
            222    //等待用戶終止事件或者子線程結束事件
            223    //子線程結束前需要設置子線程結束事件,并等待回調線程結束
            224    WaitForSingleObject(p->hEvent[2], INFINITE);
            225 
            226    return 0;
            227 }
            228 
            229 //----------------------------------------------------------------------------
            230 VOID CALLBACK AsyncWinINet::AsyncInternetCallback(HINTERNET hInternet,
            231     DWORD dwContext,
            232     DWORD dwInternetStatus,
            233     LPVOID lpvStatusInformation,
            234     DWORD dwStatusInformationLength)
            235 {
            236    thread_info* p = (thread_info*)dwContext;
            237   
            238    //在我們的應用中,我們只關心下面三個狀態
            239    switch(dwInternetStatus)
            240    {
            241    //句柄被創建
            242    case INTERNET_STATUS_HANDLE_CREATED:
            243     p->hFile = (HINTERNET)(((LPINTERNET_ASYNC_RESULT)
            244      (lpvStatusInformation))->dwResult);
            245     break;
            246   
            247    //句柄被關閉
            248    case INTERNET_STATUS_HANDLE_CLOSING:
            249     SetEvent(p->hEvent[1]);
            250     break;
            251 
            252    //一個請求完成,比如一次句柄創建的請求,或者一次讀數據的請求
            253    case INTERNET_STATUS_REQUEST_COMPLETE:
            254     if (ERROR_SUCCESS == ((LPINTERNET_ASYNC_RESULT)
            255      (lpvStatusInformation))->dwError)
            256     { 
            257      //設置句柄被創建事件或者讀數據成功完成事件
            258      SetEvent(p->hEvent[0]);
            259     }
            260     else
            261     { 
            262      //如果發生錯誤,則設置子線程退出事件 這里也是一個陷阱,經常會忽視處理這個錯誤,
            263      SetEvent(p->hEvent[2]);
            264     }
            265     break;
            266 
            267    case INTERNET_STATUS_CONNECTION_CLOSED:
            268     SetEvent(p->hEvent[2]);
            269     break;
            270 
            271    }
            272 }
            273 
            274 //--------------------------------------------------------------------
            275 BOOL AsyncWinINet::WaitExitEvent(thread_info *p)
            276 {
            277    DWORD dwRet = WaitForMultipleObjects(3, p->hEvent, FALSE, INFINITE);
            278   
            279    switch (dwRet)
            280    {
            281    case WAIT_OBJECT_0://句柄被創建事件或者讀數據請求成功完成事件
            282    case WAIT_OBJECT_0+1://句柄被關閉事件
            283    case WAIT_OBJECT_0+2://用戶要求終止子線程事件或者發生錯誤事件
            284     break;
            285    }
            286    return WAIT_OBJECT_0 != dwRet;
            287 }
            288 

            posted on 2009-05-17 16:33 Benjamin 閱讀(11753) 評論(15)  編輯 收藏 引用 所屬分類: VC

            評論

            # 我暈就是太崇拜!!!  回復  更多評論   

            暫時失去意識。
            2009-09-11 20:09 | 感嘆12345678

            # re: WinInet編程中如何使用異步  回復  更多評論   

            寫的非常不錯,感謝!
            2009-12-18 14:53 | xuqs

            # re: WinInet編程中如何使用異步  回復  更多評論   

            寫得很好,給我幫助很大,謝謝!
            2010-08-19 17:36 | lvcayu

            # re: WinInet編程中如何使用異步  回復  更多評論   

            請問有代碼工程嗎,發給我一份好嗎?267358440@qq.com,謝謝您了!
            2010-08-28 17:43 | 學習

            # re: WinInet編程中如何使用異步  回復  更多評論   

            Wince下異步使用InternetReadFileEx就不可以,lz說可以,不知是否有試驗過,應該改為InternetReadFileExA才可
            2011-04-18 11:28 | 4321

            # re: WinInet編程中如何使用異步  回復  更多評論   

            @4321
            僅僅WinCE下InternetReadFileEx未實現而已
            2011-04-18 12:37 | 溪流

            # re: WinInet編程中如何使用異步  回復  更多評論   

            Wince下我發現句柄關閉時回調函數也沒有
            InternetStates:70 即INTERNET_STATUS_HANDLE_CLOSING,這個該如何解決
            2011-04-18 17:13 | 4321

            # re: WinInet編程中如何使用異步  回復  更多評論   

            CE或mobile下的異步要用InternetReadFileExA,也可以多線程實現;
            2011-04-18 22:36 | Benjamin

            # re: WinInet編程中如何使用異步  回復  更多評論   

            @Benjamin
            多線程不是很好吧,要是在多線程的同步下讀取數據的函數阻塞了會把線程給卡死,強制退出線程問題多多啊。
            還是想問
            Wince下句柄關閉時回調函數沒有接收到
            InternetStates:70 即INTERNET_STATUS_HANDLE_CLOSING 消息,這個該怎么解決
            2011-04-19 10:05 | 4321

            # re: WinInet編程中如何使用異步  回復  更多評論   

            這些代碼怎么寫的啊,好難
            2011-07-19 17:36 |

            # re: WinInet編程中如何使用異步  回復  更多評論   

            http://blog.csdn.net/achellies/article/details/4569456
            2011-09-27 18:28 | daixi

            # re: WinInet編程中如何使用異步  回復  更多評論   

            不好意思,直接Ctrl+Enter就發出去了,悲摧。。。

            http://blog.csdn.net/achellies/article/details/4569456

            這篇文章里面說,直接使用InternetConenect會有問題,不知道博主有研究過嗎?我想多學習一下,謝謝。。
            2011-09-27 18:29 | daixi

            # re: WinInet編程中如何使用異步  回復  更多評論   

            作者的思路有嚴重問題,完全沒有利用到異步的優勢,用WaitForSingleObject等在那里,跟同步有啥區別啊,還不如用同步方式處理了。回調函數難道就是給你用來設置事件的?

            真正的異步是不需要等的,數據的處理放在回調中進行,完全不用等待。
            2012-02-20 16:14 | famu

            # re: WinInet編程中如何使用異步  回復  更多評論   

            @famu
            可以讓線程掛起,釋放cpu資源。
            2013-01-07 10:43 | yoooooo

            # re: WinInet編程中如何使用異步  回復  更多評論   

            說是異步,其實還是WAIT等同步方式,此乃非真正的異步
            2015-09-08 11:01 | 無名氏
            久久久久综合国产欧美一区二区| 久久久人妻精品无码一区| 高清免费久久午夜精品| 日本精品久久久久中文字幕| 久久夜色撩人精品国产| 久久99亚洲网美利坚合众国| 美女写真久久影院| 久久免费视频1| 亚洲国产精品婷婷久久| 欧美激情一区二区久久久| 久久se精品一区精品二区| 一本大道久久东京热无码AV| 2021久久国自产拍精品| 久久精品国产亚洲AV不卡| 国产精品99久久久久久www| 亚洲AV无码久久精品蜜桃| 久久精品国产清自在天天线| 久久综合香蕉国产蜜臀AV| 亚洲国产成人久久综合碰| www.久久热.com| 亚洲AV日韩精品久久久久 | 国产99精品久久| 久久精品国产欧美日韩99热| 99久久免费只有精品国产| 久久99精品久久久久久hb无码| 亚洲国产成人精品91久久久| 99久久国产综合精品网成人影院| 国产成年无码久久久久毛片 | 国产精品岛国久久久久| 亚洲色大成网站www久久九| 亚洲精品久久久www| 久久国产成人午夜AV影院| AAA级久久久精品无码片| 亚洲精品乱码久久久久久 | 中文字幕成人精品久久不卡| 久久精品中文无码资源站| 97精品伊人久久久大香线蕉| 久久天天躁狠狠躁夜夜avapp| 伊人精品久久久久7777| 伊人久久大香线蕉精品不卡 | 久久精品国产亚洲av麻豆蜜芽|