WinInet 和 InternetOpen
WinInet and InternetOpen
文档指出可以多次调用 InternetOpen 而不会出现任何问题。我的问题是我应该多次调用它返回的句柄上的 InternetCloseHandle 吗?
例如,我有一个 class,我称之为 CAPIRequestContext
,它有一个由 InternetOpen 返回的句柄。我的每一个请求都有它自己的副本。现在,我在析构函数中调用了 InternetCloseHandle,因此它被调用了多次。
我想知道以下情况是否会导致问题:
线程 A 创建一个 CAPIRequestObject
调用 InternetOpen 并存储句柄。线程 B 做同样的事情,但在线程 A 退出之前超出范围,因此线程 B 在它自己的 CAPIRequestObject
中调用析构函数,它在 InternetOpen 返回的句柄上调用 InternetCloseHandle
。
我是否应该在 class 的析构函数中删除对 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;
}
The documentation states that InternetOpen can be called multiple times without any issues. My question though is should I be calling InternetCloseHandle on handle returned by it multiple times?
是的,如 InternetOpen()
文档所述:
After the calling application has finished using the HINTERNET
handle returned by InternetOpen
, it must be closed using the InternetCloseHandle
function.
For example, I have a class I call CAPIRequestContext
, which has a handle which is returned by InternetOpen
. Each one of my requests has it's own copy. Right now, I call InternetCloseHandle
in the destructor, so it gets called multiple times.
如果 class 的每个实例调用 InternetOpen()
,或者以其他方式获得唯一 HINTERNET
.
的所有权,那将是一个正确的实现
但是,请注意这样的 class 需要实现 Rule of Three。基本上,如果你必须提供一个析构函数来释放资源,你还需要提供一个复制构造函数和复制赋值运算符。
但是,你不能在同一个 HINTERNET
上多次调用 InternetCloseHandle()
,所以你不能有多个 CAPIRequestContext
使用同一个 HINTERNET
和所有其中调用 InternetCloseHandle()
1。因此,您的复制构造函数和复制赋值运算符必须:
从正在复制的来源 CAPIRequestContext
获取 HINTERNET
的所有权。
完全禁用以防止将一个 CAPIRequestContext
复制到另一个。
在你的情况下,我会选择#2。
1:您需要一个实例标志,指示哪个实例可以调用它,哪些不能。但是这样class设计的不好。如果您需要共享一个 HINTERNET
,您应该改为实现引用计数语义,例如 std::shared_ptr
.
提供的
I'm wondering if the following could cause issues: Thread A creates a CAPIRequestObject which calls InternetOpen and stores the handle. Thread B does the same, but then goes out of scope before Thread A exits, so Thread B calls the destructor in it's own CAPIRequestObject, which calls InternetCloseHandle on the handle returned by InternetOpen.
这是绝对安全的,前提是每个 CAPIRequestObject
都有自己的 HINTERNET
。
Should I remove the call to InternetCloseHandle in the destructors of my class?
否,如果每个 class 实例都拥有唯一的 HINTERNET
。
I assume I should call InternetCloseHandle for the handle returned by HttpOpenRequest.
是的,如 HttpOpenRequest()
文档中所述:
After the calling application has finished using the HINTERNET
handle returned by HttpOpenRequest
, it must be closed using the InternetCloseHandle
function.
I have similar questions regarding the handle returned by InternetConnect. Are these handles shared?
每个 HINTERNET
必须单独关闭。
文档指出可以多次调用 InternetOpen 而不会出现任何问题。我的问题是我应该多次调用它返回的句柄上的 InternetCloseHandle 吗?
例如,我有一个 class,我称之为 CAPIRequestContext
,它有一个由 InternetOpen 返回的句柄。我的每一个请求都有它自己的副本。现在,我在析构函数中调用了 InternetCloseHandle,因此它被调用了多次。
我想知道以下情况是否会导致问题:
线程 A 创建一个 CAPIRequestObject
调用 InternetOpen 并存储句柄。线程 B 做同样的事情,但在线程 A 退出之前超出范围,因此线程 B 在它自己的 CAPIRequestObject
中调用析构函数,它在 InternetOpen 返回的句柄上调用 InternetCloseHandle
。
我是否应该在 class 的析构函数中删除对 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;
}
The documentation states that InternetOpen can be called multiple times without any issues. My question though is should I be calling InternetCloseHandle on handle returned by it multiple times?
是的,如 InternetOpen()
文档所述:
After the calling application has finished using the
HINTERNET
handle returned byInternetOpen
, it must be closed using theInternetCloseHandle
function.
For example, I have a class I call
CAPIRequestContext
, which has a handle which is returned byInternetOpen
. Each one of my requests has it's own copy. Right now, I callInternetCloseHandle
in the destructor, so it gets called multiple times.
如果 class 的每个实例调用 InternetOpen()
,或者以其他方式获得唯一 HINTERNET
.
但是,请注意这样的 class 需要实现 Rule of Three。基本上,如果你必须提供一个析构函数来释放资源,你还需要提供一个复制构造函数和复制赋值运算符。
但是,你不能在同一个 HINTERNET
上多次调用 InternetCloseHandle()
,所以你不能有多个 CAPIRequestContext
使用同一个 HINTERNET
和所有其中调用 InternetCloseHandle()
1。因此,您的复制构造函数和复制赋值运算符必须:
从正在复制的来源
CAPIRequestContext
获取HINTERNET
的所有权。完全禁用以防止将一个
CAPIRequestContext
复制到另一个。
在你的情况下,我会选择#2。
1:您需要一个实例标志,指示哪个实例可以调用它,哪些不能。但是这样class设计的不好。如果您需要共享一个 HINTERNET
,您应该改为实现引用计数语义,例如 std::shared_ptr
.
I'm wondering if the following could cause issues: Thread A creates a CAPIRequestObject which calls InternetOpen and stores the handle. Thread B does the same, but then goes out of scope before Thread A exits, so Thread B calls the destructor in it's own CAPIRequestObject, which calls InternetCloseHandle on the handle returned by InternetOpen.
这是绝对安全的,前提是每个 CAPIRequestObject
都有自己的 HINTERNET
。
Should I remove the call to InternetCloseHandle in the destructors of my class?
否,如果每个 class 实例都拥有唯一的 HINTERNET
。
I assume I should call InternetCloseHandle for the handle returned by HttpOpenRequest.
是的,如 HttpOpenRequest()
文档中所述:
After the calling application has finished using the
HINTERNET
handle returned byHttpOpenRequest
, it must be closed using theInternetCloseHandle
function.
I have similar questions regarding the handle returned by InternetConnect. Are these handles shared?
每个 HINTERNET
必须单独关闭。