• 天哪,我遇上了一个windows api BUG! 并贡献一个完全支持代理服务器的http文件下载VC代码


        好吧,我遇上了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;

    }

         

     
     
     
     
     
     
  • 相关阅读:
    统一身份认证(CAS)客户端测试获取信息代码
    常用的java工具类
    windows 批处理(bat)中执行程序后不等待直接退出(cmd中新进程执行程序)
    持续交付的八条原则,你能做到几条?(转)
    灵动标签调用栏目导航技巧
    .net网络编程(2)网络适配器
    Property Value Inheritance Tip(1)
    排序算法补充
    编码参考(Encoding)
    .net网络编程(3)Socket基础
  • 原文地址:https://www.cnblogs.com/haoxiaobo/p/2317559.html
Copyright © 2020-2023  润新知