haoxiaobo

从C到C++又到.net, 有一些心得, 和大家交流下...
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

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

 

     一开始程序是采用了CInternetSession来打开一个Session,然后再用OpenUrl来打开一个CHttpFile文件. 这个程序一直工作得很好,只要ie能上网,它就能下载。如果用代理服务器,只需要在ie中设置好即可。如果代理服务器需要口令,只需要先在ie中访问页面,输入口令,并选择保存口令,这个程序就也能正常透过代理连接了。

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

    因为 CInternetSession::OpenUrl方法调用了InternetOperUrl api函数,而InternetOperUrl函数,有个BUG.

     InternetOperUrl在IE6的环境下,除非代理服务器的用户名与口令与当前用户的用户名与口令一致,否则他不能透过代理服务器连接http文件。

    为什么我知道这是个BUG? 因为安装了ie8之后, InternetOperUrl就能正常工作了——只要在ie通过代理上网时,输入代理服务器口令时选择一下“保存我的口令”,InternetOperUrl就也能正常连接了。

    在ie6下, InternetOperUrl的似乎是总是用当前登录电脑的用户名与口令向代理服务器验证。这明显是一个错误。后来他们修好了。

 

    这个问题让我折腾了三天,安装了n台不同版本的windows和ie环境,测试了各种各样的程序,我都几乎准备要动用我的msdn技术支持时, 终于确认了问题原因。

    知道了原因就好办了。只需要绕开mfc的这个问题,直接用几个底层api就可以正常工作了。下面是可以正常工作的代码,一共支持三种不同的代理服务器设置: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;

}