Перечисление источников данных OLE DB (OLE DB)

В этом образце показано, как использовать объект перечислителя для построения списка доступных источников данных.

Для перечисления источников данных, видимых перечислителю SQLOLEDB, потребитель вызывает метод ISourcesRowset::GetSourcesRowset. Этот метод возвращает набор строк информации о видимых в настоящее время источниках данных.

В зависимости от используемой сетевой библиотеки проводится поиск источников данных в соответствующем домене. Для именованных каналов это домен, в который загружен клиент. Для AppleTalk это зона по умолчанию. Для SPX/IPX это список установок SQL Server, найденный в системной базе данных. Для Banyan VINES это установки SQL Server, найденные в локальной сети. Сокеты Multiprotocol и TCP/IP не поддерживаются.

При выключении и включении сервера может потребоваться несколько минут на обновление информации об этих доменах.

Образцу требуется образец базы данных AdventureWorks, который можно загрузить с домашней страницы Образцы кода и проекты сообщества Microsoft SQL Server (возможно, на английском языке).

Примечание по безопасностиПримечание по безопасности

По возможности используйте проверку подлинности Windows. Если проверка подлинности Windows недоступна, запросите у пользователя ввод учетных данных во время выполнения. Избегайте хранения учетных данных в файле. Если необходимо сохранить учетные данные, зашифруйте их с помощью API-интерфейса шифрования Win32.

Перечисление источников данных OLE DB

  1. Получите набор строк путем вызова метода ISourceRowset::GetSourcesRowset.

  2. Найдите описание набора строк перечислителей путем вызова метода GetColumnInfo::IColumnInfo.

  3. Создайте структуры привязки на основе информации о столбцах.

  4. Создайте метод доступа к набору строк путем вызова метода IAccessor::CreateAccessor.

  5. Выберите строки путем вызова метода IRowset::GetNextRows.

  6. Получите данные из копии строки, находящейся в наборе строк, путем вызова метода IRowset::GetData и обработайте их.

Пример

Скомпилируйте с библиотекой ole32.lib и выполните следующий листинг кода C++. Это приложение соединяется с установленным на компьютер экземпляром SQL Server по умолчанию. В некоторых операционных системах Windows придется заменить (localhost) или (local) на имя своего экземпляра SQL Server. Чтобы соединиться с именованным экземпляром, замените в строке подключения L«(local)» на L«(local)\\имя», где имя — это именованный экземпляр. По умолчанию SQL Server Express устанавливается на именованный экземпляр. Убедитесь, что переменная среды INCLUDE включает каталог, содержащий файл sqlncli.h.

// compile with: ole32.lib
#define UNICODE
#define _UNICODE
#define DBINITCONSTANTS
#define INITGUID
#define OLEDBVER 0x0250   // to include correct interfaces

#include <windows.h>
#include <stddef.h>
#include <oledb.h>
#include <oledberr.h>
#include <sqlncli.h>
#include <stdio.h>

#define NUMROWS_CHUNK  5

// AdjustLen supports binding on four-byte boundaries.
_inline DBLENGTH AdjustLen(DBLENGTH cb) { 
   return ( (cb + 3) & ~3 );
}

// Get the characteristics of the rowset (the IColumnsInfo interface).
HRESULT GetColumnInfo ( IRowset* pIRowset, 
                        DBORDINAL* pnCols, 
                        DBCOLUMNINFO** ppColumnsInfo,
                        OLECHAR** ppColumnStrings ) {
   IColumnsInfo* pIColumnsInfo;
   HRESULT hr;

   *pnCols = 0;
   if (FAILED(pIRowset->QueryInterface(IID_IColumnsInfo, (void**) &pIColumnsInfo)))
      return (E_FAIL);

   hr = pIColumnsInfo->GetColumnInfo(pnCols, ppColumnsInfo, ppColumnStrings);

   if (FAILED(hr)) {}   /* Process error */ 

   pIColumnsInfo->Release();
   return (hr);
}

// Create binding structures from column information. Binding structures
// will be used to create an accessor that allows row value retrieval.
void CreateDBBindings ( DBORDINAL nCols, 
                        DBCOLUMNINFO* pColumnsInfo, 
                        DBBINDING** ppDBBindings,
                        BYTE** ppRowValues ) {
   ULONG nCol;
   DBLENGTH cbRow = 0;
   DBLENGTH cbCol;
   DBBINDING* pDBBindings;
   BYTE* pRowValues;

   pDBBindings = new DBBINDING[nCols];
   if (!(pDBBindings /* = new DBBINDING[nCols] */ ))
      return;

   for ( nCol = 0 ; nCol < nCols ; nCol++ ) {
      pDBBindings[nCol].iOrdinal = nCol + 1;
      pDBBindings[nCol].pTypeInfo = NULL;
      pDBBindings[nCol].pObject = NULL;
      pDBBindings[nCol].pBindExt = NULL;
      pDBBindings[nCol].dwPart = DBPART_VALUE;
      pDBBindings[nCol].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
      pDBBindings[nCol].eParamIO = DBPARAMIO_NOTPARAM;
      pDBBindings[nCol].dwFlags = 0;
      pDBBindings[nCol].wType = pColumnsInfo[nCol].wType;
      pDBBindings[nCol].bPrecision = pColumnsInfo[nCol].bPrecision;
      pDBBindings[nCol].bScale = pColumnsInfo[nCol].bScale;

      cbCol = pColumnsInfo[nCol].ulColumnSize;

      switch (pColumnsInfo[nCol].wType) {
      case DBTYPE_STR: {
            cbCol += 1;
            break;
         }

      case DBTYPE_WSTR: {
            cbCol = (cbCol + 1) * sizeof(WCHAR);
            break;
         }

      default:
         break;
      }

      pDBBindings[nCol].obValue = cbRow;
      pDBBindings[nCol].cbMaxLen = cbCol;
      cbRow += AdjustLen(cbCol);
   }

   pRowValues = new BYTE[cbRow];
   *ppDBBindings = pDBBindings;
   *ppRowValues = pRowValues;
}

