OLEDB Providers Enumeration

 

By: AdvanCode [2004-12-01]
Read: 3350 times

The question is: how can we get all OLEDB providers available? This could be done, relatively simply using VC++, but there aren't a simply solution for VB users. So, we'll try to make an ATL component to be used both in VC++ or VB projects.

There are at least 2 solutions for the problem - the first one is to use ADO and the other is using OLE DB interfaces.

Using ADO is simply to return an ADODB.Recordset containing all the informations. An example could be found here (Copyright 2002 Bob Beauchemin). Mainly, this is done like this (after you added ADO support):

STDMETHODIMP CGetProvRS::GetProvRS(VARIANT *pvRecordset)
{
	Recordset20Ptr spRs;
	ADORecordsetConstructionPtr spADOsCt;
	VariantInit(pvRecordset);

	CEnumerator cenum;
	HRESULT hr;

	// Root enumerator is the default

	hr = cenum.Open();
	
	if (FAILED(hr)) 
		goto cleanup;

	hr = spRs.CreateInstance(__uuidof(Recordset));
	if (FAILED(hr))
		goto cleanup;

    hr = spRs->QueryInterface(__uuidof(ADORecordsetConstruction), 
				(void **)&spADOsCt);
	if (FAILED(hr))
		goto cleanup;

	hr = spADOsCt->put_Rowset(cenum.m_spRowset);
	if (FAILED(hr))
		goto cleanup;

	pvRecordset->vt = VT_DISPATCH;
	pvRecordset->pdispVal = (IDispatch*)spRs.Detach();

cleanup:
	cenum.Close();

	return hr;
}

Doing so, the method is returning an ADODB.Recordset that can be used in VB applications, for instance. The names of the fields returned are:

col 0:                           size 4    type DBTYPE_UI4
col 1: name SOURCES_NAME         size 255  type DBTYPE_WSTR
col 2: name SOURCES_PARSENAME    size 255  type DBTYPE_WSTR
col 3: name SOURCES_DESCRIPTION  size 255  type DBTYPE_WSTR
col 4: name SOURCES_TYPE         size 2    type DBTYPE_UI2
col 5: name SOURCES_ISPARENT     size 2    type DBTYPE_BOOL
col 6: name SOURCES_CLSID        size 255  type DBTYPE_WSTR 

All the details can be found here.

A VB example of using the component could be as below:

    Dim rs As Recordset
    Dim provrs As New GetProvRS
    Dim i As Integer
    
    Set rs = provrs.GetProvRS()
    
    While Not rs.EOF
        For i = 0 To rs.Fields.Count - 1
            Debug.Print "Field: " & rs(i).Name & " = " & rs(i).Value
        Next i
        Debug.Print
    
        rs.MoveNext
    Wend

The other solution is by using OLEDB interfaces, directly, as presented in "Teach Yourself Database Programming with Visual C++ 6 in 21 Days" (cap. 17), from Sams Publishing or this example from Microsoft KB (in italian).

Below, there is the source code for an ATL component that return all providers as variant-array, which is simply to use in VB. Create a new component using ATL COM AppWizard and add a new ATL object called "Providers". Include the libraries and the constants as below (in Providers.cpp):

#include 
#include 
#include 

typedef struct EnumProvidersRow
{
   UINT num;
   char SourceName[255];
   char ParseName[255];
   char SourceDesc[255];
   USHORT SourceType;
   BOOL IsParent;
   char SourceCLSID[255];
} ENUMPROVIDERSROW;

#define COLS 7
#define ROWS 10

Then add the following code in a new created method called GetProviders([out, retval] VARIANT* res):

