📄 stockquotes_.cpp
字号:
// StockQuotes_.cpp : Implementation of CStockQuotes
//
// This is a part of the Microsoft Foundation Classes C++ library.
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// This source code is only intended as a supplement to the
// Microsoft Foundation Classes Reference and related
// electronic documentation provided with the library.
// See these sources for detailed information regarding the
// Microsoft Foundation Classes product.
#include "stdafx.h"
#include "stockquotes.h"
#include "StockQuotes_.h"
#include "enumstocks.h"
#include "stockupdatenotify.h"
#pragma warning ( disable : 4018 4239 )
static bool g_bStopUpdating = false; // stop updating now.
bool g_bUpdating = false; // currently updating data from net?
/////////////////////////////////////////////////////////////////////////////
// CEnumStocksAsString
CEnumStocksAsString::~CEnumStocksAsString()
{
// delete all the stock symbols.
//
for (CStocksAsString::iterator i = m_stocksAsString.begin();
i != m_stocksAsString.end(); i++)
{
::SysFreeString(*i);
}
m_stocksAsString.clear();
}
// Return next N stocks, formated in a string.
//
STDMETHODIMP CEnumStocksAsString::Next(ULONG celt, LPOLESTR* rgelt, ULONG* pceltFetched)
{
if (rgelt == NULL || (celt != 1 && pceltFetched == NULL))
return E_POINTER;
if (m_iterCur == m_stocksAsString.end())
return E_FAIL;
ULONG nRem = (ULONG)(m_stocksAsString.end() - m_iterCur);
HRESULT hRes = S_OK;
if (nRem < celt)
hRes = S_FALSE;
ULONG nMin = min(celt, nRem);
if (pceltFetched != NULL)
*pceltFetched = nMin;
while(nMin--)
CCopy::copy(rgelt++, &(*m_iterCur++));
return hRes;
}
// Skip the next N stocks.
//
STDMETHODIMP CEnumStocksAsString::Skip(ULONG celt)
{
if (m_stocksAsString.end() - m_iterCur < celt)
{
m_iterCur = m_stocksAsString.end();
return S_FALSE;
}
m_iterCur += celt;
return S_FALSE;
}
// Start at the begining.
//
STDMETHODIMP CEnumStocksAsString::Reset(void)
{
m_iterCur = m_stocksAsString.begin();
return S_OK;
}
// Make a copy.
//
STDMETHODIMP CEnumStocksAsString::Clone(IEnumString** ppEnum)
{
typedef CComObject<CEnumStocksAsString> _class;
HRESULT hRes = E_POINTER;
if (ppEnum != NULL)
{
_class* p = NULL;
ATLTRY(p = new _class)
if (p == NULL)
{
*ppEnum = NULL;
hRes = E_OUTOFMEMORY;
}
else
{
hRes = p->Init(m_stocksAsString.begin(), m_stocksAsString.end(),
m_iterCur);
if (FAILED(hRes))
delete p;
else
{
hRes = p->_InternalQueryInterface(IID_IEnumString, (void**)ppEnum);
if (FAILED(hRes))
delete p;
}
}
}
return hRes;
}
// Helper to initialize object. Use given iterators to transform CStock info
// into a string. The string has the form: <symbol>: <price>(<change>) OR
// <symbol>: <NA> if stock data is not available.
//
void CEnumStocksAsString::Init(CStockList::iterator s, CStockList::iterator e)
{
for (CStockList::iterator i = s; i != e; i++)
{
CStock stock = *i;
CString str;
str = stock.GetSymbol();
str += _T(": ");
str += stock.GetCurrent();
if (stock.GetCurrent() != _T("<NA>"))
{
str += _T("(");
str += stock.GetChange() + _T(")");
}
m_stocksAsString.push_back(str.AllocSysString());
}
m_iterCur = m_stocksAsString.begin();
}
// Initialize from a CStockAsString object - similar to a copy contructor.
//
HRESULT CEnumStocksAsString::Init(CStocksAsString::iterator s,
CStocksAsString::iterator e,
CStocksAsString::iterator cur)
{
for (; s != e; s++)
m_stocksAsString.push_back(::SysAllocString(*s));
m_iterCur = m_stocksAsString.begin() + (cur - s);
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// CStockQuotes
// If the notify thread is going post message to it and return immediately .
// Otherwise update now, in which case the function will not return until
// the download is complete.
//
STDMETHODIMP CStockQuotes::Update()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
if (m_pStockUpdateNotify)
{
m_pStockUpdateNotify->PostThreadMessage(WM_STOCK_UPDATE_NOTIFY_NOW, 0, 0);
return S_OK;
}
else
return DoUpdate();
}
// Add a stock. If the stock symbol is already added then do nothing.
//
STDMETHODIMP CStockQuotes::Add(BSTR bstrSymbol)
{
Lock();
CStock s(bstrSymbol);
if (std::find(m_stockList.begin(), m_stockList.end(), s) ==
m_stockList.end())
m_stockList.push_back(s);
Unlock();
return S_OK;
}
// Remove a stock.
//
STDMETHODIMP CStockQuotes::Remove(BSTR bstrSymbol)
{
Lock();
CStockListIter i = std::find(m_stockList.begin(),
m_stockList.end(), CStock(CString(bstrSymbol)));
if (i != m_stockList.end())
m_stockList.erase(i);
Unlock();
return S_OK;
}
// Return an IEnumString object which contains the formated stock information.
//
STDMETHODIMP CStockQuotes::EnumAsString(IEnumString** ppEnum)
{
if (ppEnum == NULL)
return E_POINTER;
*ppEnum = NULL;
CComObject<CEnumStocksAsString>* pEnum = NULL;
ATLTRY(pEnum = new CComObject<CEnumStocksAsString>);
if (pEnum == NULL)
return E_OUTOFMEMORY;
Lock();
pEnum->Init(m_stockList.begin(), m_stockList.end());
Unlock();
HRESULT hRes = pEnum->QueryInterface(IID_IEnumString, (void**)ppEnum);
if (FAILED(hRes))
delete pEnum;
return hRes;
}
// Return an IEnumStocks object which contains the raw stock data.
//
STDMETHODIMP CStockQuotes::EnumStocks(IEnumStocks** ppEnum)
{
if (ppEnum == NULL)
return E_POINTER;
*ppEnum = NULL;
CComObject<CEnumStocks>* pEnum = NULL;
ATLTRY(pEnum = new CComObject<CEnumStocks>);
if (pEnum == NULL)
return E_OUTOFMEMORY;
Lock();
pEnum->Init(m_stockList.begin(), m_stockList.end());
Unlock();
HRESULT hRes = pEnum->QueryInterface(IID_IEnumStocks, (void**)ppEnum);
if (FAILED(hRes))
delete pEnum;
return hRes;
}
// Return number of stocks being tracked.
//
STDMETHODIMP CStockQuotes::StockCount(int* cnt)
{
*cnt = (int)m_stockList.size();
return S_OK;
}
//
// Save stock symbols to given stream.
//
STDMETHODIMP CStockQuotes::Save(IStream* pIStream)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
Lock();
COleStreamFile file(pIStream);
int size = (int)m_stockList.size(); // number of stock symbols to save.
file.Write(&size, sizeof(size));
for (CStockListIter i = m_stockList.begin(); i != m_stockList.end(); i++)
SaveString(file, (*i).GetSymbol());
// save URLs
//
CStockQuoteSource* p = m_sqsList.GetMSInvestor();
CString strEmpty(_T(""));
if (p)
SaveString(file, p->GetURL());
else
SaveString(file, strEmpty);
p = m_sqsList.GetStockSourceISAPIDll();
if (p)
SaveString(file, p->GetURL());
else
SaveString(file, strEmpty);
file.Detach(); // don't want to close the stream.
Unlock();
return S_OK;
}
// Load stock symbols from given stream.
//
STDMETHODIMP CStockQuotes::Load(IStream* pIStream)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
Lock();
COleStreamFile file(pIStream);
m_stockList.clear(); // remove all stocks.
int size = 0;
CString strTmp;
file.Read(&size, sizeof(size)); // number of stock symbols to read.
for (int i = 0; i < size; i++)
{
LoadString(file, strTmp);
m_stockList.push_back(CStock(strTmp)); // add to list.
}
// load URLs.
//
CStockQuoteSource* p;
LoadString(file, strTmp);
if (strTmp.GetLength())
{
p = m_sqsList.GetMSInvestor();
if (p)
p->SetURL(strTmp);
}
LoadString(file, strTmp);
if (strTmp.GetLength())
{
p = m_sqsList.GetStockSourceISAPIDll();
if (p)
p->SetURL(strTmp);
}
file.Detach(); // don't want to close stream.
Unlock();
return S_OK;
}
// Create worker thread that will setup a timer and call back into us
// every "nUpdateInterval" minutes. If the tread is already runniing just
// adjust the update interval.
//
STDMETHODIMP CStockQuotes::StartUpdating(int nUpdateInterval)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
if (!m_pStockUpdateNotify)
{
m_pStockUpdateNotify =
(CStockUpdateNotify*)AfxBeginThread(RUNTIME_CLASS(CStockUpdateNotify));
m_pStockUpdateNotify->Init(this);
}
if (m_pStockUpdateNotify)
m_pStockUpdateNotify->SetNotifyInterval(nUpdateInterval);
return S_OK;
}
// If we are updating (accessing the net) close the connection. Terminate
// notification thread.
//
STDMETHODIMP CStockQuotes::StopUpdating()
{
ShutdownUpdating();
return S_OK;
}
// Set flag indicating that notifications should not occur.
//
STDMETHODIMP CStockQuotes::PauseUpdating()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
if (m_pStockUpdateNotify)
m_pStockUpdateNotify->SuspendNotifications();
return S_OK;
}
// Get and Set MS Investor and stock source ISAPI dll URLs.
//
STDMETHODIMP CStockQuotes::SetMSInvestorURL(BSTR newVal)
{
CStockQuoteSource* pSQS = m_sqsList.GetMSInvestor();
if (pSQS)
pSQS->SetURL(newVal);
return S_OK;
}
STDMETHODIMP CStockQuotes::GetMSInvestorURL(BSTR * pVal)
{
USES_CONVERSION_EX;
BSTR strTmp;
if ((strTmp=T2BSTR_EX(_T("")))==NULL)
return E_OUTOFMEMORY;
CComBSTR bstr(strTmp);
CStockQuoteSource* pSQS = m_sqsList.GetMSInvestor();
if (pSQS)
{
if ((strTmp=T2BSTR_EX((LPCTSTR)pSQS->GetURL()))==NULL)
return E_OUTOFMEMORY;
bstr = strTmp;
}
*pVal = bstr.Detach();
return S_OK;
}
STDMETHODIMP CStockQuotes::SetStockSourceISAPIDllURL(BSTR newVal)
{
CStockQuoteSource* pSQS = m_sqsList.GetStockSourceISAPIDll();
if (pSQS)
pSQS->SetURL(newVal);
return S_OK;
}
STDMETHODIMP CStockQuotes::GetStockSourceISAPIDllURL(BSTR * pVal)
{
USES_CONVERSION_EX;
BSTR strTmp;
if ((strTmp=T2BSTR_EX(_T("")))==NULL)
return E_OUTOFMEMORY;
CComBSTR bstr(strTmp);
CStockQuoteSource* pSQS = m_sqsList.GetStockSourceISAPIDll();
if (pSQS)
{
if ((strTmp=T2BSTR_EX((LPCTSTR)pSQS->GetURL()))==NULL)
return E_OUTOFMEMORY;
bstr = strTmp;
}
*pVal = bstr.Detach();
return S_OK;
}
// Close any pending updates and terminate thread.
//
void CStockQuotes::FinalRelease()
{
ShutdownUpdating();
}
HRESULT CStockQuotes::FinalConstruct()
{
return S_OK;
}
// Connect to net and download data for all stocks. Close session (connection)
// at end of download.
//
HRESULT CStockQuotes::DoUpdate()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
if (g_bUpdating)
return S_OK;
Lock();
g_bUpdating = true;
DWORD dwAccessType;
dwAccessType = PRE_CONFIG_INTERNET_ACCESS;
try
{
m_pINetSession = new CInternetSession(_T("Stock Quotes"));
for (CStockListIter i = m_stockList.begin();
!g_bStopUpdating && i != m_stockList.end(); i++)
{
bool bFoundInfo = false;
for (CSQSList::iterator j = m_sqsList.begin();
!g_bStopUpdating && j != m_sqsList.end(); j++)
{
if ((*j)->Update(*m_pINetSession, *i))
{
bFoundInfo = true;
break;
}
}
if (!bFoundInfo) // no stock info, set indicator string.
i->SetCurrent(_T("<NA>"));
}
Fire_InfoUpdate();
}
catch(CInternetException* e)
{
// if closed prematurely then ok, otherwise let user know.
//
if (e->m_dwError != ERROR_INVALID_HANDLE)
{
TCHAR buf[1025];
e->GetErrorMessage(buf, 1024);
::MessageBox(0, buf, _T("Stock Quotes Component Error"),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -