Connecting to an MDP by Using the Root Enumerator

Connection to a 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:

//
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.
   ULONG cBindings = 5;
   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, 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;
   ULONG cRowsObtained = 0;
   ULONG cEnumInfo = 0;
   ENUMINFO* rgEnumInfo;
   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 (ULONG 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;
}