天哪,我遇上了一個windows api BUG! 並貢獻一個完全支援Proxy 伺服器的http檔案下載VC代碼

來源:互聯網
上載者:User

    好吧,我遇上了windows api的bug...

 

     一開始程式是採用了CInternetSession來開啟一個Session,然後再用OpenUrl來開啟一個CHttpFile檔案. 這個程式一直工作得很好,只要ie能上網,它就能下載。如果用Proxy 伺服器,只需要在ie中設定好即可。如果Proxy 伺服器需要口令,只需要先在ie中訪問頁面,輸入口令,並選擇儲存口令,這個程式就也能正常透過代理串連了。

    直到有一天,它被安裝在了一台ie6的windows xp機器上,它不能工作了。

    因為 CInternetSession::OpenUrl方法調用了InternetOperUrl api函數,而InternetOperUrl函數,有個BUG.

     InternetOperUrl在IE6的環境下,除非Proxy 伺服器的使用者名稱與口令與目前使用者的使用者名稱與口令一致,否則他不能透過Proxy 伺服器串連http檔案。

    為什麼我知道這是個BUG? 因為安裝了ie8之後, InternetOperUrl就能正常工作了——只要在ie通過代理上網時,輸入Proxy 伺服器口令時選擇一下“儲存我的口令”,InternetOperUrl就也能正常串連了。

    在ie6下, InternetOperUrl的似乎是總是用當前登入電腦的使用者名稱與口令向Proxy 伺服器驗證。這明顯是一個錯誤。後來他們修好了。

 

    這個問題讓我折騰了三天,安裝了n台不同版本的windows和ie環境,測試了各種各樣的程式,我都幾乎準備要動用我的msdn支援人員時, 終於確認了問題原因。

    知道了原因就好辦了。只需要繞開mfc的這個問題,直接用幾個底層api就可以正常工作了。下面是可以正常工作的代碼,一共支援三種不同的Proxy 伺服器設定:0 用ie的設定(包括ie儲存了的密碼),1,堅決不用代理,一定要直連。2,用本程式指定的代理。

 iProxyMode 、bProxyNeedPassword、proxyinfo、sProxyUserName、sProxyPassword等是全域變數,你可以在調用這個函數之前準備好這些變數。

BOOL GetHttpFile(LPCTSTR psUrl, LPCTSTR psLocalFile, CString &sErrMg)

