枚举 OLE DB 数据源 (OLE DB)

此示例显示如何使用枚举器对象列出可用数据源。

若要列出对 SQLOLEDB 枚举器可见的数据源,使用者应调用 ISourcesRowset::GetSourcesRowset 方法。 此方法返回与当前可见数据源有关的信息的行集。

根据所使用的网络库,将搜索相应的域以找到数据源。 对于命名管道,将搜索客户端登录到的域。 对于 AppleTalk,将搜索默认区域。 对于 SPX/IPX,将搜索在平构数据库中找到的 SQL Server 安装的列表。 对于 Banyan VINES,将搜索在本地网络中找到的 SQL Server 安装。 不支持多协议和 TCP/IP 套接字。

在开关服务器时,可能需要几分钟来更新这些域中的信息。

此示例要求使用 AdventureWorks 示例数据库,可以从 Microsoft SQL Server Samples and Community Projects(Microsoft SQL Server 示例和社区项目)主页下载该数据库。

安全说明安全说明

请尽可能使用 Windows 身份验证。 如果 Windows 身份验证不可用,请在运行时提示用户输入其凭据。 不要将凭据存储在一个文件中。 如果必须保存凭据,应当用 Win32 crypto API(Win32 加密 API)加密它们。

枚举 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)\\name",其中 name 是命名实例。 默认情况下,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;
}