//----------------------------------------------------------------------------- // Microsoft OLE DB RowsetViewer // Copyright (C) 1994 - 1999 By Microsoft Corporation. // // @doc // // @module CENUM.CPP // //----------------------------------------------------------------------------------- ///////////////////////////////////////////////////////////////// // Includes // ///////////////////////////////////////////////////////////////// #include "Headers.h" ///////////////////////////////////////////////////////////////// // CEnumerator::CEnumerator // ///////////////////////////////////////////////////////////////// CEnumerator::CEnumerator(CMainWindow* pCMainWindow, CMDIChild* pCMDIChild) : CPropertiesBase(eCEnumerator, pCMainWindow, pCMDIChild) { //[MANDATORY] m_pISourcesRowset = NULL; //Enumerator interface m_pIParseDisplayName = NULL; //Enumerator interface //[OPTIONAL] //Enumerator ProvierInfo m_cEnumInfo = 0; m_rgEnumInfo = NULL; } ///////////////////////////////////////////////////////////////// // CEnumerator::~CEnumerator // ///////////////////////////////////////////////////////////////// CEnumerator::~CEnumerator() { ReleaseObject(0); m_cEnumInfo = 0; SAFE_FREE(m_rgEnumInfo); } ///////////////////////////////////////////////////////////////// // IUnknown** CEnumerator::GetInterfaceAddress // ///////////////////////////////////////////////////////////////// IUnknown** CEnumerator::GetInterfaceAddress(REFIID riid) { HANDLE_GETINTERFACE(ISourcesRowset); HANDLE_GETINTERFACE(IParseDisplayName); //Otherwise delegate return CPropertiesBase::GetInterfaceAddress(riid); } ///////////////////////////////////////////////////////////////// // CEnumerator::AutoRelease // ///////////////////////////////////////////////////////////////// HRESULT CEnumerator::AutoRelease() { //[MANDATORY] RELEASE_INTERFACE(ISourcesRowset); RELEASE_INTERFACE(IParseDisplayName); //[OPTIONAL] //Delegate return CPropertiesBase::AutoRelease(); } ///////////////////////////////////////////////////////////////// // HRESULT CEnumerator::AutoQI // ///////////////////////////////////////////////////////////////// HRESULT CEnumerator::AutoQI(DWORD dwCreateOpts) { //Delegate First so we have base interfaces CPropertiesBase::AutoQI(dwCreateOpts); //[MANDATORY] if(dwCreateOpts & CREATE_QI_MANDATORY) { OBTAIN_INTERFACE(IParseDisplayName); OBTAIN_INTERFACE(ISourcesRowset); } //AutoQI if(dwCreateOpts & CREATE_QI_OPTIONAL) { //[OPTIONAL] } return S_OK; } ///////////////////////////////////////////////////////////////////////////// // CEnumerator::GetObjectDesc // ///////////////////////////////////////////////////////////////////////////// WCHAR* CEnumerator::GetObjectDesc() { if(!m_strObjectDesc && m_guidSource != GUID_NULL) { if(m_guidSource == CLSID_OLEDB_ENUMERATOR) m_strObjectDesc.CopyFrom(L"Root Enumerator"); else m_strObjectDesc.CopyFrom(GetProgID(m_guidSource)); } return m_strObjectDesc; } //////////////////////////////////////////////////////////////// // CEnumerator::OnDefOperation // ///////////////////////////////////////////////////////////////// void CEnumerator::OnDefOperation() { if(m_pISourcesRowset) m_pCMainWindow->DisplayDialog(IDD_GETSOURCESROWSET, GetFocus(), CMainWindow::GetSourcesRowsetProc, this); } ///////////////////////////////////////////////////////////////////////////// // HRESULT CEnumerator::ParseDisplayName // ///////////////////////////////////////////////////////////////////////////// HRESULT CEnumerator::ParseDisplayName(WCHAR* pwszParseName, DWORD dwCLSCTX, REFIID riid, IUnknown** ppIUnknown, CBase** ppCSource, DWORD dwConnectOpts, WCHAR* pwszRemoteServer) { ASSERT(pwszParseName); CComPtr spMoniker; CComPtr spBindCtx; ULONG chEaten = 0; CLSID clsid; HRESULT hr = E_FAIL; CBase* pCSource = NULL; //Try and use ParseDisplayName //Otherwise we may be forced to just try CoCreateInstance if not installed... //Also cannot use ParseDisplayName if trying to aggregate ServiceComponents if(m_pIParseDisplayName && !(dwConnectOpts & CREATE_USESERVICECOMP)) { if(dwCLSCTX) { //Setup BIND_OPTS BIND_OPTS2 BindOps2; BindOps2.cbStruct = sizeof(BIND_OPTS2); BindOps2.grfFlags = BIND_MAYBOTHERUSER; BindOps2.grfMode = STGM_READWRITE; BindOps2.dwTickCountDeadline = 0; BindOps2.dwTrackFlags = 1; BindOps2.dwClassContext = dwCLSCTX; BindOps2.locale = GetSystemDefaultLCID(); BindOps2.pServerInfo = NULL; //Setup ServerInfo just incase we need it... COSERVERINFO ServerInfo = { 0, pwszRemoteServer, NULL, 0}; //Setup RemoteServer is specified if(dwCLSCTX & CLSCTX_REMOTE_SERVER) BindOps2.pServerInfo = &ServerInfo; //If this fails for some reason, we can still continue... hr = CreateBindCtx(0, &spBindCtx); if(SUCCEEDED(hr) && spBindCtx) hr = spBindCtx->SetBindOptions(&BindOps2); //If it does fail we will just release the Bind Context and pass //IParseDisplayName NULL and let it choose the CLXCTX... if(FAILED(hr)) spBindCtx.Release(); } //ParseDisplayName //Don't display error, since we have our own retry logic... hr = m_pIParseDisplayName->ParseDisplayName(spBindCtx, pwszParseName, &chEaten, &spMoniker); TRACE_METHOD(hr, L"IParseDisplayName::ParseDisplayName(0x%p, \"%s\", &%d, &0x%p)", spBindCtx, pwszParseName, chEaten, spMoniker); if(SUCCEEDED(hr)) { XTEST(hr = BindMoniker(spMoniker, 0, riid, (void**)ppIUnknown)); TESTC(TRACE_METHOD(hr, L"BindMoniker(0x%p, 0, %s, &0x%p)", spBindCtx, GetInterfaceName(riid), ppIUnknown ? *ppIUnknown : NULL)); pCSource = this; } } //If Not using RootEnum or for some reason the RootEnum failed, if(m_pIParseDisplayName == NULL || FAILED(hr)) { //Find the CLSID from the ParseName //The user may have entered a ProgID or a CLSID //Since the ParseName is a CLSID, try the common case first... if(FAILED(hr = CLSIDFromString(pwszParseName, &clsid))) XTESTC(hr = CLSIDFromProgID(pwszParseName, &clsid)); //If using Service Components if(dwConnectOpts & CREATE_USESERVICECOMP) { if(dwCLSCTX == CLSCTX_INPROC_SERVER) { //Can just reuse our Main DataLink object... TESTC(hr = m_pCMainWindow->m_pCServiceComp->CreateDBInstance(clsid, NULL, CLSCTX_INPROC_SERVER, riid, ppIUnknown)); pCSource = m_pCMainWindow->m_pCServiceComp; } else { //If not inproc we just create a stand alone Data Link object //We do this again here, incase you want Remoted Providers... CServiceComp* pCServiceComp = new CServiceComp(m_pCMainWindow); TESTC(pCServiceComp->Create(NULL, dwCLSCTX, pwszRemoteServer)); //The provider is always "inproc" to wherever the ServiceComponents are: TESTC(hr = pCServiceComp->CreateDBInstance(clsid, NULL, CLSCTX_INPROC_SERVER, riid, ppIUnknown)); pCSource = pCServiceComp; } } else { //Delegate XTESTC(hr = CreateInstance(NULL, clsid, dwCLSCTX, riid, ppIUnknown, pwszRemoteServer)); pCSource = NULL; } } CLEANUP: if(ppCSource) *ppCSource = pCSource; return hr; } ///////////////////////////////////////////////////////////////// // HRESULT CEnumerator::GetSourcesRowset // ///////////////////////////////////////////////////////////////// HRESULT CEnumerator::GetSourcesRowset(CAggregate* pCAggregate, REFIID riid, ULONG cPropSets, DBPROPSET* rgPropSets, IUnknown** ppIUnknown) { HRESULT hr = S_OK; if(m_pISourcesRowset) { XTEST_(hr = m_pISourcesRowset->GetSourcesRowset(pCAggregate, riid, cPropSets, rgPropSets, ppIUnknown),S_OK); TRACE_METHOD(hr, L"ISourcesRowset::GetSourcesRowset(0x%p, %s, %d, 0x%p, &0x%p)", pCAggregate, GetInterfaceName(riid), cPropSets, rgPropSets, ppIUnknown ? *ppIUnknown : NULL); } //Display Errors (if occurred) TESTC(hr = DisplayPropErrors(hr, cPropSets, rgPropSets)); //Handle Aggregation if(pCAggregate) TESTC(hr = pCAggregate->HandleAggregation(riid, ppIUnknown)); CLEANUP: return hr; } WINOLEAPI CoCreateInstanceEx(REFCLSID, IUnknown*, DWORD, COSERVERINFO*, DWORD, MULTI_QI*); ///////////////////////////////////////////////////////////////////////////// // HRESULT CEnumerator::CreateInstance // ///////////////////////////////////////////////////////////////////////////// HRESULT CEnumerator::CreateInstance(CAggregate* pCAggregate, REFCLSID clsid, DWORD dwCLSCTX, REFIID riid, IUnknown** ppIUnknown, WCHAR* pwszRemoteServer) { HRESULT hr = S_OK; //CLSID to String (just for display purposes...) WCHAR* pwszProgID = GetProgID(clsid); //Determine which method to use... if(dwCLSCTX & CLSCTX_REMOTE_SERVER) { //Setup ServerInfo... COSERVERINFO ServerInfo = { 0, pwszRemoteServer, NULL, 0}; MULTI_QI MultiQI = { &riid, NULL, S_OK}; //CoCreateInstanceEx hr = CoCreateInstanceEx(clsid, pCAggregate, dwCLSCTX, &ServerInfo, 1, &MultiQI); TESTC(TRACE_METHOD(hr, L"CoCreateInstanceEx(%s, 0x%p, 0x%08x, 0x%p, 1, 0x%p)", pwszProgID, pCAggregate, dwCLSCTX, &ServerInfo, &MultiQI)); //Output pointer from the MultiQI if(ppIUnknown) *ppIUnknown = MultiQI.pItf; } else { //CoCreateInstance hr = CoCreateInstance(clsid, pCAggregate, dwCLSCTX, riid, (void**)ppIUnknown); TESTC(TRACE_METHOD(hr, L"CoCreateInstance(%s, 0x%p, 0x%08x, %s, &0x%p)", pwszProgID, pCAggregate, dwCLSCTX, GetInterfaceName(riid), ppIUnknown ? *ppIUnknown : NULL)); } //Handle Aggregation if(pCAggregate) TESTC(hr = pCAggregate->HandleAggregation(riid, ppIUnknown)); CLEANUP: SAFE_FREE(pwszProgID); return hr; } ///////////////////////////////////////////////////////////////////////////// // HRESULT CEnumerator::Create // ///////////////////////////////////////////////////////////////////////////// HRESULT CEnumerator::Create(REFCLSID clsid) { HRESULT hr = S_OK; CComPtr spParseDisplayName; //Initialize the Enumerator and Obtain rowset m_guidSource = clsid; TESTC(hr = CreateInstance(NULL, clsid, CLSCTX_ALL, IID_IParseDisplayName, (IUnknown**)&spParseDisplayName)); //Now Delegate to our generic Enumerator method TESTC(hr = CreateObject(NULL, IID_IParseDisplayName, spParseDisplayName)); CLEANUP: return hr; } ///////////////////////////////////////////////////////////////////////////// // HRESULT CEnumerator::CreateEnumInfo // ///////////////////////////////////////////////////////////////////////////// HRESULT CEnumerator::CreateEnumInfo(REFCLSID clsid, BOOL fRefresh) { HRESULT hr = S_OK; //Create the Enumerator, if we haven't already... if(clsid!=GUID_NULL && !m_pIParseDisplayName) TESTC(hr = Create(clsid)); //Free Previous Info if(fRefresh || !m_cEnumInfo) { m_cEnumInfo = 0; SAFE_FREE(m_rgEnumInfo) //Obtain the Enumerator Info from the rowset... TESTC(hr = EnumerateInfo(&m_cEnumInfo, &m_rgEnumInfo)); } CLEANUP: return hr; } ///////////////////////////////////////////////////////////////////////////// // HRESULT CEnumerator::EnumerateInfo // ///////////////////////////////////////////////////////////////////////////// HRESULT CEnumerator::EnumerateInfo(ULONG* pcEnumInfo, ENUMINFO** prgEnumInfo) { HRESULT hr = E_FAIL; ASSERT(pcEnumInfo); ASSERT(prgEnumInfo); HROW rghRows[MAX_BLOCK_SIZE]; HROW* phRows = rghRows; DBCOUNTITEM cRowsObtained = 0; CComPtr spRowset = NULL; HACCESSOR hAccessor = DB_NULL_HACCESSOR; CRowset cRowset(m_pCMainWindow); //Make our lives easier ULONG cEnumInfo = 0; ENUMINFO* rgEnumInfo = NULL; // Bind the user and table name for the list const static DBCOUNTITEM cBindings = 5; const static DBBINDING rgBindings[cBindings] = { 1, offsetof(ENUMINFO, wszName), 0, 0, NULL, NULL, NULL, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, MAX_NAME_LEN, 0, DBTYPE_WSTR, 0, 0, 2, offsetof(ENUMINFO, wszParseName), 0, 0, NULL, NULL, NULL, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, MAX_NAME_LEN, 0, DBTYPE_WSTR, 0, 0, 3, offsetof(ENUMINFO, wszDescription), 0, 0, NULL, NULL, NULL, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, MAX_NAME_LEN, 0, DBTYPE_WSTR, 0, 0, 4, offsetof(ENUMINFO, eType), 0, 0, NULL, NULL, NULL, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof(USHORT), 0, DBTYPE_UI2, 0, 0, 5, offsetof(ENUMINFO, fIsParent), 0, 0, NULL, NULL, NULL, DBPART_VALUE, DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof(VARIANT_BOOL), 0, DBTYPE_BOOL, 0, 0, }; //ISourcesRowset::GetSourcesRowset TESTC(hr = GetSourcesRowset(NULL, IID_IRowset, 0, NULL, (IUnknown**)&spRowset)); TESTC(hr = cRowset.CreateObject(this, IID_IRowset, spRowset)); //Create Accessor TESTC(hr = cRowset.CreateAccessor(DBACCESSOR_ROWDATA, cBindings, (DBBINDING*)rgBindings, 0, &hAccessor)); //Loop through the entire returned rowset while(TRUE) { TESTC(hr = cRowset.GetNextRows(0, MAX_BLOCK_SIZE, &cRowsObtained, &phRows)); //ENDOFROWSET if(cRowsObtained==0) break; //Alloc room for ProviderInfo (in chunks) SAFE_REALLOC(rgEnumInfo, ENUMINFO, cEnumInfo + cRowsObtained); memset(&rgEnumInfo[cEnumInfo], 0, sizeof(ENUMINFO) * (size_t)cRowsObtained); //Loop over rows obtained and get ProviderInfo for(ULONG i=0; i