STDMETHODIMP CProviders::GetProviders(VARIANT *res)
{
	// TODO: Add your implementation code here

   ISourcesRowset* pSrcRowset;
   IRowset* pRowset;
   IAccessor* pAccessor;
   HACCESSOR hAccessor;
   ENUMPROVIDERSROW Rows;
   DBBINDING Binding[COLS];
   DBBINDSTATUS BindingStatus[COLS];
   ULONG Feched;
   HROW* phRow = new HROW[ROWS];
   ZeroMemory( &Binding[0], sizeof(DBBINDING) * COLS);

   HRESULT hr = CoCreateInstance(CLSID_OLEDB_ENUMERATOR, NULL, 
			CLSCTX_INPROC_SERVER, IID_ISourcesRowset, (LPVOID*)&pSrcRowset);
   if( hr == S_OK )
   {
      hr = pSrcRowset->GetSourcesRowset( NULL, IID_IRowset, 0, NULL, 
					(LPUNKNOWN*)&pRowset);
      pSrcRowset->Release();
      
      if(  hr == S_OK )
      {
         hr = pRowset->QueryInterface(IID_IAccessor, (LPVOID*)&pAccessor);
         if(  hr == S_OK )
         {
            Binding[0].iOrdinal = 0;
            Binding[0].obValue = offsetof(ENUMPROVIDERSROW, num);
            Binding[0].dwPart = DBPART_VALUE;
            Binding[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
            Binding[0].eParamIO = DBPARAMIO_NOTPARAM;
            Binding[0].wType = DBTYPE_UI4;

            Binding[1].iOrdinal = 1;
            Binding[1].obValue = offsetof(ENUMPROVIDERSROW, SourceName);
            Binding[1].dwPart = DBPART_VALUE;
            Binding[1].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
            Binding[1].eParamIO = DBPARAMIO_NOTPARAM;
            Binding[1].wType = DBTYPE_STR;
            Binding[1].cbMaxLen = 255;

            Binding[2].iOrdinal = 2;
            Binding[2].obValue = offsetof(ENUMPROVIDERSROW, ParseName);
            Binding[2].dwPart = DBPART_VALUE;
            Binding[2].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
            Binding[2].eParamIO = DBPARAMIO_NOTPARAM;
            Binding[2].wType = DBTYPE_STR;
            Binding[2].cbMaxLen = 255;

            Binding[3].iOrdinal = 3;
            Binding[3].obValue = offsetof(ENUMPROVIDERSROW, SourceDesc);
            Binding[3].dwPart = DBPART_VALUE;
            Binding[3].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
            Binding[3].eParamIO = DBPARAMIO_NOTPARAM;
            Binding[3].wType = DBTYPE_STR;
            Binding[3].cbMaxLen = 255;

            Binding[4].iOrdinal = 4;
            Binding[4].obValue = offsetof(ENUMPROVIDERSROW, SourceType);
            Binding[4].dwPart = DBPART_VALUE;
            Binding[4].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
            Binding[4].eParamIO = DBPARAMIO_NOTPARAM;
            Binding[4].wType = DBTYPE_UI2;

            Binding[5].iOrdinal = 5;
            Binding[5].obValue = offsetof(ENUMPROVIDERSROW, IsParent);
            Binding[5].dwPart = DBPART_VALUE;
            Binding[5].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
            Binding[5].eParamIO = DBPARAMIO_NOTPARAM;
            Binding[5].wType = DBTYPE_BOOL;

            Binding[6].iOrdinal = 6;
            Binding[6].obValue = offsetof(ENUMPROVIDERSROW, SourceCLSID);
            Binding[6].dwPart = DBPART_VALUE;
            Binding[6].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
            Binding[6].eParamIO = DBPARAMIO_NOTPARAM;
            Binding[6].wType = DBTYPE_STR;
            Binding[6].cbMaxLen = 255;
            
            hr = pAccessor->CreateAccessor( DBACCESSOR_ROWDATA, COLS, 
						&Binding[0], 0, &hAccessor, &BindingStatus[0]);
            
            if(  hr == S_OK )
            {
               hr = pRowset->RestartPosition( DB_NULL_HCHAPTER );
               while(true)
               {
                  hr = pRowset->GetNextRows( DB_NULL_HCHAPTER, 0, ROWS, 
							&Feched, &phRow);
                  if(  (hr == S_OK || hr == DB_S_ENDOFROWSET) && Feched )
                  {
					 SAFEARRAYBOUND MyBound[2];
					 MyBound[0].cElements = Feched-2; //first item lost
					 MyBound[1].cElements = Feched-2;
					 MyBound[0].lLbound  = 0;
					 MyBound[1].lLbound = 0;
					 
					 res->vt = VT_VARIANT | VT_ARRAY; 
					 res->parray = SafeArrayCreate(VT_VARIANT,2,MyBound);
					 long MyPosition[2];
					 VARIANT tmp;
					 VariantInit(&tmp);

                     for(int i=0; i<(int)Feched; i++)
                     {
                        pRowset->GetData( phRow[i], hAccessor, 
								(LPVOID)&Rows);

						MyPosition[0] = i;
						MyPosition[1] = 0;
						tmp.vt =VT_BSTR;
						tmp.bstrVal = SysAllocString(A2BSTR(Rows.SourceName));
						SafeArrayPutElement(res->parray,MyPosition,&tmp);

						MyPosition[1] = 1;
						SysFreeString(tmp.bstrVal);
						tmp.bstrVal = SysAllocString(A2BSTR(Rows.ParseName));
						SafeArrayPutElement(res->parray,MyPosition,&tmp);

						MyPosition[1] = 2;
						SysFreeString(tmp.bstrVal);
						tmp.bstrVal = SysAllocString(A2BSTR(Rows.SourceDesc));
						SafeArrayPutElement(res->parray,MyPosition,&tmp);

						MyPosition[1] = 3;
						SysFreeString(tmp.bstrVal);
						tmp.vt = VT_I2;
						tmp.iVal = Rows.SourceType ;
						SafeArrayPutElement(res->parray,MyPosition,&tmp);

						MyPosition[1] = 4;
						tmp.vt = VT_BOOL;
						tmp.boolVal  = Rows.IsParent ;
						SafeArrayPutElement(res->parray,MyPosition,&tmp);

						MyPosition[1] = 5;
						tmp.vt = VT_BSTR;
						tmp.bstrVal = SysAllocString(A2BSTR(Rows.SourceCLSID));
						SafeArrayPutElement(res->parray,MyPosition,&tmp);
						SysFreeString(tmp.bstrVal);

                     }
                     pRowset->ReleaseRows( Feched, phRow, NULL, NULL, NULL);
                     if( hr == DB_S_ENDOFROWSET)
                        break;
                  }
                  else
                     break;
               }
               pAccessor->ReleaseAccessor( hAccessor, NULL);
            }
            pAccessor->Release();
         }
         pRowset->Release();
      }
   }
   delete[] phRow;

   return hr;
}

To use it in a VB project is straightforward - add a reference to "AllProvs 1.0 Type Library" and add the code:

Dim x As New ALLPROVSLib.Providers

Private Sub Command1_Click()
Dim a As Variant
a = x.GetProviders
For i = 0 To UBound(a, 1)
    For j = 0 To UBound(a, 2)
        Debug.Print a(i, j) & " - ";
    Next
Debug.Print
Next
End Sub
原文网址:http://www.advancode.com/articles.php?page=oledbproviders

你可能感兴趣的:(技术心得,binding,null,vb,constants,returning,microsoft)