int main() {
   ISourcesRowset* pISourceRowset = NULL;    
   IRowset* pIRowset = NULL;        
   IAccessor* pIAccessor = NULL;
   DBBINDING* pDBBindings = NULL;            

   HROW* pRows = new HROW[500];    
   HACCESSOR hAccessorRetrieve = NULL;        
   ULONG DSSeqNumber = 0;

   HRESULT hr;
   DBORDINAL nCols;
   DBCOLUMNINFO* pColumnsInfo = NULL;
   OLECHAR* pColumnStrings = NULL;
   DBBINDSTATUS* pDBBindStatus = NULL;

   BYTE* pRowValues = NULL;
   DBCOUNTITEM cRowsObtained;
   ULONG iRow;
   char* pMultiByte = NULL;
   short* psSourceType = NULL;
   BYTE* pDatasource = NULL;

   if (!pRows)
      return (0);

   // Initialize COM library.
   CoInitialize(NULL);

   // Initialize the enumerator.
   if (FAILED(CoCreateInstance(CLSID_SQLNCLI11_ENUMERATOR, 
                               NULL,
                               CLSCTX_INPROC_SERVER, 
                               IID_ISourcesRowset, 
                               (void**)&pISourceRowset))) {
      // Process error.
      return TRUE;
   }

   // Retrieve the source rowset.
   hr = pISourceRowset->GetSourcesRowset(NULL, IID_IRowset, 0, NULL, (IUnknown**)&pIRowset);

   pISourceRowset->Release();
   if (FAILED(hr)) {
      // Process error.
      return TRUE;
   }

   // Get the description of the enumerator's rowset.
   if (FAILED(hr = GetColumnInfo(pIRowset, &nCols, &pColumnsInfo, &pColumnStrings))) {
      // Process error.
      goto SAFE_EXIT;
   }

   // Create the binding structures.
   CreateDBBindings(nCols, pColumnsInfo, &pDBBindings, &pRowValues);
   pDBBindStatus = new DBBINDSTATUS[nCols];

   if (sizeof(TCHAR) != sizeof(WCHAR))
      pMultiByte = new char[pDBBindings[0].cbMaxLen];

   if (FAILED(pIRowset->QueryInterface(IID_IAccessor, (void**)&pIAccessor))) {
      // Process error.
      goto SAFE_EXIT;
   }

   // Create the rowset accessor.
   if (FAILED(hr = pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA, 
                                              nCols,
                                              pDBBindings, 
                                              0, 
                                              &hAccessorRetrieve, 
                                              pDBBindStatus))) {
      // Process error.
      goto SAFE_EXIT;
   }

   // Process all the rows, NUMROWS_CHUNK rows at a time.
   while (SUCCEEDED(hr)) {
      hr = pIRowset->GetNextRows(NULL, 0, NUMROWS_CHUNK, &cRowsObtained, &pRows);
      if( FAILED(hr)) {
         // process error
      }
      if (cRowsObtained == 0 || FAILED(hr))
         break;

      for (iRow = 0 ; iRow < cRowsObtained ; iRow++) {
         // Get the rowset data.
         if (SUCCEEDED(hr = pIRowset->GetData(pRows[iRow], hAccessorRetrieve, pRowValues))) {
            psSourceType = (short *)(pRowValues + pDBBindings[3].obValue);

            if (*psSourceType == DBSOURCETYPE_DATASOURCE) {
               DSSeqNumber = DSSeqNumber + 1;   // Data source counter.
               pDatasource = (pRowValues + pDBBindings[0].obValue);

               if ( sizeof(TCHAR) != sizeof(WCHAR) ) {
                  WideCharToMultiByte(CP_ACP, 
                                      0,
                                      (WCHAR*)pDatasource, 
                                      -1, 
                                      pMultiByte,
                                      static_cast<int>(pDBBindings[0].cbMaxLen), 
                                      NULL, 
                                      NULL);

                  printf( "DataSource# %d\tName: %S\n", 
                          DSSeqNumber, 
                          (WCHAR *) pMultiByte );
               }
               else {
                  printf( "DataSource# %d\tName: %S\n", 
                          DSSeqNumber, 
                          (WCHAR *) pDatasource );
               }
            }
         }
      }
      pIRowset->ReleaseRows(cRowsObtained, pRows, NULL, NULL, NULL);
   }

   // Release COM library.
   CoUninitialize();

SAFE_EXIT:
   // Do the clean-up.
   return TRUE;
}