2025-11-28 00:35:46 +09:00

1446 lines
38 KiB
C++

//-----------------------------------------------------------------------------
// Microsoft OLE DB RowsetViewer
// Copyright (C) 1994 - 1999 By Microsoft Corporation.
//
// @doc
//
// @module CBASE.CPP
//
//-----------------------------------------------------------------------------------
/////////////////////////////////////////////////////////////////
// Includes
//
/////////////////////////////////////////////////////////////////
#include "Headers.h"
/////////////////////////////////////////////////////////////////
// CBase::CBase
//
/////////////////////////////////////////////////////////////////
CBase::CBase(SOURCE eObjectType, CMainWindow* pCMainWindow, CMDIChild* pCMDIChild)
{
//IUnknown
m_cRef = 1;
//BackPointers
ASSERT(pCMainWindow || pCMDIChild);
m_pCMDIChild = pCMDIChild;
m_pCMainWindow = pCMainWindow ? pCMainWindow : pCMDIChild->m_pCMainWindow;
//Common OLE DB Interfaces
m_pIUnknown = NULL;
m_pISupportErrorInfo = NULL;
m_pIAggregate = NULL;
m_pIService = NULL;
//Data
m_hTreeItem = NULL;
m_eObjectType = eObjectType;
m_eBaseClass = eCBase;
m_dwCLSCTX = CLSCTX_INPROC_SERVER;
//Parent Info
m_pCParent = NULL;
m_guidSource = GUID_NULL;
}
/////////////////////////////////////////////////////////////////
// CBase::~CBase
//
/////////////////////////////////////////////////////////////////
CBase::~CBase()
{
//ReleaseObject should have already been called...
//If you hit this ASSERT put a "ReleaseObject(0)" in the obhjects destructor...
//NOTE: We can't just call ReleaseObject here since its a virtual function.
//Calling a virtual function would invoke the derived class, which when we are here
//(in the base destructor) the derived class is already garbaged!
ASSERT(m_pIUnknown == NULL);
ASSERT(m_pCParent == NULL);
//Make sure this item is removed from the tree...
CObjTree* pCObjTree = m_pCMainWindow->m_pCMDIObjects->m_pCObjTree;
if(pCObjTree && m_hTreeItem)
{
//NOTE: The object (after this desctructor) is no longer available,
//so make sure that even if the node cannot be removed (child nodes),
//we need to still remove the object reference so it doesn't try and access it anymore...
pCObjTree->RemoveObject(this);
pCObjTree->SetItemParam(m_hTreeItem, NULL);
}
}
/////////////////////////////////////////////////////////////////
// CBase::AddRef
//
/////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CBase::AddRef()
{
//AddRef
return ++m_cRef;
}
/////////////////////////////////////////////////////////////////
// CBase::Release
//
/////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CBase::Release()
{
//NOTE: The only thing that we have to be careful with is that our objects are refcounted,
//but they contain a pointer to the window, which might have gone away or be going away.
//So if the window is no longer valid, make sure we NULL out our window pointer...
if(m_pCMDIChild && !m_pCMDIChild->m_hWnd)
m_pCMDIChild = NULL;
//Release
if(--m_cRef)
return m_cRef;
delete this;
return 0;
}
/////////////////////////////////////////////////////////////////
// CBase::QueryInterface
//
/////////////////////////////////////////////////////////////////
STDMETHODIMP CBase::QueryInterface(REFIID riid, LPVOID *ppv)
{
if(!ppv)
return E_INVALIDARG;
*ppv = NULL;
//IUNKNOWN
if(riid == IID_IUnknown)
*ppv = this;
if(*ppv)
{
((IUnknown*)(*ppv))->AddRef();
return S_OK;
}
return E_NOINTERFACE;
}
/////////////////////////////////////////////////////////////////
// CBase::ObjectAddRef
//
/////////////////////////////////////////////////////////////////
ULONG CBase::ObjectAddRef()
{
//Record the number of times the user has addref'd this object.
//So we can know when to correctly NULL out the interface, so they can longer use it...
AddRef();
//IUnknown::AddRef
return TRACE_ADDREF(m_pIUnknown, GetObjectName());
}
/////////////////////////////////////////////////////////////////
// CBase::ObjectRelease
//
/////////////////////////////////////////////////////////////////
ULONG CBase::ObjectRelease()
{
IUnknown* pIUnknown = m_pIUnknown;
ULONG ulRefCount = 0;
//IUnknown::Release
ulRefCount = CIntTrace::TraceRelease(&pIUnknown, GetObjectName());
//We need to disable this interface once it hits zero so
//its not used incorrectly after the object is released...
if(ulRefCount == 0 || m_cRef<=1)
{
m_pIUnknown = NULL;
ReleaseObject();
}
else
{
Release();
}
return ulRefCount;
}
/////////////////////////////////////////////////////////////////
// HRESULT CBase::SetInterface
//
/////////////////////////////////////////////////////////////////
HRESULT CBase::SetInterface(REFIID riid, IUnknown* pIUnknown)
{
//We need to put the obtained interface in the appropiate member...
if(pIUnknown)
{
//First obtain the correct interface member variable...
IUnknown** ppInterfaceMember = GetInterfaceAddress(riid);
if(!ppInterfaceMember)
return E_NOINTERFACE;
TRACE_RELEASE(*ppInterfaceMember, GetObjectName());
TRACE_ADDREF(pIUnknown, GetObjectName());
*ppInterfaceMember = pIUnknown;
}
return S_OK;
}
/////////////////////////////////////////////////////////////////
// HRESULT CBase::GetInterface
//
/////////////////////////////////////////////////////////////////
IUnknown* CBase::GetInterface(REFIID riid)
{
//Delegate to the derived class...
IUnknown** ppIUnknown = GetInterfaceAddress(riid);
if(ppIUnknown)
return *ppIUnknown;
return NULL;
}
/////////////////////////////////////////////////////////////////
// HRESULT CBase::ObjectQI
//
/////////////////////////////////////////////////////////////////
HRESULT CBase::ObjectQI(REFIID riid, IUnknown** ppIUnknown)
{
HRESULT hr = S_OK;
//IUnknown::QueryInterface
XTESTC(hr = TRACE_QI(m_pIUnknown, riid, ppIUnknown, GetObjectName()));
//We need to put the obtained interface in the appropiate member...
if(ppIUnknown && *ppIUnknown)
hr = SetInterface(riid, *ppIUnknown);
CLEANUP:
return hr;
}
/////////////////////////////////////////////////////////////////
// CBase::ReleaseObject
//
/////////////////////////////////////////////////////////////////
HRESULT CBase::ReleaseObject(ULONG ulExpectedRefCount)
{
//Release Derived interfaces first...
AutoRelease();
//IUnknown
TRACE_RELEASE_(m_pIUnknown, L"IUnknown", ulExpectedRefCount);
//Cleanup when there are no more references
if(ulExpectedRefCount==0)
{
//Remove this object from the tree, unless there is a window associated with it
m_pCMainWindow->m_pCMDIObjects->m_pCObjTree->RemoveObject(this);
m_guidSource = GUID_NULL;
//Release Parent
SAFE_RELEASE(m_pCParent);
}
return S_OK;
}
/////////////////////////////////////////////////////////////////
// CBase::ReleaseChildren
//
/////////////////////////////////////////////////////////////////
HRESULT CBase::ReleaseChildren()
{
//Make our lives easier...
CObjTree* pCObjTree = m_pCMainWindow->m_pCMDIObjects->m_pCObjTree;
//No-op
if(!m_hTreeItem || !pCObjTree->m_hWnd)
return S_OK;
BOOL bAllRemoved = TRUE;
//Try to obtain the first child...
HTREEITEM hChildItem = pCObjTree->GetChildItem(m_hTreeItem);
while(hChildItem)
{
//NOTE: Before deleting this node of the tree, obtain the
//next sibling (if there is one...). Since we can't do this after the node has been deleted!
HTREEITEM hNextSibling = pCObjTree->GetNextItem(hChildItem);
CBase* pCChild = (CBase*)pCObjTree->GetItemParam(hChildItem);
if(pCChild)
{
//Make sure all its children are released (recurse)
//If this child cannot be released, we still can continue on to the next child
//(ie: release everything we can - not all or nothing...)
if(SUCCEEDED(pCChild->ReleaseChildren()))
{
//Now we can release this child
pCChild->ReleaseObject();
}
}
//Go to the next sibling...
hChildItem = hNextSibling;
}
return bAllRemoved ? S_OK : E_FAIL;
}
/////////////////////////////////////////////////////////////////
// HRESULT CBase::CreateObject
//
/////////////////////////////////////////////////////////////////
HRESULT CBase::CreateObject(CBase* pCSource, REFIID riid, IUnknown* pIUnkObject, DWORD dwCreateOpts)
{
//No-op...
if(!pIUnkObject)
return E_INVALIDARG;
//Use exsiting Connection
IUnknown* pIUnknown = NULL;
if(dwCreateOpts == -1 /*Default*/)
dwCreateOpts = GetOptions()->m_dwCreateOpts;
HRESULT hr = S_OK;
//Store the Parent Object...
SAFE_RELEASE(m_pCParent);
SAFE_ADDREF(pCSource);
m_pCParent = pCSource;
//First we QI for IID_IUnknown the object passed in.
//NOTE: We do this before we call ReleaseObject since the caller of this
//method could have passed in our own member variable (m_pIUnknown) to "recreate" the object.
TRACE_QI(pIUnkObject, IID_IUnknown, &pIUnknown, GetObjectName());
//Release all Previous interfaces...
ReleaseObject(1);
//[MANDATORY]
//Used the AddRef'd input as our IUnknown, since all interfaces inherit from IUnknown.
m_pIUnknown = pIUnknown;
//Now set the pointer pased into the appropiate interface member
//NOTE: We already handled IUnknown above...
if(riid != IID_IUnknown)
SetInterface(riid, pIUnkObject);
//Now AutoQI for derived object interfaces...
AutoQI(dwCreateOpts);
//Add this object to the Objects Window
m_pCMainWindow->m_pCMDIObjects->m_pCObjTree->AddObject(pCSource, this);
//CLEANUP:
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CBase::AutoRelease
//
/////////////////////////////////////////////////////////////////
HRESULT CBase::AutoRelease()
{
//Common OLE DB Interface
RELEASE_INTERFACE(ISupportErrorInfo);
RELEASE_INTERFACE(IAggregate);
RELEASE_INTERFACE(IService);
return S_OK;
}
/////////////////////////////////////////////////////////////////
// HRESULT CBase::AutoQI
//
/////////////////////////////////////////////////////////////////
HRESULT CBase::AutoQI(DWORD dwCreateOpts)
{
//[MANDATORY] Obtain [mandatory] interfaces
if(dwCreateOpts & CREATE_QI_MANDATORY)
{
}
//[OPTIONAL]
if(dwCreateOpts & CREATE_QI_OPTIONAL)
{
OBTAIN_INTERFACE(ISupportErrorInfo);
OBTAIN_INTERFACE(IAggregate);
OBTAIN_INTERFACE(IService);
}
return S_OK;
}
/////////////////////////////////////////////////////////////////
// IUnknown** CBase::GetInterfaceAddress
//
/////////////////////////////////////////////////////////////////
IUnknown** CBase::GetInterfaceAddress(REFIID riid)
{
HANDLE_GETINTERFACE(IUnknown);
HANDLE_GETINTERFACE(ISupportErrorInfo);
HANDLE_GETINTERFACE(IAggregate);
HANDLE_GETINTERFACE(IService);
return NULL;
}
/////////////////////////////////////////////////////////////////
// CBase::IsSameObject
//
/////////////////////////////////////////////////////////////////
BOOL CBase::IsSameObject(IUnknown* pIUnkObject)
{
CComPtr<IUnknown> spUnknown = m_pIUnknown;
return spUnknown.IsEqualObject(pIUnkObject);
}
/////////////////////////////////////////////////////////////////
// CBase::GetParent
//
/////////////////////////////////////////////////////////////////
CBase* CBase::GetParent(SOURCE eSource)
{
CBase* pCParent = m_pCParent;
//Try to find the requested parent object type
while(pCParent)
{
//Do we have a match...
if(pCParent->m_eObjectType == eSource)
return pCParent;
//Try the previous parent...
pCParent = pCParent->m_pCParent;
}
return NULL;
}
////////////////////////////////////////////////////////////////
// CBase::SetObjectDesc
//
/////////////////////////////////////////////////////////////////
void CBase::SetObjectDesc(WCHAR* pwszObjectDesc, BOOL fCopy)
{
//Optmization: If the caller no longer needs the name,
//no sense in reallocing, copying, freeing, freeing. Just reference it...
if(fCopy)
{
m_strObjectDesc.CopyFrom(pwszObjectDesc);
}
else
{
m_strObjectDesc.Attach(pwszObjectDesc);
}
//Update the object in the tree...
if(m_strObjectDesc && m_hTreeItem)
m_pCMainWindow->m_pCMDIObjects->m_pCObjTree->AddObject(NULL, this);
}
////////////////////////////////////////////////////////////////
// CBase::OnDefOperation
//
/////////////////////////////////////////////////////////////////
void CBase::OnDefOperation()
{
//The default implementation (unless its overridden)
//Activate the MDIChild window assoicated with this object
if(m_pCMDIChild && m_pCMDIChild->m_hWnd)
m_pCMainWindow->MDIActivate(m_pCMDIChild->m_hWnd);
}
////////////////////////////////////////////////////////////////
// CBase::DisplayObject
//
/////////////////////////////////////////////////////////////////
HRESULT CBase::DisplayObject()
{
//Update the object in the tree...
if(m_hTreeItem)
m_pCMainWindow->m_pCMDIObjects->m_pCObjTree->AddObject(NULL, this);
return S_OK;
}
////////////////////////////////////////////////////////////////
// CBase::GetOptions
//
/////////////////////////////////////////////////////////////////
COptionsSheet* CBase::GetOptions()
{
return m_pCMainWindow->GetOptions();
}
// {CB21F4D6-878D-11d1-9528-00C04FB66A50}
static const IID IID_IAggregate =
{ 0xcb21f4d6, 0x878d, 0x11d1, { 0x95, 0x28, 0x0, 0xc0, 0x4f, 0xb6, 0x6a, 0x50 } };
///////////////////////////////////////////////////////////////////////////////
// CAggregate
//
///////////////////////////////////////////////////////////////////////////////
CAggregate::CAggregate()
{
m_cRef = 1;
}
///////////////////////////////////////////////////////////////////////////////
// ~CAggregate
//
///////////////////////////////////////////////////////////////////////////////
CAggregate::~CAggregate()
{
//COM Aggregation rule #6
//To free an inner pointer (other than IUnknown), the outer object calls its
//own outer unknown's AddRef followed by Release on the inner object's pointer
//Currently we don't have this case, since we only have IUnknown
//AddRef()
//SAFE_RELEASE(m_pNonIUnknownInner);
//Inner object free
ReleaseInner();
}
/////////////////////////////////////////////////////////////////////////////
// CAggregate::SetInner
//
/////////////////////////////////////////////////////////////////////////////
HRESULT CAggregate::SetInner(IUnknown* pIUnkInner)
{
if(!pIUnkInner)
return E_INVALIDARG;
TRACE_RELEASE(m_spUnkInner.p, L"IUnknown");
return TRACE_QI(pIUnkInner, IID_IUnknown, (IUnknown**)&m_spUnkInner);
}
/////////////////////////////////////////////////////////////////////////////
// CAggregate::ReleaseInner
//
/////////////////////////////////////////////////////////////////////////////
HRESULT CAggregate::ReleaseInner()
{
//Only release the inner if the RefCount of the outer has gone to its
//orginal refcount
if(m_cRef <= 1)
{
TRACE_RELEASE(m_spUnkInner.p, L"IUnknown");
return S_OK;
}
return S_FALSE;
}
/////////////////////////////////////////////////////////////////////////////
// CAggregate::HandleAggregation
//
/////////////////////////////////////////////////////////////////////////////
HRESULT CAggregate::HandleAggregation(REFIID riid, IUnknown** ppIUnknown)
{
HRESULT hr = S_OK;
IUnknown* pIUnkInner = ppIUnknown ? *ppIUnknown : NULL;
if(pIUnkInner)
{
//This would be a bug in the provider if aggregaiton succeeded
//but the user didn't request IID_IUnknown.
if(riid != IID_IUnknown)
{
//NOTE: We don't want to just continue here since this is dangerous.
//If the provider succeeds, this means the outer object was probably returned rather
//than the inner non-delegating IUnknown, this will cause our outer controlling object
//to have a circular QI problem when asked for an inner interface, and will have refcounting
//problems as well. Might as well let the use know, and don't further this provider bug...
if(IDNO == wMessageBox
(
GetFocus(),
MB_TASKMODAL | MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON1,
wsz_ERROR,
L"Provider Bug: Allowed Aggregation and riid!=IID_IUnknown!\n\n"
L"This may crash your Provider...\n"
L"Do you wish to continue anyway?"
))
{
//return a failure if the user wished not to continue...
TESTC(hr = E_INVALIDARG);
}
}
//We need to "hook" up our objects. So that our outer controlling object
//has a pointer to the inner for delegating QI calls. This must be an non-delegating
//inner IUnknown, (see below). Also the caller of this function will ALWAYS
//release their CAggregate object, and we return a the Aggregate object with our
//reference count. (consistent with COM, calle never releases callers IUnknown, and
//calle always addref's if they hold onto the callers object).
if(SUCCEEDED(hr = SetInner(pIUnkInner)))
{
//SetInner
TRACE_RELEASE(pIUnkInner, L"IUnknown");
hr = QueryInterface(IID_IUnknown, (void**)ppIUnknown);
}
}
CLEANUP:
return hr;
}
/////////////////////////////////////////////////////////////////////////////
// CAggregate::AddRef
//
/////////////////////////////////////////////////////////////////////////////
ULONG CAggregate::AddRef(void)
{
return ++m_cRef;
}
/////////////////////////////////////////////////////////////////////////////
// CAggregate::Release
//
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP_(ULONG) CAggregate::Release(void)
{
ASSERT(m_cRef);
if(--m_cRef)
return m_cRef;
//COM Aggregation rule #5
//The outer object must protect its implementation of Release from
//reentrantcy with an artifical reference count arround its destruction code
m_cRef++;
//Delete this object
delete this;
return 0;
}
/////////////////////////////////////////////////////////////////////////////
// CAggregate::QueryInterface
//
/////////////////////////////////////////////////////////////////////////////
HRESULT CAggregate::QueryInterface(REFIID riid, LPVOID *ppv)
{
HRESULT hr = S_OK;
//TEST_ NULL
if(ppv == NULL)
return E_INVALIDARG;
*ppv = NULL;
//Support IID_IUnknown
if(riid == IID_IUnknown)
{
*ppv = (IUnknown*)this;
SAFE_ADDREF((IUnknown*)*ppv);
}
else if(riid == IID_IAggregate)
{
*ppv = (IUnknown*)this;
SAFE_ADDREF((IUnknown*)*ppv);
}
else if(m_spUnkInner)
{
//Delegate the the Inner Object
//This is not "circular" since this interface is the IID_IUnknown
//interface only, which has its own non-delegating QI...
hr = m_spUnkInner->QueryInterface(riid, ppv);
}
else
{
return E_NOINTERFACE;
}
return hr;
}
/////////////////////////////////////////////////////////////////
// CContainerBase::CContainerBase
//
/////////////////////////////////////////////////////////////////
CContainerBase::CContainerBase(SOURCE eObjectType, CMainWindow* pCMainWindow, CMDIChild* pCMDIChild)
: CBase(eObjectType, pCMainWindow, pCMDIChild)
{
//eBaseClass
m_eBaseClass = BASE_CLASS(m_eBaseClass | eCContainerBase);
//Common OLE DB Interfaces
m_pIConnectionPointContainer = NULL;
}
/////////////////////////////////////////////////////////////////
// CContainerBase::~CContainerBase
//
/////////////////////////////////////////////////////////////////
CContainerBase::~CContainerBase()
{
ReleaseObject(0);
}
/////////////////////////////////////////////////////////////////
// HRESULT CContainerBase::AutoRelease
//
/////////////////////////////////////////////////////////////////
HRESULT CContainerBase::AutoRelease()
{
//Common OLE DB Interface
RELEASE_INTERFACE(IConnectionPointContainer);
//Delegate
return CBase::AutoRelease();
}
/////////////////////////////////////////////////////////////////
// HRESULT CContainerBase::AutoQI
//
/////////////////////////////////////////////////////////////////
HRESULT CContainerBase::AutoQI(DWORD dwCreateOpts)
{
//Delegate First so we have base interfaces
CBase::AutoQI(dwCreateOpts);
//[MANDATORY] Obtain [mandatory] interfaces
if(dwCreateOpts & CREATE_QI_MANDATORY)
{
}
//[OPTIONAL]
if(dwCreateOpts & CREATE_QI_OPTIONAL)
{
OBTAIN_INTERFACE(IConnectionPointContainer);
}
return S_OK;
}
/////////////////////////////////////////////////////////////////
// IUnknown** CContainerBase::GetInterfaceAddress
//
/////////////////////////////////////////////////////////////////
IUnknown** CContainerBase::GetInterfaceAddress(REFIID riid)
{
HANDLE_GETINTERFACE(IConnectionPointContainer);
//Otherwise delegate
return CBase::GetInterfaceAddress(riid);
}
/////////////////////////////////////////////////////////////////
// HRESULT CContainerBase::FindConnectionPoint
//
/////////////////////////////////////////////////////////////////
HRESULT CContainerBase::FindConnectionPoint(REFIID riid, IConnectionPoint** ppIConnectionPoint)
{
HRESULT hr = S_OK;
if(m_pIConnectionPointContainer)
{
//IConnectionPointContainer::FindConnectionPoint
hr = m_pIConnectionPointContainer->FindConnectionPoint(riid, ppIConnectionPoint);
TESTC(TRACE_METHOD(hr, L"IConnectionPointContainer::FindConnectionPoint(%s, &0x%p)", GetInterfaceName(riid), ppIConnectionPoint ? *ppIConnectionPoint : NULL));
}
CLEANUP:
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CContainerBase::AdviseListener
//
/////////////////////////////////////////////////////////////////
HRESULT CContainerBase::AdviseListener(REFIID riid, DWORD* pdwCookie)
{
HRESULT hr = S_OK;
if(m_pIConnectionPointContainer)
{
if(riid == IID_IDBAsynchNotify)
{
if(GetOptions()->m_dwNotifyOpts & NOTIFY_IDBASYNCHNOTIFY)
hr = m_pCMainWindow->m_pCListener->Advise(this, riid, pdwCookie);
}
else if(riid == IID_IRowsetNotify)
{
if(GetOptions()->m_dwNotifyOpts & NOTIFY_IROWSETNOTIFY)
hr = m_pCMainWindow->m_pCListener->Advise(this, riid, pdwCookie);
}
else if(riid == IID_IRowPositionChange)
{
if(GetOptions()->m_dwNotifyOpts & NOTIFY_IROWPOSITIONCHANGE)
hr = m_pCMainWindow->m_pCListener->Advise(this, riid, pdwCookie);
}
else
{
ASSERT(!"Unhandled Notification Type!");
}
}
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CContainerBase::UnadviseListener
//
/////////////////////////////////////////////////////////////////
HRESULT CContainerBase::UnadviseListener(REFIID riid, DWORD* pdwCookie)
{
ASSERT(pdwCookie);
HRESULT hr = S_OK;
if(m_pIConnectionPointContainer)
{
if(*pdwCookie)
hr = m_pCMainWindow->m_pCListener->Unadvise(this, riid, pdwCookie);
}
return hr;
}
/////////////////////////////////////////////////////////////////
// CConnectionPoint::CConnectionPoint
//
/////////////////////////////////////////////////////////////////
CConnectionPoint::CConnectionPoint(CMainWindow* pCMainWindow, CMDIChild* pCMDIChild)
: CBase(eCConnectionPoint, pCMainWindow, pCMDIChild)
{
//Common OLE DB Interfaces
m_pIConnectionPoint = NULL; //Connection interface
//Data
m_dwCookie = 0;
}
/////////////////////////////////////////////////////////////////
// CConnectionPoint::~CConnectionPoint
//
/////////////////////////////////////////////////////////////////
CConnectionPoint::~CConnectionPoint()
{
ReleaseObject(0);
}
/////////////////////////////////////////////////////////////////
// HRESULT CConnectionPoint::AutoRelease
//
/////////////////////////////////////////////////////////////////
HRESULT CConnectionPoint::AutoRelease()
{
//Common OLE DB Interface
RELEASE_INTERFACE(IConnectionPoint);
//Delegate
return CBase::AutoRelease();
}
/////////////////////////////////////////////////////////////////
// HRESULT CConnectionPoint::AutoQI
//
/////////////////////////////////////////////////////////////////
HRESULT CConnectionPoint::AutoQI(DWORD dwCreateOpts)
{
//Delegate First so we have base interfaces
CBase::AutoQI(dwCreateOpts);
//[MANDATORY] Obtain [mandatory] interfaces
if(dwCreateOpts & CREATE_QI_MANDATORY)
{
OBTAIN_INTERFACE(IConnectionPoint);
}
//[OPTIONAL]
if(dwCreateOpts & CREATE_QI_OPTIONAL)
{
}
return S_OK;
}
/////////////////////////////////////////////////////////////////
// IUnknown** CConnectionPoint::GetInterfaceAddress
//
/////////////////////////////////////////////////////////////////
IUnknown** CConnectionPoint::GetInterfaceAddress(REFIID riid)
{
HANDLE_GETINTERFACE(IConnectionPoint);
//Otherwise delegate
return CBase::GetInterfaceAddress(riid);
}
/////////////////////////////////////////////////////////////////////////////
// CConnectionPoint::GetObjectDesc
//
/////////////////////////////////////////////////////////////////////////////
WCHAR* CConnectionPoint::GetObjectDesc()
{
if(!m_strObjectDesc && m_pIConnectionPoint)
{
IID iid;
if(SUCCEEDED(GetConnectionInterface(&iid)))
m_strObjectDesc.CopyFrom(GetInterfaceName(iid));
}
return m_strObjectDesc;
}
/////////////////////////////////////////////////////////////////
// HRESULT CConnectionPoint::GetConnectionInterface
//
/////////////////////////////////////////////////////////////////
HRESULT CConnectionPoint::GetConnectionInterface(IID* pIID)
{
HRESULT hr = S_OK;
if(m_pIConnectionPoint)
{
hr = m_pIConnectionPoint->GetConnectionInterface(pIID);
TESTC(TRACE_METHOD(hr, L"IConnectionPoint::GetConnectionInterface(&%s)", GetInterfaceName(pIID ? *pIID : IID_NULL)));
}
CLEANUP:
return hr;
}
/////////////////////////////////////////////////////////////////
// CAsynchBase::CAsynchBase
//
/////////////////////////////////////////////////////////////////
CAsynchBase::CAsynchBase(SOURCE eObjectType, CMainWindow* pCMainWindow, CMDIChild* pCMDIChild)
: CContainerBase(eObjectType, pCMainWindow, pCMDIChild)
{
//eBaseClass
m_eBaseClass = BASE_CLASS(m_eBaseClass | eCAsynchBase);
//OLE DB Interfaces
m_pIDBInitialize = NULL; //OLE DB interface
m_pIDBAsynchStatus = NULL; //OLE DB interface
//Extra interfaces
m_dwCookieAsynchNotify = 0;
//Data
m_fInitialized = FALSE;
}
/////////////////////////////////////////////////////////////////
// CAsynchBase::~CAsynchBase
//
/////////////////////////////////////////////////////////////////
CAsynchBase::~CAsynchBase()
{
}
/////////////////////////////////////////////////////////////////
// IUnknown** CAsynchBase::GetInterfaceAddress
//
/////////////////////////////////////////////////////////////////
IUnknown** CAsynchBase::GetInterfaceAddress(REFIID riid)
{
HANDLE_GETINTERFACE(IDBInitialize);
HANDLE_GETINTERFACE(IDBAsynchStatus);
//Otherwise delegate
return CContainerBase::GetInterfaceAddress(riid);
}
////////////////////////////////////////////////////////////////
// CAsynchBase::AutoRelease
//
/////////////////////////////////////////////////////////////////
HRESULT CAsynchBase::AutoRelease()
{
//UnadviseListeners
UnadviseListener(IID_IDBAsynchNotify, &m_dwCookieAsynchNotify);
//OLE DB interfaces
RELEASE_INTERFACE(IDBInitialize);
RELEASE_INTERFACE(IDBAsynchStatus);
//Extra interfaces
//Data
m_fInitialized = FALSE;
//Delegate
return CContainerBase::AutoRelease();
}
/////////////////////////////////////////////////////////////////
// HRESULT CAsynchBase::AutoQI
//
/////////////////////////////////////////////////////////////////
HRESULT CAsynchBase::AutoQI(DWORD dwCreateOpts)
{
//Delegate First so we have base interfaces
CContainerBase::AutoQI(dwCreateOpts);
//[MANDATORY]
if(dwCreateOpts & CREATE_QI_MANDATORY)
{
}
//AutoQI
if(dwCreateOpts & CREATE_QI_OPTIONAL)
{
//[OPTIONAL]
OBTAIN_INTERFACE(IDBInitialize);
OBTAIN_INTERFACE(IDBAsynchStatus);
}
//Listeners
AdviseListener(IID_IDBAsynchNotify, &m_dwCookieAsynchNotify);
return S_OK;
}
/////////////////////////////////////////////////////////////////
// HRESULT CAsynchBase::Initialize
//
/////////////////////////////////////////////////////////////////
HRESULT CAsynchBase::Initialize()
{
HRESULT hr = S_OK;
DWORD dwCreateOpts = GetOptions()->m_dwCreateOpts;
if(!m_pIDBInitialize)
goto CLEANUP;
//Initailize
//NOTE: Expect S_OK or DB_E_CANCELED, since canceling the dialog always returns DB_E_CANCELED
XTEST_(hr = m_pIDBInitialize->Initialize(), DB_E_CANCELED);
TRACE_METHOD(hr, L"IDBInitialize::Initialize()");
//Display any property errors...
TESTC(hr = DisplayPropErrors(hr, IID_IDBProperties, m_pIDBInitialize));
//We are now Initialized
m_fInitialized = TRUE;
//Obtain all interfaces, now that we are initialized
TESTC(hr = AutoQI(dwCreateOpts));
//Also "redraw" the object now that more interfaces are available for use
//For Example: If the rowset was originally obtained Asynchronously and now interfaces
//to obtain columns and data are available, display the object...
TESTC(hr = DisplayObject());
CLEANUP:
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CAsynchBase::Uninitialize
//
/////////////////////////////////////////////////////////////////
HRESULT CAsynchBase::Uninitialize()
{
HRESULT hr = S_OK;
if(!m_pIDBInitialize)
goto CLEANUP;
//Uninitailize
XTEST(hr = m_pIDBInitialize->Uninitialize());
TESTC(TRACE_METHOD(hr, L"IDBInitialize::Uninitialize()"));
//We are now Uninitialized
m_fInitialized = FALSE;
CLEANUP:
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CAsynchBase::Abort
//
/////////////////////////////////////////////////////////////////
HRESULT CAsynchBase::Abort(HCHAPTER hChapter, DBASYNCHOP eOperation)
{
HRESULT hr = S_OK;
if(!m_pIDBAsynchStatus)
goto CLEANUP;
//IDBAsynchStatus::Abort
XTEST(hr = m_pIDBAsynchStatus->Abort(hChapter, eOperation));
TRACE_METHOD(hr, L"IDBAsynchStatus::Abort(0x%p, %s)", hChapter, GetAsynchReason(eOperation));
CLEANUP:
return hr;
}
/////////////////////////////////////////////////////////////////
// HRESULT CAsynchBase::GetStatus
//
/////////////////////////////////////////////////////////////////
HRESULT CAsynchBase::GetStatus(HCHAPTER hChapter, DBASYNCHOP eOperation, DBCOUNTITEM* pulProgress, DBCOUNTITEM* pulProgressMax, DBASYNCHPHASE* peAsynchPhase, LPOLESTR* ppwszStatusText)
{
HRESULT hr = S_OK;
if(!m_pIDBAsynchStatus)
goto CLEANUP;
//IDBAsynchStatus::GetStatus
XTEST(hr = m_pIDBAsynchStatus->GetStatus(hChapter, eOperation, pulProgress, pulProgressMax, peAsynchPhase, ppwszStatusText));
TRACE_METHOD(hr, L"IDBAsynchStatus::GetStatus(0x%p, %s, &%lu, &%lu, &%s, &\"%s\")", hChapter, GetAsynchReason(eOperation), pulProgress ? *pulProgress : 0, pulProgressMax ? *pulProgressMax : 0, GetAsynchPhase(peAsynchPhase ? *peAsynchPhase : 0), ppwszStatusText ? *ppwszStatusText : NULL);
CLEANUP:
return hr;
}
/////////////////////////////////////////////////////////////////
// CPropertiesBase::CPropertiesBase
//
/////////////////////////////////////////////////////////////////
CPropertiesBase::CPropertiesBase(SOURCE eObjectType, CMainWindow* pCMainWindow, CMDIChild* pCMDIChild)
: CAsynchBase(eObjectType, pCMainWindow, pCMDIChild)
{
//eBaseClass
m_eBaseClass = BASE_CLASS(m_eBaseClass | eCPropertiesBase);
//OLE DB Interfaces
m_pIDBProperties = NULL; //OLE DB interface
}
/////////////////////////////////////////////////////////////////
// CPropertiesBase::~CPropertiesBase
//
/////////////////////////////////////////////////////////////////
CPropertiesBase::~CPropertiesBase()
{
}
/////////////////////////////////////////////////////////////////
// IUnknown** CPropertiesBase::GetInterfaceAddress
//
/////////////////////////////////////////////////////////////////
IUnknown** CPropertiesBase::GetInterfaceAddress(REFIID riid)
{
HANDLE_GETINTERFACE(IDBProperties);
//Otherwise delegate
return CAsynchBase::GetInterfaceAddress(riid);
}
////////////////////////////////////////////////////////////////
// CPropertiesBase::AutoRelease
//
/////////////////////////////////////////////////////////////////
HRESULT CPropertiesBase::AutoRelease()
{
//OLE DB interfaces
RELEASE_INTERFACE(IDBProperties);
//Delegate
return CAsynchBase::AutoRelease();
}
/////////////////////////////////////////////////////////////////
// HRESULT CPropertiesBase::AutoQI
//
/////////////////////////////////////////////////////////////////
HRESULT CPropertiesBase::AutoQI(DWORD dwCreateOpts)
{
//Delegate First so we have IConnectionPointContainer
CAsynchBase::AutoQI(dwCreateOpts);
//[MANDATORY]
if(dwCreateOpts & CREATE_QI_MANDATORY)
{
OBTAIN_INTERFACE(IDBProperties);
//NOTE: Since this class inherits from CAsynchBase which already has an IDBInitialize
//pointer we will just use that, but the problem is that in the object its an optional
//interface, and under the DSO its a required interface. So we just do a QI again
//if the pointer has not already been retrived...
OBTAIN_INTERFACE(IDBInitialize);
}
//AutoQI
if(dwCreateOpts & CREATE_QI_OPTIONAL)
{
//[OPTIONAL]
}
return S_OK;
}
/////////////////////////////////////////////////////////////////
// HRESULT CPropertiesBase::SetProperties
//
/////////////////////////////////////////////////////////////////
HRESULT CPropertiesBase::SetProperties(ULONG cPropSets, DBPROPSET* rgPropSets)
{
HRESULT hr = S_OK;
if(m_pIDBProperties && cPropSets)
{
//SetProperties
XTEST_(hr = m_pIDBProperties->SetProperties(cPropSets, rgPropSets),S_OK);
TRACE_METHOD(hr, L"IDBProperties::SetProperties(%d, 0x%p)", cPropSets, rgPropSets);
//Display any property errors...
TESTC(hr = DisplayPropErrors(hr, cPropSets, rgPropSets));
}
CLEANUP:
return hr;
}
/////////////////////////////////////////////////////////////////
// GuidToSourceType
//
/////////////////////////////////////////////////////////////////
SOURCE GuidToSourceType(REFGUID guidType)
{
if(guidType == DBGUID_ROWSET)
return eCRowset;
else if(guidType == DBGUID_ROW)
return eCRow;
else if(guidType == DBGUID_COMMAND)
return eCCommand;
else if(guidType == DBGUID_SESSION)
return eCSession;
else if(guidType == DBGUID_DSO)
return eCDataSource;
else if(guidType == DBGUID_STREAM)
return eCStream;
return eCUnknown;
}
////////////////////////////////////////////////////////////////
// DetermineObjectType
//
/////////////////////////////////////////////////////////////////
SOURCE DetermineObjectType(IUnknown* pIUnkObject, SOURCE eSource)
{
//Don't rely upon the caller knowing exactly what the object type is...
//Since many OLE DB methods can return different objects depending upon interface or properties
//requested. So use the "suggested" type as an optimizing starting point, and if not
//then proceed the hard way to determine exactly what it is...
//Do we need to figure out what type of object this is?
if(!pIUnkObject)
return eCUnknown;
IUnknown* pIUnknown = NULL;
HRESULT hr = E_NOINTERFACE;
//See of the object is what the user's "guess" indicates...
//If it is where done...
switch(eSource)
{
case eCRow:
hr = TRACE_QI(pIUnkObject, IID_IRow, &pIUnknown);
break;
case eCRowset:
hr = TRACE_QI(pIUnkObject, IID_IRowset, &pIUnknown);
break;
case eCCommand:
hr = TRACE_QI(pIUnkObject, IID_ICommand, &pIUnknown);
break;
case eCSession:
hr = TRACE_QI(pIUnkObject, IID_IOpenRowset, &pIUnknown);
break;
case eCMultipleResults:
hr = TRACE_QI(pIUnkObject, IID_IMultipleResults, &pIUnknown);
break;
case eCEnumerator:
hr = TRACE_QI(pIUnkObject, IID_ISourcesRowset, &pIUnknown);
break;
case eCBinder:
hr = TRACE_QI(pIUnkObject, IID_IBindResource, &pIUnknown);
break;
case eCDataSource:
//IDBInitialize is no longer enough to fully indentify wither the object returned
//is a DataSource or not. Other objects also have these: ie: Enumerator, Binder, etc
if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_IDBInitialize, &pIUnknown)))
{
TRACE_RELEASE(pIUnknown, L"IDBInitialize");
hr = TRACE_QI(pIUnkObject, IID_IPersist, &pIUnknown);
}
break;
case eCServiceComp:
hr = TRACE_QI(pIUnkObject, IID_IDataInitialize, &pIUnknown);
break;
case eCDataLinks:
hr = TRACE_QI(pIUnkObject, IID_IDBPromptInitialize, &pIUnknown);
break;
case eCStream:
//Some providers for some reason may not support the inherited ISequentialStream interface
if(FAILED(hr = TRACE_QI(pIUnkObject, IID_ISequentialStream, &pIUnknown)))
hr = TRACE_QI(pIUnkObject, IID_IStream, &pIUnknown);
break;
case eCDataset:
hr = TRACE_QI(pIUnkObject, IID_IMDDataset, &pIUnknown);
break;
case eCRowPosition:
hr = TRACE_QI(pIUnkObject, IID_IRowPosition, &pIUnknown);
break;
case eCTransaction:
hr = TRACE_QI(pIUnkObject, IID_ITransaction, &pIUnknown);
break;
case eCTransactionOptions:
hr = TRACE_QI(pIUnkObject, IID_ITransactionOptions, &pIUnknown);
break;
case eCError:
hr = TRACE_QI(pIUnkObject, IID_IErrorInfo, &pIUnknown);
break;
case eCCustomError:
hr = TRACE_QI(pIUnkObject, IID_ISQLErrorInfo, &pIUnknown);
break;
case eCConnectionPoint:
hr = TRACE_QI(pIUnkObject, IID_IConnectionPoint, &pIUnknown);
break;
default:
hr = E_NOINTERFACE;
break;
};
//If the object doesn't match the users guess we will need to try and determine what it really is...
if(FAILED(hr))
{
//Since many objects support the same interface,
//we need to actually QI for a "unique" interface on that object
//to determine what type of object it really is...
if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_IRow, &pIUnknown)))
eSource = eCRow;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_IRowset, &pIUnknown)))
eSource = eCRowset;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_ICommand, &pIUnknown)))
eSource = eCCommand;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_IOpenRowset, &pIUnknown)))
eSource = eCSession;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_IMultipleResults, &pIUnknown)))
eSource = eCMultipleResults;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_ISourcesRowset, &pIUnknown)))
eSource = eCEnumerator;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_IBindResource, &pIUnknown)))
eSource = eCBinder;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_IDBProperties, &pIUnknown)))
eSource = eCDataSource;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_IDataInitialize, &pIUnknown)))
eSource = eCServiceComp;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_IDBPromptInitialize, &pIUnknown)))
eSource = eCDataLinks;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_ISequentialStream, &pIUnknown)) || SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_IStream, &pIUnknown)))
eSource = eCStream;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_IMDDataset, &pIUnknown)))
eSource = eCDataset;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_IRowPosition, &pIUnknown)))
eSource = eCRowPosition;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_ITransaction, &pIUnknown)))
eSource = eCTransaction;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_ITransactionOptions, &pIUnknown)))
eSource = eCTransactionOptions;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_IErrorInfo, &pIUnknown)))
eSource = eCError;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_ISQLErrorInfo, &pIUnknown)))
eSource = eCCustomError;
else if(SUCCEEDED(hr = TRACE_QI(pIUnkObject, IID_IConnectionPoint, &pIUnknown)))
eSource = eCConnectionPoint;
else
eSource = eCUnknown;
}
if(SUCCEEDED(hr))
TRACE_RELEASE(pIUnknown, L"IUnknown");
return eSource;
}