📄 stockquotes_.cpp
字号:
MB_ICONEXCLAMATION | MB_OK);
}
e->Delete();
}
DelSession();
g_bUpdating = false;
Unlock();
return S_OK;
}
// Helper function to shutdown the updating process, terminates any pending
// updates.
//
void CStockQuotes::ShutdownUpdating()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
g_bStopUpdating = true;
if (m_pINetSession)
m_pINetSession->Close();
TermNotifyThread();
DelSession(false);
g_bStopUpdating = false;
}
// Helper function to close and delete session.
//
void CStockQuotes::DelSession(bool bCloseFirst)
{
if (bCloseFirst && m_pINetSession)
m_pINetSession->Close();
delete m_pINetSession;
m_pINetSession = 0;
}
// Helper function to terminate notification thread.
// Waits for thread to end, otherwise we could get a memory leak when things
// shutdown.
//
void CStockQuotes::TermNotifyThread()
{
if (m_pStockUpdateNotify)
{
m_pStockUpdateNotify->PostThreadMessage(WM_QUIT, 0, 0);
::WaitForSingleObject(m_pStockUpdateNotify->m_hThread, 30000);
}
}
// Write CString to stream.
//
//
void CStockQuotes::SaveString(COleStreamFile& strmFile, CString& s)
{
int size;
LPTSTR psz;
size = s.GetLength();
psz = s.LockBuffer();
strmFile.Write(&size, sizeof(size)); // size of string.
strmFile.Write(psz, size); // string.
s.UnlockBuffer();
}
// Read CString from stream.
//
//
void CStockQuotes::LoadString(COleStreamFile& strmFile, CString& s)
{
TCHAR buf[128]; // more than enough for a stock symbol.
int strSize = 0;
memset(buf, 0, sizeof(TCHAR)*128);
strmFile.Read(&strSize, sizeof(strSize)); // size of string.
strmFile.Read(buf, strSize);
s = buf;
}
// debugging function.
// format:
// <symbol>:<price> <change>
void CStockQuotes::PrintStocks()
{
#if 0 // set to 1 to use.
for (CStockListIter i = m_stockList.begin();
i != m_stockList.end(); i++)
{
CStock s = *i;
std::cout << (LPCTSTR)s.GetSymbol() << _T(":") << (LPCTSTR)s.GetCurrent() << _T(" ")
<< (LPCTSTR)s.GetChange() << std::endl;
}
#endif
}
///////////////////////////////////////////////////////////////////////////////
// CStockQuoteSource
//
// StripTags() rips through a buffer and removes HTML tags from it.
// The function uses a static variable to remember its state in case
// a HTML tag spans a buffer boundary.
//
void CStockQuoteSource::StripTags(LPTSTR pszBuffer)
{
LPTSTR pszSource = pszBuffer;
LPTSTR pszDest = pszBuffer;
while (*pszSource != '\0')
{
if (m_bInTag)
{
if (*pszSource == '>')
m_bInTag = FALSE;
pszSource++;
}
else
{
if (*pszSource == '<')
m_bInTag = TRUE;
else
{
*pszDest = *pszSource;
pszDest++;
}
pszSource++;
}
}
*pszDest = '\0';
}
// Strips extra WS such that there are no 2 or more adjacent WS characters.
// Don't add space after the '/' character.
//
void CStockQuoteSource::StripExtraSpace(CString& s)
{
CString temp;
int size = s.GetLength();
for (int i = 0; i < size; i++)
{
int x = i;
while (i < size && _istspace(s[i]))
i++;
if ((i - x > 0) &&
(s[x-1] != _T('/') && s[x-1] != _T('+') && s[x-1] != _T('-')))
temp += _T(' ');
temp += s[i];
}
s = temp;
}
// Do the download of the stock info. Several types of exceptions may be
// thrown. Just return 0 on an exception unless it is a CInternetException,
// then pass it on up.
//
bool CStockQuoteSource::DownloadStockInfo(CInternetSession& session, CStock& stock)
{
CString strURL; // URL to connect to.
DWORD dwHttpRequestFlags =
INTERNET_FLAG_EXISTING_CONNECT | INTERNET_FLAG_NO_AUTO_REDIRECT;
const TCHAR szHeaders[] =
_T("Accept: text/*\r\nUser-Agent: Stock Quotes\r\n");
CHttpConnection* pServer = NULL;
CHttpFile* pFile = NULL;
bool retval = true;
m_bInTag = false;
// construct URL to connect to.
//
strURL=GetURL();
strURL+=stock.GetSymbol();
CString strServerName;
CString strObject;
INTERNET_PORT nPort;
DWORD dwServiceType;
try
{
// Handle upto 5 redirections otherwise bail out
for(int i = 0; i < 5; ++i)
{
if (!AfxParseURL((LPCTSTR)strURL, dwServiceType, strServerName, strObject, nPort) ||
dwServiceType != INTERNET_SERVICE_HTTP)
{
throw 1;
}
if (g_bStopUpdating)
throw 99;
pServer = session.GetHttpConnection(strServerName, nPort);
if (g_bStopUpdating)
throw 99;
pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET,
strObject, NULL, 1, NULL, NULL, dwHttpRequestFlags);
pFile->AddRequestHeaders(szHeaders);
pFile->SendRequest();
if (g_bStopUpdating)
throw 99;
DWORD dwRet;
pFile->QueryInfoStatusCode(dwRet);
// if access was denied exit out.
if (dwRet == HTTP_STATUS_DENIED)
{
throw 1;
}
// were we redirected?
// these response status codes come from WININET.H
if (g_bStopUpdating)
throw 99;
if (dwRet == HTTP_STATUS_MOVED ||
dwRet == HTTP_STATUS_REDIRECT ||
dwRet == HTTP_STATUS_REDIRECT_METHOD)
{
CString strNewLocation;
pFile->QueryInfo(HTTP_QUERY_RAW_HEADERS_CRLF, strNewLocation);
int nPlace = strNewLocation.Find(_T("Location: "));
if (nPlace == -1)
{
throw 2;
}
strNewLocation = strNewLocation.Mid(nPlace + 10);
if(strNewLocation[0] == _T('/'))
{
strURL=_T("http://");
strURL+=strServerName;
}
else
strURL=_T("");
nPlace = strNewLocation.Find(_T('\n'));
if (nPlace > 0)
strNewLocation = strNewLocation.Left(nPlace);
// close up the redirected site
pFile->Close();
delete pFile;
pServer->Close();
delete pServer;
strURL+=strNewLocation;
}
else
break;
}
retval = SetStockInfo(pFile, stock);
pFile->Close();
pServer->Close();
}
catch(CInternetException* e)
{
if (pFile != NULL)
delete pFile;
if (pServer != NULL)
delete pServer;
retval = false;
throw e;
}
catch(...)
{
retval = false;
}
if (pFile != NULL)
delete pFile;
if (pServer != NULL)
delete pServer;
return retval;
}
// Read data from net and attempt to find key words that identify where
// the stock info is.
//
bool CStockQuoteSource::SetStockInfoHelper(CHttpFile* pFile, CStock& stock, TCHAR* szCurText, TCHAR* szChangeText)
{
CString cur;
CString change;
int cnt = 0;
TCHAR sz[1024];
while (!g_bStopUpdating && pFile->ReadString(sz, 1023) && cnt != 2)
{
StripTags(sz);
if (cnt == 0 && ParseStockInfo(sz, szCurText, cur))
{
stock.SetCurrent(cur);
cnt++;
}
// assume change value comes after current.
//
if (cnt == 1 && ParseStockInfo(sz, szChangeText, change))
{
stock.SetChange(change);
cnt++;
}
}
return cnt == 2;
}
// Using the szHeader member try to find the "key word" that identifies the
// stock info. If found then read until we run into something other than
// a space, digit, +, -, or / characters. If this algorithm does not
// work for your site, just override.
//
bool CStockQuoteSource::ParseStockInfo(TCHAR* szBuf, TCHAR* szHeader, CString& strResult)
{
TCHAR* temp = _tcsstr(szBuf, szHeader);
if (temp)
{
temp += _tcslen(szHeader);
// skip leading WS so the first character to be processed can be checked for
// validity more accurately.
while (*temp && _istspace(*temp)) temp++;
}
while(temp && *temp)
{
if (_istdigit(*temp) || _istspace(*temp) || *temp == '+' || *temp == '-' || *temp == '/' || *temp == '.')
strResult += *temp;
else
break;
temp++;
}
if (!strResult.IsEmpty())
{
strResult.TrimLeft();
strResult.TrimRight();
StripExtraSpace(strResult);
return true;
}
return false;
}
// This helper function just checks to see if the given url ends with a '='.
// If is does then there is nothing else to do. Otherwise append the given tail
// to the url.
//
//
//
void CStockQuoteSource::SetURLHelper(const CString& strURL,
const CString& strURLTail)
{
m_strURL = strURL;
if (strURL[strURL.GetLength()-1] != '=')
m_strURL += strURLTail;
}
//////////////////////////////////////////////////////////////////////////////
// CSQSMSInvestor
//
bool CSQSMSInvestor::SetStockInfo(CHttpFile* pFile, CStock& stock)
{
return SetStockInfoHelper(pFile, stock, _T("Last"), _T("Change"));
}
bool CSQSMSInvestor::ParseStockInfo(TCHAR* szBuf, TCHAR* szHeader, CString& strResult)
{
TCHAR* temp;
if (!m_bFoundHeader)
{
temp = _tcsstr(szBuf, szHeader);
if (temp)
{
temp += _tcslen(szHeader);
m_bFoundHeader = true;
}
}
else
temp = szBuf;
if (temp)
{
// skip leading WS so the first character to be processed can be checked for
// validity more accurately.
// also skip everything up to first $.
bool bNeg = false;
while (*temp && !_istdigit(*temp) && *temp!= '.' && *temp !='-')
++temp;
if (*temp == '-')
bNeg = true;
if (*temp && bNeg)
{
++temp;
strResult += _T("-");
}
while(temp && *temp)
{
if (_istdigit(*temp) || *temp == '.')
strResult += *temp;
else
break;
temp++;
}
if (!strResult.IsEmpty())
{
strResult.TrimLeft();
strResult.TrimRight();
StripExtraSpace(strResult);
m_bFoundHeader = false;
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////////
// ISAPI Dll Stock Source
//
bool CSQSISAPIDll::SetStockInfo(CHttpFile* pFile, CStock& stock)
{
return SetStockInfoHelper(pFile, stock, _T("Current:"), _T("Change:"));
}
//////////////////////////////////////////////////////////////////////////////
// CSQSList
//
void CSQSList::Init()
{
push_back(new CSQSMSInvestor);
push_back(new CSQSISAPIDll);
}
CStockQuoteSource* CSQSList::GetMSInvestor()
{
for (iterator i = begin(); i != end(); i++)
if ((*i)->IsMSInvestor())
return *i;
return 0;
}
CStockQuoteSource* CSQSList::GetStockSourceISAPIDll()
{
for (iterator i = begin(); i != end(); i++)
if ((*i)->IsISAPIDll())
return *i;
return 0;
};
void CSQSList::Cleanup()
{
for (iterator i = begin(); i != end(); i++)
delete *i;
clear();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -