You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
839 lines
30 KiB
839 lines
30 KiB
//+-----------------------------------------------------------------------
|
|
//
|
|
// Tabular Data Control
|
|
// Copyright (C) Microsoft Corporation, 1996, 1997
|
|
//
|
|
// File: TDCCtl.h
|
|
//
|
|
// Contents: Declaration of the CTDCCtl ActiveX Control.
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
|
|
#include "resource.h" // main symbols
|
|
#include <simpdata.h>
|
|
#include "wch.h"
|
|
#include <wininet.h> // for INTERNET_MAX_URL_LENGTH
|
|
|
|
#pragma comment(lib, "wininet.lib")
|
|
|
|
#ifndef DISPID_AMBIENT_CODEPAGE
|
|
#define DISPID_AMBIENT_CODEPAGE (-725)
|
|
#endif
|
|
|
|
// Declare helper needed in IHttpNegotiateImpl
|
|
HRESULT
|
|
GetHostURL(IOleClientSite *pSite, LPOLESTR *ppszHostName);
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// Template: CMyBindStatusCallback
|
|
//
|
|
// Synopsis: This is a temporary kludge to get around an ATL feature
|
|
// while we're waiting for it to become official code.
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
template <class T>
|
|
class ATL_NO_VTABLE IServiceProviderImpl
|
|
{
|
|
public:
|
|
// IUnknown
|
|
//
|
|
STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObject) = 0;
|
|
_ATL_DEBUG_ADDREF_RELEASE_IMPL(IServiceProviderImpl)
|
|
|
|
STDMETHOD(QueryService) (REFGUID guidService,
|
|
REFIID riid,
|
|
void **ppvObject)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
};
|
|
|
|
template <class T>
|
|
class ATL_NO_VTABLE IHttpNegotiateImpl
|
|
{
|
|
public:
|
|
// IUnknown
|
|
//
|
|
STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObject) = 0;
|
|
_ATL_DEBUG_ADDREF_RELEASE_IMPL(IHttpNegotiateImpl)
|
|
|
|
STDMETHOD(BeginningTransaction) (LPCWSTR szURL,
|
|
LPCWSTR szHeaders,
|
|
DWORD dwReserved,
|
|
LPWSTR *pszAdditionalHeaders)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHOD(OnResponse) (DWORD dwResponseCode,
|
|
LPCWSTR szResponseHeaders,
|
|
LPCWSTR szRequestHeaders,
|
|
LPWSTR *pszAdditionalRequestHeaders)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
// IE5 85290: mshtml needs a way to recognize the TDC from
|
|
// its IBindStatusCallback. We define a dummy interface for this.
|
|
|
|
template <class T>
|
|
class ATL_NO_VTABLE IAmTheTDCImpl
|
|
{
|
|
public:
|
|
// IUnknown
|
|
//
|
|
STDMETHOD(QueryInterface)(REFIID riid, void ** ppvObject) = 0;
|
|
_ATL_DEBUG_ADDREF_RELEASE_IMPL(IAmTheTDCImpl)
|
|
};
|
|
|
|
|
|
template <class T>
|
|
class ATL_NO_VTABLE CMyBindStatusCallback :
|
|
public CComObjectRootEx<typename T::_ThreadModel::ThreadModelNoCS>,
|
|
public IBindStatusCallbackImpl<T>, public IHttpNegotiateImpl<T>, public IServiceProviderImpl<T>,
|
|
public IAmTheTDCImpl<T>
|
|
{
|
|
typedef void (T::*ATL_PDATAAVAILABLE)(CMyBindStatusCallback<T>* pbsc, BYTE* pBytes, DWORD dwSize);
|
|
|
|
public:
|
|
|
|
BEGIN_COM_MAP(CMyBindStatusCallback<T>)
|
|
COM_INTERFACE_ENTRY_IID(IID_IBindStatusCallback, IBindStatusCallbackImpl<T>)
|
|
COM_INTERFACE_ENTRY_IID(IID_IHttpNegotiate, IHttpNegotiateImpl<T>)
|
|
COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProviderImpl<T>)
|
|
COM_INTERFACE_ENTRY_IID(IID_IAmTheTDC, IAmTheTDCImpl<T>)
|
|
END_COM_MAP()
|
|
|
|
CMyBindStatusCallback()
|
|
{
|
|
m_pT = NULL;
|
|
m_pFunc = NULL;
|
|
m_fReload = FALSE;
|
|
}
|
|
~CMyBindStatusCallback()
|
|
{
|
|
ATLTRACE(_T("~CMyBindStatusCallback\n"));
|
|
}
|
|
|
|
// IServiceProvider methods
|
|
|
|
STDMETHOD(QueryService) (REFGUID guidService,
|
|
REFIID riid,
|
|
void **ppvObject)
|
|
{
|
|
// As it turns out, the service ID for IHttpNegotiate is the same
|
|
// as it's IID (confusing). This is the only service we support.
|
|
if (IsEqualGUID(IID_IHttpNegotiate, guidService))
|
|
{
|
|
return ((IHttpNegotiate *)this)->QueryInterface(riid, ppvObject);
|
|
}
|
|
else return E_NOTIMPL;
|
|
}
|
|
|
|
//
|
|
// IHttpNegotiate methods
|
|
//
|
|
|
|
STDMETHOD(BeginningTransaction) (LPCWSTR szURL,
|
|
LPCWSTR szHeaders,
|
|
DWORD dwReserved,
|
|
LPWSTR *pszAdditionalHeaders)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
WCHAR swzHostScheme[INTERNET_MAX_URL_LENGTH];
|
|
DWORD cchHostScheme = INTERNET_MAX_URL_LENGTH;
|
|
WCHAR swzFileScheme[INTERNET_MAX_URL_LENGTH];
|
|
DWORD cchFileScheme = INTERNET_MAX_URL_LENGTH;
|
|
|
|
LPOLESTR pszHostName;
|
|
|
|
*pszAdditionalHeaders = NULL;
|
|
|
|
hr = GetHostURL(m_spClientSite, &pszHostName);
|
|
if (FAILED(hr))
|
|
goto Cleanup;
|
|
|
|
// PARSE_SCHEMA didn't work, so we'll just CANONICALIZE and then use the first N
|
|
// characters of the URL
|
|
hr = CoInternetParseUrl(pszHostName, PARSE_CANONICALIZE, 0, swzHostScheme, cchHostScheme,
|
|
&cchHostScheme, 0);
|
|
if (FAILED(hr))
|
|
goto Cleanup;
|
|
|
|
// Don't send a referer which isn't http: or https:, it's none
|
|
// of the servers' business. Further, don't send an https:
|
|
// referer when requesting an http: file.
|
|
if (0 != wch_incmp(swzHostScheme, L"https:", 6) &&
|
|
0 != wch_incmp(swzHostScheme, L"http:", 5))
|
|
goto Cleanup;
|
|
|
|
if (0 == wch_incmp(swzHostScheme, L"https:", 6))
|
|
{
|
|
hr = CoInternetParseUrl(szURL, PARSE_CANONICALIZE, 0, swzFileScheme, cchFileScheme,
|
|
&cchFileScheme, 0);
|
|
if (0 == wch_incmp(swzFileScheme, L"http:", 5)) // don't send https: referer
|
|
goto Cleanup; // to an http: file.
|
|
}
|
|
|
|
// 3*sizeof(WCHAR) is for CR, LF, & '\0'
|
|
*pszAdditionalHeaders = (WCHAR *)CoTaskMemAlloc(sizeof(L"Referer: ") +
|
|
ocslen(pszHostName)*sizeof(WCHAR) +
|
|
3*sizeof(WCHAR));
|
|
if (NULL != *pszAdditionalHeaders)
|
|
{
|
|
ocscpy(*pszAdditionalHeaders, L"Referer: ");
|
|
ocscpy(&((*pszAdditionalHeaders)[9]), pszHostName);
|
|
ocscpy(&((*pszAdditionalHeaders)[9+ocslen(pszHostName)]), L"\r\n");
|
|
}
|
|
|
|
Cleanup:
|
|
CoTaskMemFree(pszHostName);
|
|
return hr;
|
|
}
|
|
|
|
STDMETHOD(OnResponse) (DWORD dwResponseCode,
|
|
LPCWSTR szResponseHeaders,
|
|
LPCWSTR szRequestHeaders,
|
|
LPWSTR *pszAdditionalRequestHeaders)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// IBindStatusCallback methods
|
|
//
|
|
|
|
STDMETHOD(OnStartBinding)(DWORD dwReserved, IBinding *pBinding)
|
|
{
|
|
ATLTRACE(_T("CMyBindStatusCallback::OnStartBinding\n"));
|
|
m_spBinding = pBinding;
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHOD(GetPriority)(LONG *pnPriority)
|
|
{
|
|
ATLTRACENOTIMPL(_T("CMyBindStatusCallback::GetPriority"));
|
|
}
|
|
|
|
STDMETHOD(OnLowResource)(DWORD reserved)
|
|
{
|
|
ATLTRACENOTIMPL(_T("CMyBindStatusCallback::OnLowResource"));
|
|
}
|
|
|
|
STDMETHOD(OnProgress)(ULONG ulProgress, ULONG ulProgressMax, ULONG ulStatusCode, LPCWSTR szStatusText)
|
|
{
|
|
if (BINDSTATUS_REDIRECTING == ulStatusCode && szStatusText != NULL)
|
|
{
|
|
ocscpy(m_pszURL, szStatusText);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHOD(OnStopBinding)(HRESULT hresult, LPCWSTR szError)
|
|
{
|
|
// ATLTRACE(_T("CMyBindStatusCallback::OnStopBinding\n"));
|
|
(m_pT->*m_pFunc)(this, NULL, 0);
|
|
if (m_spWinInetFileStream)
|
|
{
|
|
m_spWinInetFileStream.Release();
|
|
}
|
|
m_spBinding.Release();
|
|
m_spBindCtx.Release();
|
|
m_spMoniker.Release();
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHOD(GetBindInfo)(DWORD *pgrfBINDF, BINDINFO *pbindInfo)
|
|
{
|
|
ATLTRACE(_T("CMyBindStatusCallback::GetBindInfo\n"));
|
|
|
|
if (!pbindInfo || !pbindInfo->cbSize || !pgrfBINDF)
|
|
return E_INVALIDARG;
|
|
|
|
*pgrfBINDF = BINDF_ASYNCHRONOUS
|
|
| BINDF_ASYNCSTORAGE
|
|
;
|
|
// ;begin_internal
|
|
#ifdef NEVER
|
|
// I want DEBUG mode to NOT cache things!! -cfranks
|
|
*pgrfBINDF |= BINDF_GETNEWESTVERSION
|
|
| BINDF_NOWRITECACHE
|
|
| BINDF_RESYNCHRONIZE
|
|
;
|
|
#endif
|
|
// ;end_internal
|
|
|
|
#ifndef DISPID_AMBIENT_OFFLINE
|
|
#define DISPID_AMBIENT_OFFLINE (-5501)
|
|
#endif
|
|
// Get our offline property from container
|
|
VARIANT var;
|
|
VariantInit(&var);
|
|
DWORD dwConnectedStateFlags;
|
|
m_pT->GetAmbientProperty(DISPID_AMBIENT_OFFLINE, var);
|
|
if (var.vt==VT_BOOL && var.boolVal)
|
|
{
|
|
if (!(InternetGetConnectedState(&dwConnectedStateFlags, 0)) &&
|
|
(0 == (dwConnectedStateFlags & INTERNET_CONNECTION_MODEM_BUSY)))
|
|
{
|
|
ATLTRACE(_T("CMyBindStatusCallback::GetBindInfo OFFLINE\n"));
|
|
// We're not even dialed out to another connectoid
|
|
*pgrfBINDF |= BINDF_OFFLINEOPERATION;
|
|
}
|
|
else
|
|
{
|
|
ATLTRACE(_T("CMyBindStatusCallback::GetBindInfo OFFLINE\n"));
|
|
*pgrfBINDF &= ~BINDF_OFFLINEOPERATION;
|
|
}
|
|
}
|
|
|
|
// See if we should force a reload, iff we're not offline.
|
|
if (!(*pgrfBINDF & BINDF_OFFLINEOPERATION) && m_fReload)
|
|
{
|
|
*pgrfBINDF |= BINDF_RESYNCHRONIZE|BINDF_PRAGMA_NO_CACHE;
|
|
}
|
|
|
|
ULONG cbSize = pbindInfo->cbSize;
|
|
memset(pbindInfo, 0, cbSize);
|
|
|
|
pbindInfo->cbSize = cbSize;
|
|
pbindInfo->dwBindVerb = BINDVERB_GET;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHOD(OnDataAvailable)(DWORD grfBSCF, DWORD dwSize, FORMATETC *pformatetc, STGMEDIUM *pstgmed)
|
|
{
|
|
ATLTRACE(_T("CMyBindStatusCallback::OnDataAvailable\n"));
|
|
HRESULT hr = S_OK;
|
|
|
|
// Get the Stream passed
|
|
if (BSCF_FIRSTDATANOTIFICATION & grfBSCF)
|
|
{
|
|
if (!m_spStream && pstgmed->tymed == TYMED_ISTREAM)
|
|
{
|
|
m_spStream = pstgmed->pstm;
|
|
(void)m_spStream->QueryInterface(IID_IWinInetFileStream, (void **)&m_spWinInetFileStream);
|
|
|
|
if (m_spWinInetFileStream)
|
|
{
|
|
CComPtr<IWinInetHttpInfo> spWinInetHttpInfo;
|
|
(void)m_spBinding->QueryInterface(IID_IWinInetHttpInfo, (void **)&spWinInetHttpInfo);
|
|
if (spWinInetHttpInfo)
|
|
{
|
|
HANDLE hWinInetLock = NULL;
|
|
DWORD dwHandleSize = sizeof(HANDLE);
|
|
HRESULT hr = spWinInetHttpInfo->QueryOption(WININETINFO_OPTION_LOCK_HANDLE, (LPVOID)&hWinInetLock, &dwHandleSize);
|
|
if (SUCCEEDED(hr) && hWinInetLock)
|
|
{
|
|
m_spWinInetFileStream->SetHandleForUnlock((DWORD_PTR)hWinInetLock, 0);
|
|
}
|
|
spWinInetHttpInfo.Release();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DWORD dwRead = dwSize - m_dwTotalRead; // Minimum amount available that hasn't been read
|
|
DWORD dwActuallyRead = 0; // Placeholder for amount read during this pull
|
|
|
|
// If there is some data to be read then go ahead and read them
|
|
if (m_spStream)
|
|
{
|
|
if (dwRead > 0)
|
|
{
|
|
BYTE* pBytes = NULL;
|
|
ATLTRY(pBytes = new BYTE[dwRead + 1]);
|
|
if (pBytes == NULL)
|
|
return S_FALSE;
|
|
hr = m_spStream->Read(pBytes, dwRead, &dwActuallyRead);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
pBytes[dwActuallyRead] = 0;
|
|
if (dwActuallyRead>0)
|
|
{
|
|
(m_pT->*m_pFunc)(this, pBytes, dwActuallyRead);
|
|
m_dwTotalRead += dwActuallyRead;
|
|
}
|
|
}
|
|
delete[] pBytes;
|
|
}
|
|
}
|
|
|
|
if (BSCF_LASTDATANOTIFICATION & grfBSCF)
|
|
m_spStream.Release();
|
|
return hr;
|
|
}
|
|
|
|
STDMETHOD(OnObjectAvailable)(REFIID riid, IUnknown *punk)
|
|
{
|
|
ATLTRACENOTIMPL(_T("CMyBindStatusCallback::OnObjectAvailable"));
|
|
}
|
|
|
|
HRESULT _StartAsyncDownload(BSTR bstrURL, IUnknown* pUnkContainer, BOOL bRelative)
|
|
{
|
|
m_dwTotalRead = 0;
|
|
m_dwAvailableToRead = 0;
|
|
HRESULT hr = S_OK;
|
|
CComQIPtr<IServiceProvider, &IID_IServiceProvider> spServiceProvider(pUnkContainer);
|
|
CComPtr<IBindHost> spBindHost;
|
|
CComPtr<IStream> spStream;
|
|
if (spServiceProvider)
|
|
spServiceProvider->QueryService(SID_IBindHost, IID_IBindHost, (void**)&spBindHost);
|
|
|
|
// We don't bother checking this QI, because the only failure mode is that our
|
|
// BeginningNegotitation method won't be able able to properly add the referer string.
|
|
(void)pUnkContainer->QueryInterface(IID_IOleClientSite, (void **)&m_spClientSite);
|
|
|
|
if (spBindHost == NULL)
|
|
{
|
|
if (bRelative)
|
|
return E_NOINTERFACE; // relative asked for, but no IBindHost
|
|
hr = CreateURLMoniker(NULL, bstrURL, &m_spMoniker);
|
|
if (SUCCEEDED(hr))
|
|
hr = CreateBindCtx(0, &m_spBindCtx);
|
|
|
|
if (SUCCEEDED(hr))
|
|
hr = RegisterBindStatusCallback(m_spBindCtx, reinterpret_cast<IBindStatusCallback*>(static_cast<IBindStatusCallbackImpl<T>*>(this)), 0, 0L);
|
|
else
|
|
m_spMoniker.Release();
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPOLESTR pszTemp = NULL;
|
|
hr = m_spMoniker->GetDisplayName(m_spBindCtx, NULL, &pszTemp);
|
|
if (!hr && pszTemp != NULL)
|
|
ocscpy(m_pszURL, pszTemp);
|
|
CoTaskMemFree(pszTemp);
|
|
|
|
hr = m_spMoniker->BindToStorage(m_spBindCtx, 0, IID_IStream, (void**)&spStream);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = CreateBindCtx(0, &m_spBindCtx);
|
|
if (SUCCEEDED(hr))
|
|
hr = RegisterBindStatusCallback(m_spBindCtx, reinterpret_cast<IBindStatusCallback*>(static_cast<IBindStatusCallbackImpl<T>*>(this)), 0, 0L);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (bRelative)
|
|
hr = spBindHost->CreateMoniker(bstrURL, m_spBindCtx, &m_spMoniker, 0);
|
|
else
|
|
hr = CreateURLMoniker(NULL, bstrURL, &m_spMoniker);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LPOLESTR pszTemp = NULL;
|
|
hr = m_spMoniker->GetDisplayName(m_spBindCtx, NULL, &pszTemp);
|
|
if (!hr && pszTemp != NULL)
|
|
ocscpy(m_pszURL, pszTemp);
|
|
CoTaskMemFree(pszTemp);
|
|
hr = spBindHost->MonikerBindToStorage(m_spMoniker, NULL, reinterpret_cast<IBindStatusCallback*>(static_cast<IBindStatusCallbackImpl<T>*>(this)), IID_IStream, (void**)&spStream);
|
|
ATLTRACE(_T("Bound"));
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
HRESULT StartAsyncDownload(T* pT, ATL_PDATAAVAILABLE pFunc, BSTR bstrURL, IUnknown* pUnkContainer, BOOL bRelative,
|
|
BOOL fReload)
|
|
{
|
|
m_pT = pT;
|
|
m_pFunc = pFunc;
|
|
m_fReload = fReload; // force reload if TRUE
|
|
return _StartAsyncDownload(bstrURL, pUnkContainer, bRelative);
|
|
}
|
|
|
|
static HRESULT Download(T* pT, ATL_PDATAAVAILABLE pFunc, BSTR bstrURL, IUnknown* pUnkContainer = NULL, BOOL bRelative = FALSE)
|
|
{
|
|
CComObject<CMyBindStatusCallback<T> > *pbsc;
|
|
HRESULT hRes = CComObject<CMyBindStatusCallback<T> >::CreateInstance(&pbsc);
|
|
if (FAILED(hRes))
|
|
return hRes;
|
|
return pbsc->StartAsyncDownload(pT, pFunc, bstrURL, pUnkContainer, bRelative, FALSE);
|
|
}
|
|
|
|
void DeleteDataFile()
|
|
{
|
|
// we can't delete the file at the time of the call (it's in use), so
|
|
// mark it for deletion later - at stream destruction time
|
|
if (m_spWinInetFileStream)
|
|
{
|
|
m_spWinInetFileStream->SetDeleteFile(0);
|
|
}
|
|
}
|
|
|
|
CComPtr<IMoniker> m_spMoniker;
|
|
CComPtr<IBindCtx> m_spBindCtx;
|
|
CComPtr<IBinding> m_spBinding;
|
|
CComPtr<IWinInetFileStream> m_spWinInetFileStream;
|
|
CComPtr<IStream> m_spStream;
|
|
CComPtr<IOleClientSite> m_spClientSite;
|
|
BOOL m_fReload;
|
|
OLECHAR m_pszURL[INTERNET_MAX_URL_LENGTH];
|
|
T* m_pT;
|
|
ATL_PDATAAVAILABLE m_pFunc;
|
|
DWORD m_dwTotalRead;
|
|
DWORD m_dwAvailableToRead;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// CTimer
|
|
template <class Derived, class T, const IID* piid>
|
|
class CTimer
|
|
{
|
|
public:
|
|
|
|
CTimer()
|
|
{
|
|
m_bTimerOn = FALSE;
|
|
}
|
|
|
|
HRESULT TimerOn(DWORD dwTimerInterval)
|
|
{
|
|
Derived* pDerived = ((Derived*)this);
|
|
|
|
m_dwTimerInterval = dwTimerInterval;
|
|
if (m_bTimerOn) // already on, just change interval
|
|
return S_OK;
|
|
|
|
m_bTimerOn = TRUE;
|
|
m_dwTimerInterval = dwTimerInterval;
|
|
m_pStream = NULL;
|
|
|
|
HRESULT hRes;
|
|
|
|
hRes = CoMarshalInterThreadInterfaceInStream(*piid, (T*)pDerived, &m_pStream);
|
|
|
|
// Create thread and pass the thread proc the this ptr
|
|
m_hThread = CreateThread(NULL, 0, &_Apartment, (void*)this, 0, &m_dwThreadID);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void TimerOff()
|
|
{
|
|
if (m_bTimerOn)
|
|
{
|
|
m_bTimerOn = FALSE;
|
|
AtlWaitWithMessageLoop(m_hThread);
|
|
}
|
|
}
|
|
|
|
|
|
// Implementation
|
|
private:
|
|
static DWORD WINAPI _Apartment(void* pv)
|
|
{
|
|
CTimer<Derived, T, piid>* pThis = (CTimer<Derived, T, piid>*) pv;
|
|
pThis->Apartment();
|
|
return 0;
|
|
}
|
|
|
|
DWORD Apartment()
|
|
{
|
|
CoInitialize(NULL);
|
|
HRESULT hRes;
|
|
|
|
m_spT.Release();
|
|
|
|
if (m_pStream)
|
|
{
|
|
hRes = CoGetInterfaceAndReleaseStream(m_pStream, *piid, (void**)&m_spT);
|
|
}
|
|
|
|
while(m_bTimerOn)
|
|
{
|
|
Sleep(m_dwTimerInterval);
|
|
if (!m_bTimerOn)
|
|
break;
|
|
|
|
m_spT->_OnTimer();
|
|
}
|
|
m_spT.Release();
|
|
|
|
CoUninitialize();
|
|
return 0;
|
|
}
|
|
|
|
// Attributes
|
|
public:
|
|
DWORD m_dwTimerInterval;
|
|
|
|
// Implementation
|
|
private:
|
|
HANDLE m_hThread;
|
|
DWORD m_dwThreadID;
|
|
LPSTREAM m_pStream;
|
|
CComPtr<T> m_spT;
|
|
BOOL m_bTimerOn;
|
|
};
|
|
|
|
class CEventBroker;
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
// CProxyITDCCtlEvents
|
|
template <class T>
|
|
class CProxyITDCCtlEvents : public IConnectionPointImpl<T, &IID_ITDCCtlEvents, CComDynamicUnkArray>
|
|
{
|
|
//ITDCCtlEvents : IDispatch
|
|
public:
|
|
void FireOnReadyStateChanged()
|
|
{
|
|
T* pT = (T*)this;
|
|
pT->Lock();
|
|
IUnknown** pp = m_vec.begin();
|
|
while (pp < m_vec.end())
|
|
{
|
|
if (*pp != NULL)
|
|
{
|
|
DISPPARAMS dispParams;
|
|
dispParams.cArgs = 0;
|
|
dispParams.cNamedArgs = 0;
|
|
dispParams.rgvarg = NULL;
|
|
dispParams.rgdispidNamedArgs = NULL;
|
|
ITDCCtlEvents* pITDCCtlEvents = reinterpret_cast<ITDCCtlEvents*>(*pp);
|
|
pITDCCtlEvents->Invoke(DISPID_READYSTATECHANGE, IID_NULL, CP_ACP, DISPATCH_METHOD, &dispParams,
|
|
NULL, NULL, NULL);
|
|
}
|
|
pp++;
|
|
}
|
|
pT->Unlock();
|
|
return;
|
|
}
|
|
|
|
};
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// Class: CTDCCtl
|
|
//
|
|
// Synopsis: This is the TabularDataControl COM object.
|
|
// It creates a CTDCArr object to manage the control's data.
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
class CTDCCtl :
|
|
public CComObjectRoot,
|
|
public CComCoClass<CTDCCtl, &CLSID_CTDCCtl>,
|
|
public CComControl<CTDCCtl>,
|
|
public CStockPropImpl<CTDCCtl, ITDCCtl, &IID_ITDCCtl, &LIBID_TDCLib>,
|
|
public IProvideClassInfo2Impl<&CLSID_CTDCCtl, &IID_ITDCCtlEvents, &LIBID_TDCLib>,
|
|
public IPersistStreamInitImpl<CTDCCtl>,
|
|
public IOleControlImpl<CTDCCtl>,
|
|
public IOleObjectImpl<CTDCCtl>,
|
|
public IOleInPlaceActiveObjectImpl<CTDCCtl>,
|
|
public IViewObjectExImpl<CTDCCtl>,
|
|
public IOleInPlaceObjectWindowlessImpl<CTDCCtl>,
|
|
public IPersistPropertyBagImpl<CTDCCtl>,
|
|
public CTimer<CTDCCtl, ITDCCtl, &IID_ITDCCtl>,
|
|
public IRunnableObjectImpl<CTDCCtl>,
|
|
public IConnectionPointContainerImpl<CTDCCtl>,
|
|
public IPropertyNotifySinkCP<CTDCCtl>,
|
|
public CProxyITDCCtlEvents<CTDCCtl>
|
|
{
|
|
public:
|
|
CTDCCtl();
|
|
~CTDCCtl();
|
|
|
|
DECLARE_REGISTRY_RESOURCEID(IDR_TDCCtl)
|
|
|
|
DECLARE_NOT_AGGREGATABLE(CTDCCtl)
|
|
|
|
BEGIN_COM_MAP(CTDCCtl)
|
|
COM_INTERFACE_ENTRY(IDispatch)
|
|
COM_INTERFACE_ENTRY(ITDCCtl)
|
|
COM_INTERFACE_ENTRY_IMPL_IID(IID_IViewObject, IViewObjectEx)
|
|
COM_INTERFACE_ENTRY_IMPL_IID(IID_IViewObject2, IViewObjectEx)
|
|
COM_INTERFACE_ENTRY_IMPL(IViewObjectEx)
|
|
COM_INTERFACE_ENTRY_IMPL_IID(IID_IOleWindow, IOleInPlaceObjectWindowless)
|
|
COM_INTERFACE_ENTRY_IMPL_IID(IID_IOleInPlaceObject, IOleInPlaceObjectWindowless)
|
|
COM_INTERFACE_ENTRY_IMPL(IOleInPlaceObjectWindowless)
|
|
COM_INTERFACE_ENTRY_IMPL(IOleInPlaceActiveObject)
|
|
COM_INTERFACE_ENTRY_IMPL(IOleControl)
|
|
COM_INTERFACE_ENTRY_IMPL(IOleObject)
|
|
COM_INTERFACE_ENTRY_IMPL(IPersistStreamInit)
|
|
COM_INTERFACE_ENTRY(IProvideClassInfo)
|
|
COM_INTERFACE_ENTRY(IProvideClassInfo2)
|
|
COM_INTERFACE_ENTRY_IMPL(IPersistPropertyBag)
|
|
COM_INTERFACE_ENTRY_IMPL(IRunnableObject)
|
|
COM_INTERFACE_ENTRY_IMPL(IConnectionPointContainer)
|
|
END_COM_MAP()
|
|
|
|
BEGIN_PROPERTY_MAP(CTDCCtl)
|
|
PROP_ENTRY("RowDelim", DISPID_ROWDELIM, CLSID_CTDCCtl)
|
|
PROP_ENTRY("FieldDelim", DISPID_FIELDDELIM, CLSID_CTDCCtl)
|
|
PROP_ENTRY("TextQualifier", DISPID_TEXTQUALIFIER, CLSID_CTDCCtl)
|
|
PROP_ENTRY("EscapeChar", DISPID_ESCAPECHAR, CLSID_CTDCCtl)
|
|
PROP_ENTRY("UseHeader", DISPID_USEHEADER, CLSID_CTDCCtl)
|
|
PROP_ENTRY("SortAscending", DISPID_SORTASCENDING, CLSID_CTDCCtl)
|
|
PROP_ENTRY("SortColumn", DISPID_SORTCOLUMN, CLSID_CTDCCtl)
|
|
PROP_ENTRY("FilterValue", DISPID_FILTERVALUE, CLSID_CTDCCtl)
|
|
PROP_ENTRY("FilterCriterion", DISPID_FILTERCRITERION, CLSID_CTDCCtl)
|
|
PROP_ENTRY("FilterColumn", DISPID_FILTERCOLUMN,CLSID_CTDCCtl)
|
|
PROP_ENTRY("CharSet", DISPID_CHARSET, CLSID_CTDCCtl)
|
|
PROP_ENTRY("Language", DISPID_LANGUAGE, CLSID_CTDCCtl)
|
|
PROP_ENTRY("CaseSensitive", DISPID_CASESENSITIVE, CLSID_CTDCCtl)
|
|
PROP_ENTRY("Sort", DISPID_SORT, CLSID_CTDCCtl)
|
|
// ;begin_internal
|
|
// Doesn't work right yet.
|
|
// PROP_ENTRY("RefreshInterval", DISPID_TIMER, CLSID_CTDCCtl)
|
|
// ;end_internal
|
|
PROP_ENTRY("Filter", DISPID_FILTER, CLSID_CTDCCtl)
|
|
PROP_ENTRY("AppendData", DISPID_APPENDDATA, CLSID_CTDCCtl)
|
|
// ;begin_internal
|
|
// Trying to save this property causes OLEAUT to GP Fault trying
|
|
// to conver the IDispatch * to a BSTR!
|
|
// PROP_ENTRY("OSP", DISPID_OSP, CLSID_CTDCCtl)
|
|
// ;end_internal
|
|
// This will be removed when we learn more about the HTML
|
|
// sub-tag "OBJECT"
|
|
PROP_ENTRY("DataURL", DISPID_DATAURL, CLSID_CTDCCtl)
|
|
PROP_ENTRY("ReadyState", DISPID_READYSTATE, CLSID_CTDCCtl)
|
|
END_PROPERTY_MAP()
|
|
|
|
BEGIN_CONNECTION_POINT_MAP(CTDCCtl)
|
|
CONNECTION_POINT_ENTRY(IID_IPropertyNotifySink)
|
|
CONNECTION_POINT_ENTRY(IID_ITDCCtlEvents)
|
|
END_CONNECTION_POINT_MAP()
|
|
|
|
BEGIN_MSG_MAP(CTDCCtl)
|
|
MESSAGE_HANDLER(WM_PAINT, OnPaint)
|
|
MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
|
|
MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
|
|
MESSAGE_HANDLER(WM_KILLFOCUS, OnKillFocus)
|
|
END_MSG_MAP()
|
|
|
|
private:
|
|
CComBSTR m_cbstrFieldDelim;
|
|
CComBSTR m_cbstrRowDelim;
|
|
CComBSTR m_cbstrQuoteChar;
|
|
CComBSTR m_cbstrEscapeChar;
|
|
BOOL m_fUseHeader;
|
|
CComBSTR m_cbstrSortColumn;
|
|
BOOL m_fSortAscending;
|
|
CComBSTR m_cbstrFilterValue;
|
|
OSPCOMP m_enumFilterCriterion;
|
|
CComBSTR m_cbstrFilterColumn;
|
|
UINT m_nCodePage;
|
|
UINT m_nAmbientCodePage;
|
|
CComBSTR m_cbstrLanguage;
|
|
CComBSTR m_cbstrDataURL;
|
|
LCID m_lcidRead;
|
|
boolean m_fDataURLChanged;
|
|
HRESULT m_hrDownloadStatus;
|
|
LONG m_lTimer;
|
|
CComBSTR m_cbstrFilterExpr;
|
|
CComBSTR m_cbstrSortExpr;
|
|
BOOL m_fAppendData;
|
|
BOOL m_fCaseSensitive;
|
|
boolean m_fInReset;
|
|
|
|
OLEDBSimpleProvider *m_pSTD;
|
|
CTDCArr *m_pArr;
|
|
IMultiLanguage *m_pML;
|
|
BOOL m_fSecurityChecked;
|
|
|
|
// ;begin_internal
|
|
DATASRCListener *m_pDATASRCListener;
|
|
// ;end_internal
|
|
DataSourceListener *m_pDataSourceListener;
|
|
CEventBroker *m_pEventBroker;
|
|
|
|
|
|
// These member objects are used while parsing the input stream
|
|
//
|
|
CTDCUnify *m_pUnify;
|
|
CComObject<CMyBindStatusCallback<CTDCCtl> > *m_pBSC;
|
|
|
|
// These members and methods expose the ITDCCtl interface
|
|
//
|
|
public:
|
|
|
|
// Control Properties
|
|
//
|
|
STDMETHOD(get_FieldDelim)(BSTR* pbstrFieldDelim);
|
|
STDMETHOD(put_FieldDelim)(BSTR bstrFieldDelim);
|
|
STDMETHOD(get_RowDelim)(BSTR* pbstrRowDelim);
|
|
STDMETHOD(put_RowDelim)(BSTR bstrRowDelim);
|
|
STDMETHOD(get_TextQualifier)(BSTR* pbstrTextQualifier);
|
|
STDMETHOD(put_TextQualifier)(BSTR bstrTextQualifier);
|
|
STDMETHOD(get_EscapeChar)(BSTR* pbstrEscapeChar);
|
|
STDMETHOD(put_EscapeChar)(BSTR bstrEscapeChar);
|
|
STDMETHOD(get_UseHeader)(VARIANT_BOOL* pfUseHeader);
|
|
STDMETHOD(put_UseHeader)(VARIANT_BOOL fUseHeader);
|
|
STDMETHOD(get_SortColumn)(BSTR* pbstrSortColumn);
|
|
STDMETHOD(put_SortColumn)(BSTR bstrSortColumn);
|
|
STDMETHOD(get_SortAscending)(VARIANT_BOOL* pfSortAscending);
|
|
STDMETHOD(put_SortAscending)(VARIANT_BOOL fSortAscending);
|
|
STDMETHOD(get_FilterValue)(BSTR* pbstrFilterValue);
|
|
STDMETHOD(put_FilterValue)(BSTR bstrFilterValue);
|
|
STDMETHOD(get_FilterCriterion)(BSTR* pbstrFilterCriterion);
|
|
STDMETHOD(put_FilterCriterion)(BSTR bstrFilterCriterion);
|
|
STDMETHOD(get_FilterColumn)(BSTR* pbstrFilterColumn);
|
|
STDMETHOD(put_FilterColumn)(BSTR bstrFilterColumn);
|
|
STDMETHOD(get_CharSet)(BSTR *pbstrCharSet);
|
|
STDMETHOD(put_CharSet)(BSTR bstrCharSet);
|
|
STDMETHOD(get_Language)(BSTR* pbstrLanguage);
|
|
STDMETHOD(put_Language_)(LPWCH pwchLanguage);
|
|
STDMETHOD(put_Language)(BSTR bstrLanguage);
|
|
STDMETHOD(get_CaseSensitive)(VARIANT_BOOL *pfCaseSensitive);
|
|
STDMETHOD(put_CaseSensitive)(VARIANT_BOOL fCaseSensitive);
|
|
STDMETHOD(get_DataURL)(BSTR* pbstrDataURL); //
|
|
STDMETHOD(put_DataURL)(BSTR bstrDataURL);
|
|
// ;begin_internal
|
|
// STDMETHOD(get_RefreshInterval)(LONG* plTimer);
|
|
// STDMETHOD(put_RefreshInterval)(LONG lTimer);
|
|
// ;end_internal
|
|
STDMETHOD(get_Filter)(BSTR* pbstrFilterExpr);
|
|
STDMETHOD(put_Filter)(BSTR bstrFilterExpr);
|
|
STDMETHOD(get_Sort)(BSTR* pbstrSortExpr);
|
|
STDMETHOD(put_Sort)(BSTR bstrSortExpr);
|
|
STDMETHOD(get_AppendData)(VARIANT_BOOL* pfAppendData);
|
|
STDMETHOD(put_AppendData)(VARIANT_BOOL fAppendData);
|
|
STDMETHOD(get_OSP)(OLEDBSimpleProviderX ** ppISTD);
|
|
|
|
STDMETHOD(get_ReadyState)(LONG *lReadyState);
|
|
STDMETHOD(put_ReadyState)(LONG lReadyState);
|
|
|
|
// Override IPersistPropertyBagImpl::Load
|
|
STDMETHOD(Load)(LPPROPERTYBAG pPropBag, LPERRORLOG pErrorLog);
|
|
|
|
void UpdateReadyState(LONG lReadyState);
|
|
// Data source notification methods
|
|
STDMETHOD(msDataSourceObject)(BSTR qualifier, IUnknown **ppUnk);
|
|
STDMETHOD(addDataSourceListener)(IUnknown *pEvent);
|
|
|
|
// Control Methods
|
|
//
|
|
STDMETHOD(Reset)();
|
|
STDMETHOD(_OnTimer)(void);
|
|
|
|
private:
|
|
STDMETHOD(CreateTDCArr)(boolean fAppend);
|
|
STDMETHOD(ReleaseTDCArr)(boolean fReplacing);
|
|
void LockBSC();
|
|
void UnlockBSC();
|
|
STDMETHOD(InitiateDataLoad)(boolean fAppend);
|
|
STDMETHOD(SecurityCheckDataURL)(LPOLESTR pszURL);
|
|
STDMETHOD(SecurityMatchAllowDomainList)();
|
|
STDMETHOD(SecurityMatchProtocols)(LPOLESTR pszURL);
|
|
STDMETHOD(TerminateDataLoad)(CMyBindStatusCallback<CTDCCtl> *pBSC);
|
|
BSTR bstrConstructSortExpr();
|
|
BSTR bstrConstructFilterExpr();
|
|
|
|
protected:
|
|
void OnData(CMyBindStatusCallback<CTDCCtl> *pbsc, BYTE *pBytes, DWORD dwSize);
|
|
};
|