Connecting to an MDP by Using the Root Enumerator

Connection to an MDP requires using the root enumerator to create a rowset representing all OLE DB providers. This function returns a pointer to the IDBInitialize interface for an MDP data source object:

//

HRESULT MDPConnectUsingRootEnum(IDBInitialize** ppIDBInitialize)
{
   HRESULT hr;
   assert(*ppIDBInitialize == NULL);

   // The ENUMINFO structure is used to bind data source
   // rowset data for the provider list.
   struct ENUMINFO
   {
      WCHAR          wszName[MAX_NAME_LEN];
      WCHAR          wszParseName[MAX_NAME_LEN];
      WCHAR          wszDescription[MAX_NAME_LEN];
      DBTYPE         wType;
      VARIANT_BOOL   fIsParent;
   };

   // Initialize the OLE DB enumerator and obtain rowset.
   ISourcesRowset* pISourcesRowset = NULL;
   hr = CoCreateInstance(CLSID_OLEDB_ENUMERATOR, NULL,
                         CLSCTX_INPROC_SERVER, IID_ISourcesRowset,
                         (void**)&pISourcesRowset);

   IRowset* pIRowset = NULL;
   hr = pISourcesRowset->GetSourcesRowset(NULL,
      IID_IRowset, 0, NULL, (IUnknown**)&pIRowset);

   // Create accessor.
   IAccessor* pIAccessor = NULL;
   hr = pIRowset->QueryInterface(IID_IAccessor, (void**)&pIAccessor);

   // rgBindings array defines column data to be bound
   // to the ENUMINFO data structure.
   DBCOUNTITEM cBindings = 5;
   DBBINDING rgBindings[5] =
   {
      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, wType), 0, 0, NULL, NULL, NULL, DBPART_VALUE,
         DBMEMOWNER_CLIENTOWNED, DBPARAMIO_NOTPARAM, sizeof(DBTYPE), 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,
   };

   HACCESSOR hAccessor = DB_NULL_HACCESSOR;
   hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,
      cBindings, rgBindings, 0, &hAccessor, NULL);

   // Obtain IParseDisplayName interface.
   IParseDisplayName*   pIParseDisplayName = NULL;
   hr = pISourcesRowset->QueryInterface(IID_IParseDisplayName,
        (void**)&pIParseDisplayName);

   // Loop through the entire returned rowset.
   HROW* rghRows = NULL;
   DBRCOUNTITEM cRowsObtained = 0;
   ULONG cEnumInfo = 0;
   ENUMINFO* rgEnumInfo = NULL;
   while (SUCCEEDED(hr))
   {
      hr = pIRowset->GetNextRows(NULL, 0, 20, &cRowsObtained, &rghRows);
      if (FAILED(hr)) break;
      
      if (cRowsObtained == 0)
      {
         // ENDOFROWSET
         break;
      }
      
      // Alloc room for ProviderInfo (in chunks).
      rgEnumInfo =
         (ENUMINFO*)CoTaskMemRealloc(rgEnumInfo,
         (cEnumInfo+cRowsObtained) * sizeof(ENUMINFO));
      memset(&rgEnumInfo[cEnumInfo], 0,
         sizeof(ENUMINFO)*cRowsObtained);

      // Loop over rows obtained and get ProviderInfo.
      for (DBCOUNTITEM i=0; i<cRowsObtained; i++)
      {   
         // Get the data.
         hr = pIRowset->GetData(rghRows[i], hAccessor,
            (void*)&rgEnumInfo[cEnumInfo]);
         if (FAILED(hr)) break;
         cEnumInfo++;
      }
         
      // Release all the rows.
      hr = pIRowset->ReleaseRows(cRowsObtained, rghRows, NULL, NULL,
                                  NULL);
      CoTaskMemFree(rghRows);
      rghRows = NULL;
   }

   // If successfully obtained a set of providers...
   if (SUCCEEDED(hr) && cEnumInfo)
   {
      // rgEnumInfo[cEnumInfo] contains enumerated info
      // for all providers.
      for (ULONG i=0; i<cEnumInfo; i++)
      {
         // Find multidimensional provider and connect
         // with IParseDisplayName.
         if (rgEnumInfo[i].wType == DBSOURCETYPE_DATASOURCE_MDP)
         {
            // Connect to MDP provider using IMoniker.
            // Create binding context; use default options.
            IBindCtx* pIBindCtx = NULL;
            hr = CreateBindCtx(0, &pIBindCtx);

            if (SUCCEEDED(hr))
            {
               ULONG chEaten = 0;
               IMoniker* pIMoniker = NULL;
               hr = pIParseDisplayName->ParseDisplayName(pIBindCtx,
                  rgEnumInfo[i].wszParseName, &chEaten, &pIMoniker);
            }
            if (SUCCEEDED(hr))
            {
                hr = BindMoniker(pIMoniker, 0, IID_IUnknown,
                   (void**)&pIDBInitialize);
            }
            if (pIBindCtx) pIBindCtx->Release();
            if (pIMoniker) pIMoniker->Release();

            if (SUCCEEDED(hr))
            {
                // If ParseDisplayName() and BindMoniker() have
                // succeeded, pIDBInitialize is a valid
                // interface pointer to the MDP data source.
                break;
            }
         }
      }
   }

   // Free enum info and rowset handles.
   CoTaskMemFree(rgEnumInfo);
   CoTaskMemFree(rghRows);
   hr = pIParseDisplayName->Release();
   hr = pIAccessor->ReleaseAccessor(hAccessor,NULL);
   hr = pIAccessor->Release();
   hr = pIRowset->Release();
   hr = pISourcesRowset->Release();
   return hr;
}