// Copyright (c) 1998, Microsoft Systems Journal
// Author: Aaron Skonnard
//
// QuoteProviders.idl : IDL source for QuoteProviders.dll
//
// This file will be processed by the MIDL tool to
// produce the type library (QuoteProviders.tlb) and marshalling code.
import "oaidl.idl";
import "ocidl.idl";
[
uuid(F02EAD3F-9F0C-11D1-B2B2-006008ACADF7),
helpstring("IQuoteProvider Interface"),
pointer_default(unique)
]
interface IQuoteProvider : IUnknown
{
[helpstring("method GetHost")] HRESULT GetHost(LPSTR lpszHost,
DWORD dwLen);
[helpstring("method GetPort")] HRESULT GetPort(USHORT* pnPort);
[helpstring("method LoginIsRequired")] HRESULT LoginIsRequired(
BOOL* pbResult);
[helpstring("method GetMethod")] HRESULT GetMethod(LPSTR lpszMethod,
DWORD dwLen);
[helpstring("method GetURL")] HRESULT GetURL(LPSTR lpszURL, DWORD dwLen);
[helpstring("method GetAcceptTypes")] HRESULT GetAcceptTypes(
LPSTR lpszAcceptTypes, DWORD dwLen);
[helpstring("method GetHttpVersion")] HRESULT GetHttpVersion(
LPSTR lpszHttpVersion, DWORD dwLen);
[helpstring("method GetFlags")] HRESULT GetFlags(DWORD* pdwFlags);
[helpstring("method GetHeaders")] HRESULT GetHeaders(LPSTR lpszHeaders,
DWORD dwLen);
[helpstring("method GetData")] HRESULT GetData(LPSTR lpszData,
DWORD dwLen);
[helpstring("method ParseResult")] HRESULT ParseResult(LPSTR lpszResult);
[helpstring("method InitializeData")] HRESULT InitializeData(
LPSTR lpszData);
};
[
uuid(BFD86BC0-A004-11d1-9912-004033D06B6E),
helpstring("IQuoteProviderEvent Interface"),
pointer_default(unique)
]
interface IQuoteProviderEvent : IUnknown //IDispatch
{
import "oaidl.idl";
HRESULT UpdateSymbol(LPCTSTR lpszSymbol, LPCTSTR lpszPrice,
LPCTSTR lpszChange, LPCTSTR lpszOpen,
LPCTSTR lpszVolume);
};
[
uuid(F02EAD31-9F0C-11D1-B2B2-006008ACADF7),
version(1.0),
helpstring("QuoteProviders 1.0 Type Library")
]
library QUOTEPROVIDERSLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
uuid(F02EAD40-9F0C-11D1-B2B2-006008ACADF7),
helpstring("ProviderYahoo Class")
]
coclass ProviderYahoo
{
[default] interface IQuoteProvider;
[default, source] interface IQuoteProviderEvent;
};
[
uuid(32FBDA43-A002-11D1-9912-004033D06B6E),
helpstring("ProviderFastQuote Class")
]
coclass ProviderFastQuote
{
[default] interface IQuoteProvider;
[default, source] interface IQuoteProviderEvent;
};
};
File | Description |
QuoteProviders.tlb | The QuoteProvider type library |
DllData.c | Implements a DLL containing the proxy/stub code |
QuoteProviders_i.c | Defines the GUIDs used in the IDL file |
QuoteProviders_p.c | Implements the proxy/stub code |
QuoteProviders.h | A header file containing the declarations for all of the interfaces defined in the IDL file |
ProviderYahoo.h
// 1998, Microsoft Systems Journal
// Author: Aaron Skonnard
//
// ProviderYahoo.h : Declaration of the CProviderYahoo
//
#ifndef __PROVIDERYAHOO_H_
#define __PROVIDERYAHOO_H_
#include "resource.h" // main symbols
#include "CPQuoteProviders.h"
/////////////////////////////////////////////////////////////////////////////
// CProviderYahoo
class ATL_NO_VTABLE CProviderYahoo :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CProviderYahoo, &CLSID_ProviderYahoo>,
public IConnectionPointContainerImpl<CProviderYahoo>,
public CProxyIQuoteProviderEvent<CProviderYahoo>,
public IQuoteProvider
{
public:
CProviderYahoo()
{
}
~CProviderYahoo()
{
}
DECLARE_REGISTRY_RESOURCEID(IDR_PROVIDERYAHOO)
BEGIN_COM_MAP(CProviderYahoo)
COM_INTERFACE_ENTRY(IQuoteProvider)
COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
END_COM_MAP()
BEGIN_CONNECTION_POINT_MAP(CProviderYahoo)
CONNECTION_POINT_ENTRY(IID_IQuoteProviderEvent)
END_CONNECTION_POINT_MAP()
// IProviderYahoo
public:
STDMETHOD(InitializeData)(LPSTR lpszData);
STDMETHOD(ParseResult)(LPSTR lpszResult);
STDMETHOD(GetData)(LPSTR lpszData, DWORD dwLen);
STDMETHOD(GetHeaders)(LPSTR lpszHeaders, DWORD dwLen);
STDMETHOD(GetFlags)(DWORD* pdwFlags);
STDMETHOD(GetHttpVersion)(LPSTR lpszHttpVersion, DWORD dwLen);
STDMETHOD(GetAcceptTypes)(LPSTR lpszAcceptTypes, DWORD dwLen);
STDMETHOD(GetURL)(LPSTR lpszURL, DWORD dwLen);
STDMETHOD(GetMethod)(LPSTR lpszMethod, DWORD dwLen);
STDMETHOD(LoginIsRequired)(BOOL* pbResult);
STDMETHOD(GetPort)(USHORT* pnPort);
STDMETHOD(GetHost)(LPSTR lpszHost, DWORD dwLen);
};
#endif //__PROVIDERYAHOO_H_
CPQuoteProviders.h
// 1998, Microsoft Systems Journal
// Author: Aaron Skonnard
//
#ifndef __CPROXYIQUOTEPROVIDEREVENT_H__
#define __CPROXYIQUOTEPROVIDEREVENT_H__
//////////////////////////////////////////////////////////////////////////////
// CProxyIQuoteProviderEvent
template <class T>
class CProxyIQuoteProviderEvent : public IConnectionPointImpl<T,
&IID_IQuoteProviderEvent, CComDynamicUnkArray>
{
public:
//IQuoteProviderEvent : IUnknown
public:
HRESULT Fire_UpdateSymbol(LPCTSTR lpszSymbol, LPCTSTR lpszPrice,
LPCTSTR lpszChange, LPCTSTR lpszOpen, LPCTSTR lpszVolume)
{
T* pT = (T*)this;
pT->Lock();
HRESULT ret;
IUnknown** pp = m_vec.begin();
while (pp < m_vec.end())
{
if (*pp != NULL)
{
IQuoteProviderEvent* pIQuoteProviderEvent =
reinterpret_cast<IQuoteProviderEvent*>(*pp);
ret = pIQuoteProviderEvent->UpdateSymbol(lpszSymbol, lpszPrice,
lpszChange, lpszOpen, lpszVolume);
}
pp++;
}
pT->Unlock();
return ret;
}
};
#endif
QuoteProviders.cpp
// 1998, Microsoft Systems Journal
// Author: Aaron Skonnard
//
// QuoteProviders.cpp : Implementation of DLL Exports.
//
#include "stdafx.h"
#include "resource.h"
#include "CategoryGuid.h"
#include "initguid.h"
#include "QuoteProviders.h"
#include "QuoteProviders_i.c"
#include "ProviderYahoo.h"
#include "ProviderFastQuote.h"
#include "comcat.h"
//Component Category Helper Functions
HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription);
HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid);
HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid);
CRITICAL_SECTION g_CS;
CComModule _Module;
BEGIN_OBJECT_MAP(ObjectMap)
OBJECT_ENTRY(CLSID_ProviderYahoo, CProviderYahoo)
OBJECT_ENTRY(CLSID_ProviderFastQuote, CProviderFastQuote)
END_OBJECT_MAP()
class CQuoteProvidersApp : public CWinApp
{
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
};
CQuoteProvidersApp theApp;
BOOL CQuoteProvidersApp::InitInstance()
{
_Module.Init(ObjectMap, m_hInstance);
return CWinApp::InitInstance();
}
int CQuoteProvidersApp::ExitInstance()
{
_Module.Term();
return CWinApp::ExitInstance();
}
/////////////////////////////////////////////////////////////////////////////
// Used to determine whether the DLL can be unloaded by OLE
STDAPI DllCanUnloadNow(void)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
return (AfxDllCanUnloadNow()==S_OK && _Module.GetLockCount()==0) ? S_OK :
S_FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// Returns a class factory to create an object of the requested type
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
return _Module.GetClassObject(rclsid, riid, ppv);
}
/////////////////////////////////////////////////////////////////////////////
// DllRegisterServer - Adds entries to the system registry
STDAPI DllRegisterServer(void)
{
HRESULT hr;
// registers object, typelib and all interfaces in typelib
hr = _Module.RegisterServer(TRUE);
if (FAILED(hr))
return hr;
hr = CreateComponentCategory(CATID_QuoteProviders,
L"Stock Watcher Quote Providers");
if (FAILED(hr))
return hr;
hr = RegisterCLSIDInCategory(CLSID_ProviderYahoo, CATID_QuoteProviders);
if (FAILED(hr))
return hr;
hr = RegisterCLSIDInCategory(CLSID_ProviderFastQuote, CATID_QuoteProviders);
if (FAILED(hr))
return hr;
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// DllUnregisterServer - Removes entries from the system registry
STDAPI DllUnregisterServer(void)
{
HRESULT hr;
_Module.UnregisterServer();
hr=UnRegisterCLSIDInCategory(CLSID_ProviderYahoo, CATID_QuoteProviders);
if (FAILED(hr))
return hr;
hr=UnRegisterCLSIDInCategory(CLSID_ProviderFastQuote, CATID_QuoteProviders);
if (FAILED(hr))
return hr;
return S_OK;
}
HRESULT CreateComponentCategory(CATID catid, WCHAR* catDescription)
{
ICatRegister* pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL,
CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (FAILED(hr))
return hr;
// Make sure the HKCR\Component Categories\{..catid...}
// key is registered.
CATEGORYINFO catinfo;
catinfo.catid = catid;
catinfo.lcid = 0x0409 ; // english
// Make sure the provided description is not too long.
// Only copy the first 127 characters if it is.
int len = wcslen(catDescription);
if (len>127)
len = 127;
wcsncpy(catinfo.szDescription, catDescription, len);
// Make sure the description is null terminated.
catinfo.szDescription[len] = '\0';
hr = pcr->RegisterCategories(1, &catinfo);
pcr->Release();
return hr;
}
HRESULT RegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{
// Register your component categories information.
ICatRegister* pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL,
CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (SUCCEEDED(hr))
{
// Register this category as being "implemented" by the class.
CATID rgcatid[1] ;
rgcatid[0] = catid;
hr = pcr->RegisterClassImplCategories(clsid, 1, rgcatid);
}
if (pcr != NULL)
pcr->Release();
return hr;
}
HRESULT UnRegisterCLSIDInCategory(REFCLSID clsid, CATID catid)
{
ICatRegister* pcr = NULL ;
HRESULT hr = S_OK ;
hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL,
CLSCTX_INPROC_SERVER, IID_ICatRegister, (void**)&pcr);
if (SUCCEEDED(hr))
{
// Unregister this category as being "implemented" by the class.
CATID rgcatid[1] ;
rgcatid[0] = catid;
hr = pcr->UnRegisterClassImplCategories(clsid, 1, rgcatid);
}
if (pcr != NULL)
pcr->Release();
return hr;
}
Method | Description |
GetHost | Provides the Yahoo! quote server's host name (quote.yahoo.com) |
GetPort | Provides the Yahoo! quote server's port number |
GetMethod | Provides the HTTP method for the quote request (GET, POST, and so on) |
GetURL | Provides the identifier for the quote request |
GetHttpVersion | Provides the HTTP version understood by the server (HTTP/1.0) |
GetHeaders | Provides additional HTTP headers that should be used in the quote request |
GetAcceptTypes | Provides additional HTTP accept types that should be used in the quote request |
GetData | Provides properly formatted input data for the quote request |
GetFlags | Provides additional WinInet specific flags that should be used in the quote request |
InitializeData | The client uses this method to pass in a string of stock symbols |
LoginIsRequired | Determines if this quote provider requires authentication |
ParseResult | Parses the HTML response returned by the Yahoo! server |
HTTPObjectServer.idl
// 1998, Microsoft Systems Journal
// Author: Aaron Skonnard
//
// HttpObjectServer.idl : IDL source for HttpObjectServer.dll
// This file will be processed by the MIDL tool to
// produce the type library (HttpObjectServer.tlb) and marshalling code.
import "oaidl.idl";
import "ocidl.idl";
[
uuid(10BE7FE8-9CC7-11D1-9912-004033D06B6E),
helpstring("IHttpRequest Interface"),
pointer_default(unique)
]
interface IHttpRequest : IUnknown //IDispatch
{
[helpstring("method ProcessRequest")] HRESULT ProcessRequest(
IUnknown* pQuoteProvider, long lMainHwnd);
[helpstring("method GetProviderInterface")] HRESULT
GetProviderInterface(IUnknown** ppUnk);
};
[
uuid(10BE7FDB-9CC7-11D1-9912-004033D06B6E),
version(1.0),
helpstring("HttpObjectServer 1.0 Type Library")
]
library HTTPOBJECTSERVERLib
{
importlib("stdole32.tlb");
importlib("stdole2.tlb");
[
uuid(10BE7FE9-9CC7-11D1-9912-004033D06B6E),
helpstring("HttpRequest Class")
]
coclass HttpRequest
{
[default] interface IHttpRequest;
};
};
HTTPRequest.h
// 1998, Microsoft Systems Journal
// Author: Aaron Skonnard
//
// HttpRequest.h : Declaration of the CHttpRequest
#ifndef __HTTPREQUEST_H_
#define __HTTPREQUEST_H_
#include "resource.h" // main symbols
#include "..\QuoteProviders\QuoteProviders.h"
/////////////////////////////////////////////////////////////////////////////
// CHttpRequest
class ATL_NO_VTABLE CHttpRequest :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CHttpRequest, &CLSID_HttpRequest>,
public IHttpRequest
{
public:
CHttpRequest()
{
m_pQuoteProvider = NULL;
}
~CHttpRequest()
{
//release the IQuoteProvider interface
if (m_pQuoteProvider)
m_pQuoteProvider->Release();
}
//pointer to current quote provider interface
IQuoteProvider* m_pQuoteProvider;
//main application HWND
HWND m_hwndMain;
DECLARE_REGISTRY_RESOURCEID(IDR_HTTPREQUEST)
BEGIN_COM_MAP(CHttpRequest)
COM_INTERFACE_ENTRY(IHttpRequest)
END_COM_MAP()
// IHttpRequest
public:
STDMETHOD(GetProviderInterface)(IUnknown** ppUnk);
STDMETHOD(ProcessRequest)(IUnknown* pQuoteProvider, long lMainHwnd);
};
#endif //__HTTPREQUEST_H_
MyInternetSession.h
// 1998, Microsoft Systems Journal
// Author: Aaron Skonnard
//
// MyInternetSession.h: Declaration of CMyInternetSession
//
class CMyInternetSession : public CInternetSession
{
public:
CMyInternetSession(LPCTSTR pstrAgent = NULL, DWORD dwContext = 1,
DWORD dwAccessType = INTERNET_OPEN_TYPE_PRECONFIG,
LPCTSTR pstrProxyName = NULL,
LPCTSTR pstrProxyBypass = NULL,
DWORD dwFlags = 0 )
: CInternetSession(pstrAgent, dwContext, dwAccessType, pstrProxyName,
pstrProxyBypass, dwFlags) { m_pRequest=NULL; };
//override OnStatusCallback
virtual void OnStatusCallback(DWORD dwContext, DWORD dwInternetStatus,
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength );
//pointer to the CHttpRequest object controlling this Internet session
CHttpRequest* m_pRequest;
};
HTTPRequest.cpp
// 1998, Microsoft Systems Journal
// Author: Aaron Skonnard
//
// HttpRequest.cpp : Implementation of CHttpRequest
#include "stdafx.h"
#include "HttpObjectServer.h"
#include "HttpRequest.h"
#include "MyInternetSession.h"
#include "LoginDlg.h"
#include "profile.h"
#include "..\QuoteProviders\QuoteProviders.h"
#include "..\Stock Watcher\globals.h"
#define HTTPFILE_BUFFLEN 4096
#define BUFFLEN 255
extern CRITICAL_SECTION g_CS;
UINT HttpWorkerThread(LPVOID lpVoid);
/////////////////////////////////////////////////////////////////////////////
// CMyInternetSession
void CMyInternetSession::OnStatusCallback(DWORD dwContext, DWORD dwInternetStatus,
LPVOID lpvStatusInformation, DWORD dwStatusInformationLength )
{
if (m_pRequest)
{
if (m_pRequest->m_hwndMain)
::PostMessage(m_pRequest->m_hwndMain, WM_HTTP_THREAD_MESSAGE,
UPDATE_STATUS, dwInternetStatus);
}
}
/////////////////////////////////////////////////////////////////////////////
// CHttpRequest
STDMETHODIMP CHttpRequest::ProcessRequest(IUnknown* pQuoteProvider,
long lMainHwnd)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
m_pQuoteProvider = static_cast<IQuoteProvider*>(pQuoteProvider);
m_pQuoteProvider->AddRef();
m_hwndMain = reinterpret_cast<HWND>(lMainHwnd);
AfxBeginThread(HttpWorkerThread, this);
return S_OK;
}
STDMETHODIMP CHttpRequest::GetProviderInterface(IUnknown * * ppUnk)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState())
*ppUnk = m_pQuoteProvider;
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
// HttpWorkerThread
UINT HttpWorkerThread(LPVOID lpVoid)
{
CHttpRequest* pRequest = reinterpret_cast<CHttpRequest*>(lpVoid);
IQuoteProvider* pProvider = pRequest->m_pQuoteProvider;
CHttpConnection* pHttpConnection = NULL;
CHttpFile* pHttpFile = NULL;
LPVOID lpvoid = NULL;
char lpszHost[BUFFLEN], lpszUserName[BUFFLEN], lpszPassword[BUFFLEN],
lpszMethod[BUFFLEN];
char lpszURL[BUFFLEN], lpszAcceptTypes[BUFFLEN], lpszHttpVersion[BUFFLEN],
lpszHeaders[BUFFLEN];
char lpszData[BUFFLEN];
DWORD dwFlags;
LPCTSTR pstrAcceptTypes[2];
INTERNET_PORT nPort;
BOOL bResult;
//declare CMyInternetSession object
CMyInternetSession InternetSession(NULL, 1, INTERNET_OPEN_TYPE_PRECONFIG);
try
{
//enable the status callback
InternetSession.EnableStatusCallback(TRUE);
InternetSession.m_pRequest = pRequest;
//get connection information
pProvider->GetHost(lpszHost, BUFFLEN);
pProvider->GetPort(&nPort);
pProvider->LoginIsRequired(&bResult);
if (bResult)
{
CString strUserName = GetMyProfileString("Settings", "username", "");
CString strPassword = GetMyProfileString("Settings", "password", "");
if (strUserName.IsEmpty() || strPassword.IsEmpty())
{
// get user name & password information
CLoginDlg dlg;
if (IDCANCEL == dlg.DoModal())
return 0;
WriteMyProfileString("Settings", "username", dlg.m_strUserName);
WriteMyProfileString("Settings", "password", dlg.m_strPassword);
strcpy(lpszUserName, dlg.m_strUserName);
strcpy(lpszPassword, dlg.m_strPassword);
}
else
{
strcpy(lpszUserName, strUserName);
strcpy(lpszPassword, strPassword);
}
}
//establish the HTTP connection
pHttpConnection = InternetSession.GetHttpConnection( lpszHost, nPort,
lpszUserName, lpszPassword);
//get request specific information
pProvider->GetMethod(lpszMethod, BUFFLEN);
pProvider->GetURL(lpszURL, BUFFLEN);
pProvider->GetAcceptTypes(lpszAcceptTypes, BUFFLEN);
pstrAcceptTypes[0] = lpszAcceptTypes;
pstrAcceptTypes[1] = NULL;
pProvider->GetHttpVersion(lpszHttpVersion, BUFFLEN);
pProvider->GetFlags(&dwFlags);
//open the HTTP request
pHttpFile = pHttpConnection->OpenRequest(lpszMethod, lpszURL, "", 1,
pstrAcceptTypes, lpszHttpVersion, dwFlags);
//get the request data
pProvider->GetHeaders(lpszHeaders, BUFFLEN);
pProvider->GetData(lpszData, BUFFLEN);
if (pHttpFile->SendRequest(lpszHeaders, strlen(lpszHeaders),
static_cast<void*>(lpszData), strlen(lpszData)))
{
DWORD dwRet;
//query the HTTP status code
pHttpFile->QueryInfoStatusCode(dwRet);
//authentication techniques
while (dwRet == HTTP_STATUS_DENIED)
{
CLoginDlg dlg;
dlg.m_strUserName = GetMyProfileString("Settings",
"username", "");
dlg.m_strPassword = GetMyProfileString("Settings",
"password", "");
if (IDCANCEL == dlg.DoModal())
{
if (pHttpConnection)
{
pHttpConnection->Close();
delete pHttpConnection;
}
if (pHttpFile)
{
pHttpFile->Close();
delete pHttpFile;
}
return 0;
}
WriteMyProfileString("Settings", "username", dlg.m_strUserName);
WriteMyProfileString("Settings", "password", dlg.m_strPassword);
strcpy(lpszUserName, dlg.m_strUserName);
strcpy(lpszPassword, dlg.m_strPassword);
InternetSetOption((HINTERNET)(*pHttpFile),
INTERNET_OPTION_USERNAME, lpszUserName, strlen(lpszUserName));
InternetSetOption((HINTERNET)(*pHttpFile),
INTERNET_OPTION_PASSWORD, lpszPassword, strlen(lpszPassword));
pHttpFile->SendRequest(lpszHeaders, strlen(lpszHeaders),
static_cast<void*>(lpszData), strlen(lpszData));
pHttpFile->QueryInfoStatusCode(dwRet);
}
if (dwRet == HTTP_STATUS_OK)
{
CString strContentLen;
LPSTR lpszResult=NULL;
UINT nRead=0, nTotalRead=0;
lpvoid = malloc(HTTPFILE_BUFFLEN);
//memory error
if (!lpvoid)
return 0;
//read the HTTP response
nRead = pHttpFile->Read(lpvoid, HTTPFILE_BUFFLEN);
nTotalRead += nRead;
while (nRead == HTTPFILE_BUFFLEN)
{
lpvoid = realloc(lpvoid, nTotalRead+HTTPFILE_BUFFLEN);
nRead = pHttpFile->Read((byte*)lpvoid+nTotalRead,
HTTPFILE_BUFFLEN);
nTotalRead += nRead;
}
lpszResult = (LPSTR)lpvoid;
*(lpszResult + nTotalRead) = NULL;
//parse the HTTP response
EnterCriticalSection(&g_CS);
HRESULT hr = pProvider->ParseResult(lpszResult);
if (FAILED(hr))
::MessageBox(pRequest->m_hwndMain,
"Error parsing quote format",
"ParseResult Error", MB_ICONEXCLAMATION | MB_OK);
LeaveCriticalSection(&g_CS);
//notify the main application window
if (pRequest->m_hwndMain)
::PostMessage(pRequest->m_hwndMain, WM_HTTP_THREAD_MESSAGE,
UPDATE_ALL_VIEWS, 0);
}
}
}
catch(CInternetException *e)
{
e->ReportError();
e->Delete();
}
// cleanup
if (lpvoid)
free(lpvoid);
if (pHttpFile)
{
pHttpFile->Close();
delete pHttpFile;
}
if (pHttpConnection)
{
pHttpConnection->Close();
delete pHttpConnection;
}
return 0;
}
// 1998, Microsoft Systems Journal
// Author: Aaron Skonnard
//
// Stock WatcherDoc.cpp : implementation of the CStockWatcherDoc class
#include "stdafx.h"
#include "Stock Watcher.h"
#include "Stock WatcherDoc.h"
#include "Mainfrm.h"
#include "AddSymbolDlg.h"
#include "QuoteProviderDlg.h"
#include "..\QuoteProviders\QuoteProviders.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_SERIAL(CStockSymbol, CObject, 1);
/////////////////////////////////////////////////////////////////////////////
// CStockWatcherDoc
IMPLEMENT_DYNCREATE(CStockWatcherDoc, CDocument)
BEGIN_MESSAGE_MAP(CStockWatcherDoc, CDocument)
//{{AFX_MSG_MAP(CStockWatcherDoc)
ON_COMMAND(ID_SYMBOL_NEW, OnSymbolNew)
ON_COMMAND(ID_REFRESH_ALL_SYMBOLS, OnRefreshAllSymbols)
ON_COMMAND(ID_QUOTE_PROVIDER, OnQuoteProvider)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CStockWatcherDoc construction/destruction
CStockWatcherDoc::CStockWatcherDoc()
{
//create and initialized the CQuoteProviderEventSink object
CComObject<CQuoteProviderEventSink>::CreateInstance(&m_pQuoteProviderEventSink);
m_pQuoteProviderEventSink->AddRef();
m_pQuoteProviderEventSink->m_pDoc = this;
}
CStockWatcherDoc::~CStockWatcherDoc()
{
EmptySymbolList();
//release all IHttpRequest interfaces
long lSize = m_arrConnections.GetSize(), i;
for (i=0; i<lSize; i++)
{
IHttpRequest* pRequest =
static_cast<IHttpRequest*>(m_arrIHttpRequests.GetAt(i));
IQuoteProvider* pProvider = NULL;
pRequest->GetProviderInterface(reinterpret_cast<IUnknown**>(&pProvider));
if (pProvider)
AtlUnadvise(pProvider, IID_IQuoteProviderEvent,
m_arrConnections.GetAt(i));
pRequest->Release();
}
//release the CQuoteProviderEventSink
m_pQuoteProviderEventSink->Release();
}
void CStockWatcherDoc::OnRefreshAllSymbols()
{
long lSize = m_Objects.GetSize(), i;
CStockSymbol* pSymbol;
CString strSymbols, strCLSID;
DWORD dwConnection;
if (lSize == 0)
return;
//get the currently selected quote provider's CLSID
strCLSID = AfxGetApp()->GetProfileString("Settings", "ProviderCLSID", "");
if (strCLSID.IsEmpty())
return;
LPOLESTR lpszCLSID;
USES_CONVERSION;
lpszCLSID = A2W(strCLSID.GetBuffer(255));
CLSID clsid;
//convert from string to CLSID
CLSIDFromString(lpszCLSID, &clsid);
for (i=0; i<lSize; i++)
{
pSymbol = static_cast<CStockSymbol*>(m_Objects.GetAt(i));
if (i == 0)
strSymbols += pSymbol->m_strSymbol;
else strSymbols += ' ' + pSymbol->m_strSymbol;
}
//create the IHttpRequest component
IHttpRequest* pRequest = NULL;
CoCreateInstance(CLSID_HttpRequest, NULL, CLSCTX_ALL, IID_IHttpRequest,
(void**)&pRequest);
_ASSERTE(pRequest != NULL);
m_arrIHttpRequests.Add(pRequest);
//create the IQuoteProvider component
IQuoteProvider *pQuoteProvider = NULL;
CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_IQuoteProvider,
(void**)&pQuoteProvider);
_ASSERTE(pQuoteProvider != NULL);
//establish the connection point
AtlAdvise(pQuoteProvider, m_pQuoteProviderEventSink->GetUnknown(),
IID_IQuoteProviderEvent, &dwConnection);
m_arrConnections.Add(dwConnection);
//initialize the data (strSymbols)
pQuoteProvider->InitializeData(strSymbols.GetBuffer(255));
//call ProcessRequest
pRequest->ProcessRequest(pQuoteProvider,
reinterpret_cast<long>(AfxGetMainWnd()->GetSafeHwnd()));
//release IQuoteProvider, let the IHttpRequest object manage lifetime
pQuoteProvider->Release();
}
void CStockWatcherDoc::UpdateSymbol(LPCTSTR lpszSymbol, LPCTSTR lpszPrice,
LPCTSTR lpszChange, LPCTSTR lpszOpen, LPCTSTR lpszVolume)
{
CStockSymbol* pSymbol = FindObjectBySymbol(lpszSymbol);
pSymbol->m_strPrice = lpszPrice;
pSymbol->m_strChange = lpszChange;
pSymbol->m_strOpen = lpszOpen;
pSymbol->m_strVolume = lpszVolume;
pSymbol->m_dtLastUpdate = COleDateTime::GetCurrentTime();
SetModifiedFlag();
}
CStockSymbol* CStockWatcherDoc::FindObjectBySymbol(LPCTSTR lpszSymbol)
{
long lSize = m_Objects.GetSize(), i;
CStockSymbol* pSymbol=NULL;
for (i=0; i<lSize; i++)
{
pSymbol = static_cast<CStockSymbol*>(m_Objects.GetAt(i));
if (pSymbol->m_strSymbol.CompareNoCase(lpszSymbol) == 0)
return pSymbol;
}
return pSymbol;
}
STDMETHODIMP CQuoteProviderEventSink::UpdateSymbol(LPCTSTR lpszSymbol,
LPCTSTR lpszPrice, LPCTSTR lpszChange, LPCTSTR lpszOpen, LPCTSTR lpszVolume)
{
m_pDoc->UpdateSymbol(lpszSymbol, lpszPrice, lpszChange, lpszOpen, lpszVolume);
return S_OK;
}