代码之家  ›  专栏  ›  技术社区  ›  bpeikes

WinInet和InternetOpen

  •  0
  • bpeikes  · 技术社区  · 8 年前

    文档说明可以多次调用InternetOpen而不会出现任何问题。我的问题是,我应该多次调用InternetCloseHandle返回的句柄吗?

    例如,我有一个我调用的类 CAPIRequestContext ,它有一个由InternetOpen返回的句柄。我的每个请求都有自己的副本。现在,我在析构函数中调用InternetCloseHandle,因此它被多次调用。

    我想知道以下情况是否会导致问题: 线程A创建一个 CAPIRequestObject 它调用InternetOpen并存储句柄。线程B也这样做,但在线程A退出之前就超出了范围,因此线程B在自己的函数中调用析构函数 CAPI请求对象 ,它调用 InternetCloseHandle InternetOpen返回的句柄。

    我应该在类的析构函数中删除对InternetCloseHandle的调用吗?至少对于InternetHandle?我假设应该为HttpOpenRequest返回的句柄调用InternetCloseHandle。

    关于InternetConnect返回的句柄,我有类似的问题。这些句柄是共享的吗?

    下面是一些示例代码,减去一些我认为与问题无关的外部代码:

    class CAPIClient;
    class CAPIRequest
    {
    public:
         CAPIRequestContext()
         {
             m_hConn = NULL;
             m_hInternet = NULL;
             m_hRequest = NULL;
         }
    
         ~CAPIRequestContext()
         {
             if (m_hRequest) InternetCloseHandle(m_hRequest);
             if (m_hConn) InternetCloseHandle(m_hConn);
             if (m_hInternet) InternetCloseHandle(m_hInternet);
         }
    
         bool Init(const CAPIClient &client, const std::string &uri, const std::string &method)
         {
              ATLASSERT(!(m_hInternet || m_hConn || m_hRequest));
              if (m_hInternet || m_hConn || m_hRequest) throw std::exception("Cannot init request more than once.");
    
              bool success = false;
              m_AuthToken = *client.m_pAuthToken;
              URI = uri;
              m_hInternet = InternetOpen("MyApp", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    DWORD requestTimeout = 60 * 1000; // Set timeout to 60 seconds instead of 30
    
              if (m_hInternet)
              {  
                    InternetSetOption(m_hInternet, INTERNET_OPTION_RECEIVE_TIMEOUT, &requestTimeout, sizeof(requestTimeout));
                    m_hConn = InternetConnect(m_hInternet, (LPSTR)client.m_host.c_str(), client.m_port, NULL, NULL, INTERNET_SERVICE_HTTP, 0, (DWORD_PTR)this);
                    if (m_hConn) {
                          m_hRequest = HttpOpenRequest(m_hConn, method.c_str(), uri.c_str(), "HTTP/1.1", NULL, NULL, client.GetOpenRequestFlags(), 0);
                    }
                    if (m_hRequest)
                    {
                        success = true;
                    }
              }
           return success;
         }      
    }
    
        // There are additional calls like 
        // SendRequest
        // GetData
        // GetFullResponse
    
    private:
         // Added these methods to make sure I'm not copying the handles
    enter code here
         CAPIRequestContext(const CAPIRequestContext &other) = delete;
         CAPIRequestContext& operator=(const CAPIRequestContext& other) = delete;
    
    private:
          HINTERNET m_hInternet;
          HINTERNET m_hConn;
          HINTERNET m_hRequest;
    
    }
    
    1 回复  |  直到 8 年前
        1
  •  1
  •   Remy Lebeau    8 年前

    文档说明可以多次调用InternetOpen而不会出现任何问题。我的问题是,我应该多次调用InternetCloseHandle返回的句柄吗?

    是的,如中所述 InternetOpen() 文档:

    调用应用程序完成使用 HINTERNET 句柄由返回 InternetOpen , 必须使用 InternetCloseHandle 作用 .

    例如,我有一个我调用的类 CAPIRequestContext ,它有一个句柄,由返回 Internet打开 .我的每个请求都有自己的副本。现在,我打电话给 Internet关闭句柄 在析构函数中,因此它被多次调用。

    如果类的每个实例都调用 Internet打开() ,或以其他方式获得唯一 HINTERNET公司 .

    然而 ,请注意这样的类需要实现 Rule of Three 基本上,如果必须提供析构函数来释放资源,还需要提供复制构造函数和复制赋值运算符。

    但是,你不能打电话 InternetCloseHandle() 在同一时间多次 HINTERNET公司 ,所以不能有多个 CAPI请求上下文 使用相同的 HINTERNET公司 他们都在打电话 Internet关闭句柄() 1. 。因此,复制构造函数和复制赋值运算符必须:

    1. 取得所有权 HINTERNET公司 从源头 CAPI请求上下文 正在被复制。

    2. 完全禁用以防止复制 CAPI请求上下文 到另一个。

    在你的情况下,我会选择#2。

    1. :您需要一个每个实例的标志,指示哪些实例可以调用它,哪些实例不能调用它。但这不是一个好的课堂设计。如果您需要共享 HINTERNET公司 ,您应该实现引用计数语义,例如 std::shared_ptr .

    我想知道以下是否会导致问题:线程A创建了一个调用InternetOpen并存储句柄的CAPIRequestObject。线程B也这样做,但在线程A退出之前就超出了范围,因此线程B在自己的CAPIRequestObject中调用析构函数,后者在InternetOpen返回的句柄上调用InternetCloseHandle。

    这是非常安全的,只要每个 CAPIRequestObject 有自己的 HINTERNET公司 .

    我应该在类的析构函数中删除对InternetCloseHandle的调用吗?

    否,如果每个类实例都具有唯一的 HINTERNET公司 .

    我假设应该为HttpOpenRequest返回的句柄调用InternetCloseHandle。

    是的,正如 HttpOpenRequest() 文档:

    调用应用程序完成使用 HINTERNET公司 句柄由返回 HttpOpenRequest , 必须使用 Internet关闭句柄 作用 .

    关于InternetConnect返回的句柄,我有类似的问题。这些句柄是共享的吗?

    每个 HINTERNET公司 必须单独关闭。

    推荐文章