{
    BOOL b;
    BOOL bOK = TRUE;
    DWORD dwServiceType;
    CString strServer;
    CString strObject;
    INTERNET_PORT nPort;

    BOOL bParsed = AfxParseURL(psUrl, dwServiceType, strServer, strObject, nPort);
    if (!bParsed)
    {
        sErrMg = "遠程檔案地址格式不對!";
        return FALSE;
    }

    HINTERNET m_hInternet = InternetOpen(
        "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; InfoPath.1)", 
        INTERNET_OPEN_TYPE_PRECONFIG,
        NULL,
        NULL, 0);

    if (FALSE == m_hInternet)
    {
        InternetCloseHandle(m_hInternet);
        sErrMg.Format("建立網路會話 %s 失敗", psUrl);
        return FALSE;
    }

    if (iProxyMode != 0)
    {
        b = InternetSetOption (NULL, INTERNET_OPTION_PROXY, (LPVOID) &proxyinfo, sizeof (proxyinfo));
    }

    HINTERNET m_hConnection = InternetConnect(
        m_hInternet, 
        strServer,
        nPort, 
        NULL, 
        NULL,
        INTERNET_SERVICE_HTTP, 
        INTERNET_FLAG_NO_UI, 
        NULL);

    if (FALSE == m_hConnection)
    {
        InternetCloseHandle(m_hConnection);
        InternetCloseHandle(m_hInternet);
        sErrMg.Format("建立網路連接 %s 失敗", psUrl);
        return FALSE;
    }

    if (iProxyMode == 2 && bProxyNeedPassword)
    {
        DWORD dwUserNameLen = sProxyUserName.GetLength() + 1;
        DWORD dwUserPassLen = sProxyPassword.GetLength() + 1;

        b = InternetSetOption (m_hConnection, INTERNET_OPTION_PROXY_USERNAME, (LPVOID)(LPCTSTR)sProxyUserName, dwUserNameLen);    
        b = InternetSetOption (m_hConnection, INTERNET_OPTION_PROXY_PASSWORD, (LPVOID)(LPCTSTR)sProxyPassword, dwUserPassLen);    
    }

    static LPCTSTR s_szAcceptTypes[] = { _T("*/*"), NULL };

    HINTERNET m_hRequest = HttpOpenRequest(
        m_hConnection, _T("GET"), 
        strObject, 
        _T("HTTP/1.0"), NULL,
        s_szAcceptTypes, 
        INTERNET_FLAG_NO_UI | INTERNET_FLAG_KEEP_CONNECTION, // | ((m_url.GetScheme() == ATL_URL_SCHEME_HTTPS) ? INTERNET_FLAG_SECURE : 0)
        NULL);
    if (FALSE == m_hRequest)
    {
        InternetCloseHandle(m_hRequest);
        InternetCloseHandle(m_hConnection);
        InternetCloseHandle(m_hInternet);
        sErrMg.Format("開啟網路連接 %s 失敗", psUrl);
        return FALSE;
    }

    CString strHeaders;
    //strHeaders.Append(_T("Content-Type: text/xml; charset=utf-8\r\n"));

    b = HttpSendRequest(m_hRequest, strHeaders, (DWORD) strHeaders.GetLength(),        
        NULL, 0);

    if (FALSE == b)
    {
        InternetCloseHandle(m_hRequest);
        InternetCloseHandle(m_hConnection);
        InternetCloseHandle(m_hInternet);
        sErrMg.Format("向伺服器發送請求 %s 失敗", psUrl);
        return FALSE;
    }

    int iStatus = GetInternetRequestStatusCode(m_hRequest);

    if(!(iStatus>= 200&& iStatus<300 ))
    {
        InternetCloseHandle(m_hRequest);
        InternetCloseHandle(m_hConnection);
        InternetCloseHandle(m_hInternet);
        sErrMg.Format("開啟遠程檔案出錯,錯誤碼:%d", iStatus);
        return FALSE;
    }

    byte pData[65535];
    DWORD dwReadedLen;
    DWORD dwWrittenLen;  

    HANDLE hfile = CreateFile(psLocalFile,GENERIC_WRITE,0,0,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0); 
    if (hfile == INVALID_HANDLE_VALUE)  
    {    
        InternetCloseHandle(m_hRequest);
        InternetCloseHandle(m_hConnection);
        InternetCloseHandle(m_hInternet);

        sErrMg.Format("建立本地檔案 %s 失敗", psLocalFile);

        return FALSE;
    }  

    while(1)
    {
        b =  InternetReadFile(m_hRequest, (LPVOID)pData, sizeof(pData), &dwReadedLen);
        if (b == FALSE)
        {
            CloseHandle(hfile);
            InternetCloseHandle(m_hRequest);
            InternetCloseHandle(m_hConnection);
            InternetCloseHandle(m_hInternet);

            sErrMg.Format("讀取檔案 %s 失敗", psUrl);
            return FALSE;
        }
        if(dwReadedLen == 0)
        {
            break;  
        }
        b = WriteFile(hfile, pData, dwReadedLen, &dwWrittenLen,NULL);  
        if (b == FALSE)  
        {  
            CloseHandle(hfile);
            InternetCloseHandle(m_hRequest);
            InternetCloseHandle(m_hConnection);
            InternetCloseHandle(m_hInternet);
            sErrMg.Format("寫入本地檔案 %s 失敗", psLocalFile);
            return FALSE;
        }  

    }

    CloseHandle(hfile);
    InternetCloseHandle(m_hRequest);
    InternetCloseHandle(m_hConnection);
    InternetCloseHandle(m_hInternet);
    sErrMg.Format("下載成功");
    return TRUE;

}

 

     

      
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

Tags Index: