TxITGuy
2005-03-14 22:43:10 UTC
Ok, I almost have everything working the way it should here, but I have an
elusive problem in my code somewhere. Everything runs fine when the control
is loaded and when I execute methods / receive events. However, when I
attempt to shut down the component, it takes as long a 30 seconds to unload
and return control to the hosing app.
This problem is most apparent after calling the following method:
STDMETHODIMP CHTTP::GetRequest(BSTR sDomain, BSTR sDocument, BSTR
sQueryString, BSTR sAccept, BOOL bSecure)
{
char *lpszDomain = NULL;
char *lpszDocument = NULL;
char *lpszQueryString = NULL;
char *lpszAccept = NULL;
char **lplpszAccepts = NULL; //variable to hold "Accepts:" string array.
unsigned int uiRows = 0;
BOOL bRequestSent = FALSE;
HINTERNET hSession = NULL;
HINTERNET hRequest = NULL;
DWORD dwErrorNum = NULL;
string sError;
string sResource;
if(m_bOpen)
{
lpszDomain = _com_util::ConvertBSTRToString(sDomain);
lpszDocument = _com_util::ConvertBSTRToString(sDocument);
lpszQueryString = _com_util::ConvertBSTRToString(sQueryString);
sResource.append(lpszDocument); //concatenate document and
sResource.append(lpszQueryString); //querystring for HttpOpenRequest
lpszAccept = _com_util::ConvertBSTRToString(sAccept);
m_bSecure = bSecure;
hSession = GetInetSession(lpszDomain,INTERNET_SERVICE_HTTP,80);
//assemble and save the current URL string.
SetCurrentURL((const char *) lpszDomain,(const char *) lpszDocument,
bSecure);
if(split(lpszAccept,',',&lplpszAccepts,&uiRows))
{
//convert "Accepts:" string array to a constant pointer for API.
hRequest =
HttpOpenRequest(hSession,"GET",sResource.c_str(),"HTTP/1.1","",(const char**)
lplpszAccepts,INTERNET_FLAG_PRAGMA_NOCACHE,(DWORD) this);
delete [] lpszDomain;
delete [] lpszDocument;
delete [] lpszQueryString;
delete [] lpszAccept;
freearray(lplpszAccepts,uiRows);
if(hRequest != NULL)
{
bRequestSent = HttpSendRequest(hRequest,0,0,0,0);
if(bRequestSent) return S_OK;
else sError.append("Unable to send request.\r\n");
}
else sError.append("Unable to open request.\r\n");
dwErrorNum = GetLastError();
sError.append(InetErrorDesc(dwErrorNum));
}
else
{
dwErrorNum = 0xE0000002;
sError.append("Insufficient memory to complete requested operation.");
}
}
else
{
dwErrorNum = 0xE0000003;
sError.append("HTTP class not ready, please call Open method.");
}
return Error(sError.c_str(),GUID_NULL,dwErrorNum);
}
The above method depends on the following functions:
void freearray(char **sArray, unsigned int uiRows)
{
for (unsigned int i = 0; i < uiRows; i++)
free(sArray[i]);
free(sArray);
}
void CHTTP::SetCurrentURL(const char *lpszDomain, const char *lpszResource,
BOOL bSecure)
{
if(bSecure) m_sURL = "https://";
else m_sURL = "http://";
m_sURL += lpszDomain;
m_sURL += lpszResource;
}
This function is overloaded, but the implementation below is the one called
by the above method.
HINTERNET CHTTP::GetInetSession(char* sDomain, DWORD dwService, int iPort)
{
int iCacheIndex = 0;
//do we have a handle cached that will support the requested session?
for(int iSessionIndex=0;iSessionIndex <=9;iSessionIndex++)
{
if(m_isSessions[iSessionIndex].sAddress == sDomain &&
m_isSessions[iSessionIndex].dwService == dwService &&
m_isSessions[iSessionIndex].iPort == iPort)
{ return m_isSessions[iSessionIndex].hSession; }
}
if(m_iCachedSessions == 10)
{
//the array for cached sessions is full, so we need to close a session
handle
InternetCloseHandle(m_isSessions[m_iReplaceIndex].hSession);
//now, 0 out the closed session handle, and store the new server info.
m_isSessions[m_iReplaceIndex].hSession = 0;
m_isSessions[m_iReplaceIndex].sAddress = sDomain;
m_isSessions[m_iReplaceIndex].dwService = dwService;
m_isSessions[m_iReplaceIndex].iPort = iPort;
//save the index of the closed handle
iCacheIndex = m_iReplaceIndex;
//and update the index to indicate the next replacable handle
//(this way, the oldest handle is always the one replaced).
if(++m_iReplaceIndex == 10) m_iReplaceIndex = 0;
}
else
{
iCacheIndex = m_iCachedSessions++;
m_isSessions[m_iReplaceIndex].sAddress = sDomain;
m_isSessions[m_iReplaceIndex].dwService = dwService;
m_isSessions[m_iReplaceIndex].iPort = iPort;
}
switch(dwService)
{
case INTERNET_SERVICE_HTTP:
m_isSessions[iCacheIndex].hSession =
InternetConnect(m_hInternet,sDomain,iPort,"","",dwService,0,(DWORD) this);
break;
case INTERNET_SERVICE_GOPHER:
m_isSessions[iCacheIndex].hSession =
InternetConnect(m_hInternet,sDomain,iPort,NULL,NULL,dwService,0,(DWORD)
this);
break;
case INTERNET_SERVICE_FTP:
m_isSessions[iCacheIndex].hSession =
InternetConnect(m_hInternet,sDomain,iPort,NULL,NULL,dwService,0,(DWORD)
this);
break;
default:
m_isSessions[iCacheIndex].hSession =
InternetConnect(m_hInternet,sDomain,iPort,"","",dwService,0,(DWORD) this);
break;
}
return m_isSessions[iCacheIndex].hSession;
}
The destructor function contains the following code:
~CHTTP()
{
for(int iIndex=0;iIndex <= 0;iIndex++)
{
if(m_isSessions[iIndex].hSession != 0)
{
InternetSetStatusCallback(m_isSessions[iIndex].hSession,NULL);
InternetCloseHandle(m_isSessions[iIndex].hSession);
}
}
if(m_hInternet != 0)
{
InternetSetStatusCallback(m_hInternet,NULL);
InternetCloseHandle(m_hInternet);
}
}
I have stepped through this code until I can almost see it in my sleep, and
can't find what I'm forgetting to to close or deallocate. I'm hoping some
fresh eyes can tell me why the component is taking so horribly long to unload
itself. By the way, it doesn't get bogged down until well after it finishes
executing the destructor code.
Thanks,
Ben
elusive problem in my code somewhere. Everything runs fine when the control
is loaded and when I execute methods / receive events. However, when I
attempt to shut down the component, it takes as long a 30 seconds to unload
and return control to the hosing app.
This problem is most apparent after calling the following method:
STDMETHODIMP CHTTP::GetRequest(BSTR sDomain, BSTR sDocument, BSTR
sQueryString, BSTR sAccept, BOOL bSecure)
{
char *lpszDomain = NULL;
char *lpszDocument = NULL;
char *lpszQueryString = NULL;
char *lpszAccept = NULL;
char **lplpszAccepts = NULL; //variable to hold "Accepts:" string array.
unsigned int uiRows = 0;
BOOL bRequestSent = FALSE;
HINTERNET hSession = NULL;
HINTERNET hRequest = NULL;
DWORD dwErrorNum = NULL;
string sError;
string sResource;
if(m_bOpen)
{
lpszDomain = _com_util::ConvertBSTRToString(sDomain);
lpszDocument = _com_util::ConvertBSTRToString(sDocument);
lpszQueryString = _com_util::ConvertBSTRToString(sQueryString);
sResource.append(lpszDocument); //concatenate document and
sResource.append(lpszQueryString); //querystring for HttpOpenRequest
lpszAccept = _com_util::ConvertBSTRToString(sAccept);
m_bSecure = bSecure;
hSession = GetInetSession(lpszDomain,INTERNET_SERVICE_HTTP,80);
//assemble and save the current URL string.
SetCurrentURL((const char *) lpszDomain,(const char *) lpszDocument,
bSecure);
if(split(lpszAccept,',',&lplpszAccepts,&uiRows))
{
//convert "Accepts:" string array to a constant pointer for API.
hRequest =
HttpOpenRequest(hSession,"GET",sResource.c_str(),"HTTP/1.1","",(const char**)
lplpszAccepts,INTERNET_FLAG_PRAGMA_NOCACHE,(DWORD) this);
delete [] lpszDomain;
delete [] lpszDocument;
delete [] lpszQueryString;
delete [] lpszAccept;
freearray(lplpszAccepts,uiRows);
if(hRequest != NULL)
{
bRequestSent = HttpSendRequest(hRequest,0,0,0,0);
if(bRequestSent) return S_OK;
else sError.append("Unable to send request.\r\n");
}
else sError.append("Unable to open request.\r\n");
dwErrorNum = GetLastError();
sError.append(InetErrorDesc(dwErrorNum));
}
else
{
dwErrorNum = 0xE0000002;
sError.append("Insufficient memory to complete requested operation.");
}
}
else
{
dwErrorNum = 0xE0000003;
sError.append("HTTP class not ready, please call Open method.");
}
return Error(sError.c_str(),GUID_NULL,dwErrorNum);
}
The above method depends on the following functions:
void freearray(char **sArray, unsigned int uiRows)
{
for (unsigned int i = 0; i < uiRows; i++)
free(sArray[i]);
free(sArray);
}
void CHTTP::SetCurrentURL(const char *lpszDomain, const char *lpszResource,
BOOL bSecure)
{
if(bSecure) m_sURL = "https://";
else m_sURL = "http://";
m_sURL += lpszDomain;
m_sURL += lpszResource;
}
This function is overloaded, but the implementation below is the one called
by the above method.
HINTERNET CHTTP::GetInetSession(char* sDomain, DWORD dwService, int iPort)
{
int iCacheIndex = 0;
//do we have a handle cached that will support the requested session?
for(int iSessionIndex=0;iSessionIndex <=9;iSessionIndex++)
{
if(m_isSessions[iSessionIndex].sAddress == sDomain &&
m_isSessions[iSessionIndex].dwService == dwService &&
m_isSessions[iSessionIndex].iPort == iPort)
{ return m_isSessions[iSessionIndex].hSession; }
}
if(m_iCachedSessions == 10)
{
//the array for cached sessions is full, so we need to close a session
handle
InternetCloseHandle(m_isSessions[m_iReplaceIndex].hSession);
//now, 0 out the closed session handle, and store the new server info.
m_isSessions[m_iReplaceIndex].hSession = 0;
m_isSessions[m_iReplaceIndex].sAddress = sDomain;
m_isSessions[m_iReplaceIndex].dwService = dwService;
m_isSessions[m_iReplaceIndex].iPort = iPort;
//save the index of the closed handle
iCacheIndex = m_iReplaceIndex;
//and update the index to indicate the next replacable handle
//(this way, the oldest handle is always the one replaced).
if(++m_iReplaceIndex == 10) m_iReplaceIndex = 0;
}
else
{
iCacheIndex = m_iCachedSessions++;
m_isSessions[m_iReplaceIndex].sAddress = sDomain;
m_isSessions[m_iReplaceIndex].dwService = dwService;
m_isSessions[m_iReplaceIndex].iPort = iPort;
}
switch(dwService)
{
case INTERNET_SERVICE_HTTP:
m_isSessions[iCacheIndex].hSession =
InternetConnect(m_hInternet,sDomain,iPort,"","",dwService,0,(DWORD) this);
break;
case INTERNET_SERVICE_GOPHER:
m_isSessions[iCacheIndex].hSession =
InternetConnect(m_hInternet,sDomain,iPort,NULL,NULL,dwService,0,(DWORD)
this);
break;
case INTERNET_SERVICE_FTP:
m_isSessions[iCacheIndex].hSession =
InternetConnect(m_hInternet,sDomain,iPort,NULL,NULL,dwService,0,(DWORD)
this);
break;
default:
m_isSessions[iCacheIndex].hSession =
InternetConnect(m_hInternet,sDomain,iPort,"","",dwService,0,(DWORD) this);
break;
}
return m_isSessions[iCacheIndex].hSession;
}
The destructor function contains the following code:
~CHTTP()
{
for(int iIndex=0;iIndex <= 0;iIndex++)
{
if(m_isSessions[iIndex].hSession != 0)
{
InternetSetStatusCallback(m_isSessions[iIndex].hSession,NULL);
InternetCloseHandle(m_isSessions[iIndex].hSession);
}
}
if(m_hInternet != 0)
{
InternetSetStatusCallback(m_hInternet,NULL);
InternetCloseHandle(m_hInternet);
}
}
I have stepped through this code until I can almost see it in my sleep, and
can't find what I'm forgetting to to close or deallocate. I'm hoping some
fresh eyes can tell me why the component is taking so horribly long to unload
itself. By the way, it doesn't get bogged down until well after it finishes
executing the destructor code.
Thanks,
Ben