Поделиться через


Программирование объектов ADO с использованием Visual C++

Справочник по API ADO описывает функциональные возможности api ADO с использованием синтаксиса, аналогичного Microsoft Visual Basic. Хотя целевая аудитория — все пользователи, программисты ADO используют различные языки, такие как Visual Basic, Visual C++ (с директивой #import и без нее) и Visual J++ (с пакетом класса ADO/WFC).

Примечание

Корпорация Майкрософт прекратила поддержку Visual J++ в 2004 году.

Чтобы удовлетворить это разнообразие, синтаксические индексы ADO для Visual C++ предоставляют синтаксис Visual C++ для конкретного языка со ссылками на общие описания функциональных возможностей, параметров, исключительных поведений и т. д. в справочнике по API.

ADO реализуется с помощью интерфейсов COM (компонентной объектной модели). Однако программистам проще работать с COM на определенных языках программирования, чем на других. Например, почти все сведения об использовании COM обрабатываются неявно для программистов Visual Basic, тогда как программисты Visual C++ должны сами заниматься этими деталями.

В следующих разделах приведены сведения для программистов на C и C++, использующих ADO и директиву #import . Он посвящен типам данных, характерным для COM (Variant, BSTR и SafeArray), и обработке ошибок (_com_error).

Использование директивы компилятора #import

Директива компилятора #import Visual C++ упрощает работу с методами и свойствами ADO. Директива принимает имя файла, содержащего библиотеку типов, например .dll ADO (Msado15.dll), и создает файлы заголовков, содержащие объявления typedef, интеллектуальные указатели для интерфейсов и перечисляемые константы. Каждый интерфейс инкапсулируется или упаковывается в класс.

Для каждой операции в классе (то есть вызова метода или свойства) имеется объявление для вызова операции напрямую (т. е. "необработанной" формы операции) и объявление для вызова необработанной операции и вызова COM-ошибки, если операция не выполняется успешно. Если операция является свойством, обычно имеется директива компилятора, которая создает альтернативный синтаксис для операции с таким синтаксисом, как Visual Basic.

Операции, извлекающие значение свойства, имеют имена в форме GetProperty. Операции, которые задают значение свойства, имеют имена в форме PutProperty. Операции, устанавливающие значение свойства с указателем на объект ADO, имеют имена формы PutRefProperty.

Вы можете получить или задать свойство с помощью вызовов следующих форм:

variable = objectPtr->GetProperty(); // get property value   
objectPtr->PutProperty(value);       // set property value  
objectPtr->PutRefProperty(&value);   // set property with object pointer  

Использование директив свойств

Директива компилятора __declspec(property...) — это расширение языка C, относящееся к корпорации Майкрософт, которое объявляет функцию, используемую в качестве свойства с альтернативным синтаксисом. В результате можно задать или получить значения свойства так же, как в Visual Basic. Например, можно задать и получить свойство следующим образом:

objectPtr->property = value;        // set property value  
variable = objectPtr->property;     // get property value  

Обратите внимание, что код не требуется:

objectPtr->PutProperty(value);      // set property value  
variable = objectPtr->GetProperty;  // get property value  

Компилятор создаст соответствующий вызов свойства Get-, Put-илиPutRef в зависимости от того, какой альтернативный синтаксис объявлен, а также от того, считывается или записывается свойство.

Директива компилятора __declspec(property...) может объявлять только альтернативный синтаксис функции get, put или get и put . Операции только для чтения имеют только объявление get ; Операции только для записи имеют только объявление put ; Операции чтения и записи имеют объявления get и put .

С помощью этой директивы возможны только два объявления; Однако каждое свойство может иметь три функции свойств: GetProperty, PutProperty и PutRefProperty. В этом случае только две формы свойства имеют альтернативный синтаксис.

Например, свойство Объекта CommandActiveConnection объявляется с альтернативным синтаксисом для GetActiveConnection и PutRefActiveConnection. Синтаксис PutRef- является хорошим выбором, так как на практике обычно требуется поместить открытый объект Connection (т. е. указатель на объект Connection ) в этом свойстве. С другой стороны, объект Recordset имеет операции Get-, Put-иPutRefActiveConnection , но не имеет альтернативного синтаксиса.

Коллекции, метод GetItem и свойство Item

ADO определяет несколько коллекций, включая Поля, Параметры, Свойства и Ошибки. В Visual C++ метод GetItem(index) возвращает элемент коллекции. Index — это значение Типа Variant, значение которого является либо числовым индексом элемента в коллекции, либо строкой, содержащей имя элемента.

Директива компилятора __declspec(property...) объявляет свойство Item в качестве альтернативного синтаксиса для основного метода GetItem() каждой коллекции. Альтернативный синтаксис использует квадратные скобки и выглядит примерно так, как ссылка на массив. Как правило, эти две формы выглядят следующим образом:

  
      collectionPtr->GetItem(index);  
collectionPtr->Item[index];  

Например, присвойте значение полю объекта Recordset с именем rs, производное от таблицы авторов базы данных pubs . Используйте свойство Item() для доступа к третьему полю коллекции Fields объекта Recordset (коллекции индексируются с нуля; предположим, что третье поле называется au_fname). Затем вызовите метод Value() объекта Field , чтобы присвоить строковое значение.

Это можно выразить в Visual Basic следующими четырьмя способами (последние две формы уникальны для Visual Basic; другие языки не имеют эквивалентов):

rs.Fields.Item(2).Value = "value"  
rs.Fields.Item("au_fname").Value = "value"  
rs(2) = "value"  
rs!au_fname = "value"  

В Visual C++ первые две формы выше эквивалентны:

rs->Fields->GetItem(long(2))->PutValue("value");   
rs->Fields->GetItem("au_fname")->PutValue("value");  

-или- (также показан альтернативный синтаксис для свойства Value )

rs->Fields->Item[long(2)]->Value = "value";  
rs->Fields->Item["au_fname"]->Value = "value";  

Примеры перебора коллекции см. в разделе "Коллекции ADO" статьи "Справочник по ADO".

Типы данных COM-Specific

Как правило, любой тип данных Visual Basic, который вы найдете в справочнике по API ADO, имеет эквивалент Visual C++. К ним относятся стандартные типы данных, такие как unsigned char для байта Visual Basic, сокращение от integer и long для long. Просмотрите синтаксические индексы, чтобы точно увидеть, что требуется для операндов заданного метода или свойства.

Исключением из этого правила являются типы данных, относящиеся к COM: Variant, BSTR и SafeArray.

Variant

Variant — это структурированный тип данных, содержащий элемент значения и элемент типа данных. Variant может содержать широкий спектр других типов данных, включая другой тип данных Variant, BSTR, Boolean, IDispatch или IUnknown, валюту, дату и т. д. COM также предоставляет методы, упрощающие преобразование одного типа данных в другой.

Класс _variant_t инкапсулирует тип данных Variant и управляет им.

Если в справочнике по API ADO указано, что операнд метода или свойства принимает значение, это обычно означает, что значение передается в _variant_t.

Это правило явно верно, если в разделе Параметры в разделах справочника по API ADO указано, что операнд является вариантом. Исключением является то, что в документации явно указано, что операнд принимает стандартный тип данных, например Long или Byte, или перечисление. Еще одним исключением является то, что операнд принимает значение String.

BSTR

BSTR (Basic STRing) — это структурированный тип данных, содержащий строку символов и длину строки. COM предоставляет методы для выделения, управления и освобождения BSTR.

Класс _bstr_t инкапсулирует тип данных BSTR и управляет им.

Если в справочнике по API ADO указано, что метод или свойство принимает значение String , это означает, что значение имеет форму _bstr_t.

Приведение классов _variant_t и _bstr_t

Часто нет необходимости явно кодировать _variant_t или _bstr_t в аргументе операции. Если класс _variant_t или _bstr_t имеет конструктор, соответствующий типу данных аргумента, компилятор создаст соответствующую _variant_t или _bstr_t.

Однако если аргумент является неоднозначным, то есть тип данных аргумента соответствует нескольким конструкторам, необходимо привести аргумент с соответствующим типом данных, чтобы вызвать правильный конструктор.

Например, объявление для метода Recordset::Open :

    HRESULT Open (  
        const _variant_t & Source,  
        const _variant_t & ActiveConnection,  
        enum CursorTypeEnum CursorType,  
        enum LockTypeEnum LockType,  
        long Options );  

Аргумент ActiveConnection принимает ссылку на _variant_t, которую можно кодировать как строку подключения или указатель на открытый объект Connection .

Правильный _variant_t будет создан неявно, если передать строку, например "DSN=pubs;uid=MyUserName;pwd=MyPassword;", или указатель, например "(IDispatch *) pConn".

Примечание

При подключении к поставщику источника данных, который поддерживает проверка подлинности Windows, в строке подключения следует указать Trusted_Connection=yes или Integrated Security = SSPI вместо идентификатора пользователя и пароля.

Кроме того, можно явно закодить _variant_t , содержащий указатель, например "_variant_t((IDispatch *) pConn, true)". Приведение разрешает неоднозначность с помощью другого конструктора, (IDispatch *)который принимает указатель на интерфейс IUnknown.

Это важный, хотя и редко упоминаемый факт, что ADO является интерфейсом IDispatch. Всякий раз, когда указатель на объект ADO должен передаваться как Variant, этот указатель должен быть приведен как указатель на интерфейс IDispatch.

Последний вариант явно кодирует второй логический аргумент конструктора с его необязательным значением trueпо умолчанию . Этот аргумент вызывает конструктор Variant метод AddRef(), который компенсирует автоматический вызов метода _variant_t::Release() ADO после завершения вызова метода ADO или свойства.

SafeArray

SafeArray — это структурированный тип данных, содержащий массив других типов данных. SafeArray называется безопасным, так как он содержит сведения о границах каждого измерения массива и ограничивает доступ к элементам массива в этих границах.

Если в справочнике по API ADO указано, что метод или свойство принимает или возвращает массив, это означает, что метод или свойство принимает или возвращает SafeArray, а не собственный массив C/C++.

Например, для второго параметра метода OpenSchema объекта Connection требуется массив значений Variant. Эти значения Variant должны передаваться как элементы объекта SafeArray, а этот параметр SafeArray должен быть задан как значение другого Типа Variant. Это другой вариант Variant , который передается в качестве второго аргумента OpenSchema.

В качестве дополнительных примеров первым аргументом метода Find является Variant , значением которого является одномерный SafeArray; каждый из необязательных первого и второго аргументов AddNew является одномерным SafeArray; а возвращаемое значение метода GetRows — это variant , значение которого является двумерным SafeArray.

Отсутствующие параметры и параметры по умолчанию

Visual Basic допускает отсутствие параметров в методах. Например, метод Open объекта Recordset имеет пять параметров, но можно пропустить промежуточные параметры и оставить конечные параметры. Значение по умолчанию BSTR или Variant будет заменено в зависимости от типа данных отсутствующих операндов.

В C/C++ должны быть указаны все операнды. Если вы хотите указать отсутствующий параметр, тип данных которого является строкой, укажите _bstr_t , содержащую строку NULL. Если вы хотите указать отсутствующий параметр с типом данных Variant, укажите _variant_t со значением DISP_E_PARAMNOTFOUND и типом VT_ERROR. Кроме того, можно указать эквивалентную константу _variant_tvtMissing, которая предоставляется директивой #import .

Три метода являются исключениями из типичного использования vtMissing. Это методы Execute объектов Connection и Command , а также метод NextRecordset объекта Recordset . Ниже приведены их сигнатуры.

_RecordsetPtr <A HREF="mdmthcnnexecute.htm">Execute</A>( _bstr_t CommandText, VARIANT * RecordsAffected,   
        long Options );  // Connection  
_RecordsetPtr <A HREF="mdmthcmdexecute.htm">Execute</A>( VARIANT * RecordsAffected, VARIANT * Parameters,   
        long Options );  // Command  
_RecordsetPtr <A HREF="mdmthnextrec.htm">NextRecordset</A>( VARIANT * RecordsAffected );  // Recordset  

Параметры RecordsAffected и Parameters являются указателями на Variant. Параметры — это входной параметр, который задает адрес типа Variant , содержащего один параметр или массив параметров, который изменит выполняемую команду. RecordsAffected — это выходной параметр, указывающий адрес объекта Variant, в котором возвращается количество строк, затронутых методом .

В методе Command object Execute укажите, что никакие параметры не заданы, задав для параметра Parameters&vtMissing значение (рекомендуется) или указатель NULL (т. е. NULL или нуль (0)). Если параметру Parameters задан пустой указатель, метод внутренне заменяет эквивалент vtMissing, а затем завершает операцию.

Во всех методах укажите, что количество затронутых записей не должно быть возвращено, задав RecordsAffected нулевой указатель. В этом случае пустой указатель является не столько отсутствующим параметром, сколько признаком того, что метод должен отменить количество затронутых записей.

Таким образом, для этих трех методов допустимо кодировать следующее:

pConnection->Execute("commandText", NULL, adCmdText);   
pCommand->Execute(NULL, NULL, adCmdText);  
pRecordset->NextRecordset(NULL);  

Обработка ошибок

В COM большинство операций возвращают код возврата HRESULT, который указывает, успешно ли выполнена функция. Директива #import создает код-оболочку для каждого "необработанного" метода или свойства и проверяет возвращенный HRESULT. Если HRESULT указывает на сбой, код-оболочка выдает com-ошибку, вызывая _com_issue_errorex() с кодом возврата HRESULT в качестве аргумента. Объекты ошибок COM можно перехватывать в блоке try-catch . (Для повышения эффективности перехватите ссылку на объект _com_error .)

Помните, что это ошибки ADO: они возникают в результате сбоя операции ADO. Ошибки, возвращаемые базовым поставщиком, отображаются как объекты Error в коллекции Errors объекта Connection.

Директива #import создает только подпрограммы обработки ошибок для методов и свойств, объявленных в .dll ADO. Однако вы можете воспользоваться тем же механизмом обработки ошибок, написав собственный макрос проверки ошибок или встроенную функцию. Примеры см. в разделе Расширения Visual C++ или коде в следующих разделах.

Эквиваленты соглашений Visual Basic в Visual C++

Ниже приведена сводка по нескольким соглашениям в документации по ADO, закодированных в Visual Basic, а также их эквивалентов в Visual C++.

Объявление объекта ADO

В Visual Basic переменная объекта ADO (в данном случае для объекта Recordset ) объявляется следующим образом:

Dim rst As ADODB.Recordset  

Предложение "ADODB.Recordset" — это идентификатор ProgID объекта Recordset , как определено в реестре. Новый экземпляр объекта Record объявляется следующим образом:

Dim rst As New ADODB.Recordset  

-или-

Dim rst As ADODB.Recordset  
Set rst = New ADODB.Recordset  

В Visual C++ директива #import создает объявления типа интеллектуального указателя для всех объектов ADO. Например, переменная, указывающая на объект _Recordset , имеет тип _RecordsetPtr и объявляется следующим образом:

_RecordsetPtr  rs;  

Переменная, указывающая на новый экземпляр объекта _Recordset , объявляется следующим образом:

_RecordsetPtr  rs("ADODB.Recordset");  

-или-

_RecordsetPtr  rs;  
rs.CreateInstance("ADODB.Recordset");  

-или-

_RecordsetPtr  rs;  
rs.CreateInstance(__uuidof(_Recordset));  

После вызова метода CreateInstance переменную можно использовать следующим образом:

rs->Open(...);  

Обратите внимание, что в одном случае оператор "." используется так, как если бы переменная была экземпляром класса (rs.CreateInstance), а в другом случае оператор "->" используется так, как если бы переменная была указателем на интерфейс (rs->Open).

Одну переменную можно использовать двумя способами, так как оператор "->" перегружен, чтобы позволить экземпляру класса вести себя как указатель на интерфейс. Частный член класса переменной экземпляра содержит указатель на интерфейс _Recordset ; Оператор "->" возвращает этот указатель, а возвращенный указатель обращается к членам объекта _Recordset .

Кодирование отсутствующих параметров — строка

Если вам нужно закодировать отсутствующий строковый операнд в Visual Basic, необходимо просто опустить операнд. Операнд необходимо указать в Visual C++. Код _bstr_t с пустой строкой в качестве значения.

_bstr_t strMissing(L"");  

Кодирование отсутствующих параметров — Variant

Если вам нужно закодировать отсутствующий операнд Variant в Visual Basic, необходимо просто опустить операнд. Необходимо указать все операнды в Visual C++. Закодировать отсутствующий параметр Variant с _variant_t специальным значением, DISP_E_PARAMNOTFOUND и типом VT_ERROR. Кроме того, можно указать vtMissing, которая является эквивалентной предопределенной константой, предоставляемой директивой #import .

_variant_t  vtMissingYours(DISP_E_PARAMNOTFOUND, VT_ERROR);   

-или используйте -

...vtMissing...;  

Объявление типа Variant

В Visual Basic тип Variant объявляется с помощью инструкции Dim следующим образом:

Dim VariableName As Variant  

В Visual C++ объявите переменную как тип _variant_t. Ниже приведено несколько схематических объявлений _variant_t .

Примечание

Эти объявления просто дают примерное представление о том, что вы будете кодировать в собственной программе. Дополнительные сведения см. в примерах ниже и в документации по Visual C++.

_variant_t  VariableName(value);  
_variant_t  VariableName((data type cast) value);  
_variant_t  VariableName(value, VT_DATATYPE);  
_variant_t  VariableName(interface * value, bool fAddRef = true);  

Использование массивов вариантов

В Visual Basic массивы Variants можно закодировать с помощью инструкции Dim или использовать функцию Array , как показано в следующем примере кода:

Public Sub ArrayOfVariants  
Dim cn As ADODB.Connection  
Dim rs As ADODB.Recordset  
Dim fld As ADODB.Field  
  
    cn.Open "DSN=pubs"  
    rs = cn.OpenSchema(adSchemaColumns, _  
        Array(Empty, Empty, "authors", Empty))  
    For Each fld in rs.Fields  
        Debug.Print "Name = "; fld.Name  
    Next fld  
    rs.Close  
    cn.Close  
End Sub  

В следующем примере Visual C++ демонстрируется использование SafeArray , используемого с _variant_t.

Примечания

Следующие примечания соответствуют закомментированных разделам в примере кода.

  1. Еще раз, встроенная функция TESTHR() определена для использования существующих механизмов обработки ошибок.

  2. Требуется только одномерный массив, поэтому вы можете использовать SafeArrayCreateVector вместо объявления общего назначения SAFEARRAYBOUND и функции SafeArrayCreate . Ниже показано, как будет выглядеть этот код при использовании SafeArrayCreate:

       SAFEARRAYBOUND   sabound[1];  
       sabound[0].lLbound = 0;  
       sabound[0].cElements = 4;  
       pSa = SafeArrayCreate(VT_VARIANT, 1, sabound);  
    
  3. Схема, определяемая перечисляемой константой adSchemaColumns, связана с четырьмя столбцами ограничений: TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME и COLUMN_NAME. Поэтому создается массив значений Variant с четырьмя элементами. Затем указывается значение ограничения, соответствующее третьему столбцу, TABLE_NAME.

    Возвращаемый набор записей состоит из нескольких столбцов, подмножеством которых являются столбцы ограничений. Значения столбцов ограничений для каждой возвращаемой строки должны совпадать со значениями соответствующих ограничений.

  4. Те, кто знаком с SafeArrays , могут быть удивлены тем, что SafeArrayDeкистя() не вызывается до выхода. В этом случае вызов SafeArrayDeкистрой() вызовет исключение во время выполнения. Причина в том, что деструктор для vtCriteria вызывает VariantClear(), когда _variant_t выходит из область, что освободит SafeArray. При вызове SafeArrayDeconfig, не очищая _variant_t вручную, деструктор попытается очистить недопустимый указатель SafeArray .

    Если бы был вызван метод SafeArrayDe, код будет выглядеть следующим образом:

          TESTHR(SafeArrayDestroy(pSa));  
       vtCriteria.vt = VT_EMPTY;  
          vtCriteria.parray = NULL;  
    

    Однако гораздо проще позволить _variant_t управлять SafeArray.

// Visual_CPP_ADO_Prog_1.cpp  
// compile with: /EHsc  
#import "msado15.dll" no_namespace rename("EOF", "EndOfFile")  
  
// Note 1  
inline void TESTHR( HRESULT _hr ) {   
   if FAILED(_hr)   
      _com_issue_error(_hr);   
}  
  
int main() {  
   CoInitialize(NULL);  
   try {  
      _RecordsetPtr pRs("ADODB.Recordset");  
      _ConnectionPtr pCn("ADODB.Connection");  
      _variant_t vtTableName("authors"), vtCriteria;  
      long ix[1];  
      SAFEARRAY *pSa = NULL;  
  
      pCn->Provider = "sqloledb";  
      pCn->Open("Data Source='(local)';Initial Catalog='pubs';Integrated Security=SSPI", "", "", adConnectUnspecified);  
      // Note 2, Note 3  
      pSa = SafeArrayCreateVector(VT_VARIANT, 1, 4);  
      if (!pSa)   
         _com_issue_error(E_OUTOFMEMORY);  
  
      // Specify TABLE_NAME in the third array element (index of 2).   
      ix[0] = 2;        
      TESTHR(SafeArrayPutElement(pSa, ix, &vtTableName));  
  
      // There is no Variant constructor for a SafeArray, so manually set the   
      // type (SafeArray of Variant) and value (pointer to a SafeArray).  
  
      vtCriteria.vt = VT_ARRAY | VT_VARIANT;  
      vtCriteria.parray = pSa;  
  
      pRs = pCn->OpenSchema(adSchemaColumns, vtCriteria, vtMissing);  
  
      long limit = pRs->GetFields()->Count;  
      for ( long x = 0 ; x < limit ; x++ )  
         printf( "%d: %s\n", x + 1, ((char*) pRs->GetFields()->Item[x]->Name) );  
      // Note 4  
      pRs->Close();  
      pCn->Close();  
   }  
   catch (_com_error &e) {  
      printf("Error:\n");  
      printf("Code = %08lx\n", e.Error());  
      printf("Code meaning = %s\n", (char*) e.ErrorMessage());  
      printf("Source = %s\n", (char*) e.Source());  
      printf("Description = %s\n", (char*) e.Description());  
   }  
   CoUninitialize();  
}  

Использование свойства Get/Put/PutRef

В Visual Basic имя свойства не определяется в зависимости от того, извлекается ли оно, назначается или назначается ссылка.

Public Sub GetPutPutRef  
Dim rs As New ADODB.Recordset  
Dim cn As New ADODB.Connection  
Dim sz as Integer  
cn.Open "Provider=sqloledb;Data Source=yourserver;" & _  
         "Initial Catalog=pubs;Integrated Security=SSPI;"  
rs.PageSize = 10  
sz = rs.PageSize  
rs.ActiveConnection = cn  
rs.Open "authors",,adOpenStatic  
' ...  
rs.Close  
cn.Close  
End Sub  

В этом примере visual C++ демонстрируется свойство Get/PutRef/.

Примечания

Следующие примечания соответствуют закомментированных разделам в примере кода.

  1. В этом примере используются две формы отсутствующего аргумента строки: явная константа, strMissing и строка, которую компилятор будет использовать для создания временного _bstr_t, который будет существовать для область метода Open.

  2. Приведение операнда rs->PutRefActiveConnection(cn) к (IDispatch *) необязательно, так как тип операнда уже (IDispatch *)имеет тип .

// Visual_CPP_ado_prog_2.cpp  
// compile with: /EHsc  
#import "msado15.dll" no_namespace rename("EOF", "EndOfFile")  
  
int main() {  
   CoInitialize(NULL);  
   try {  
      _ConnectionPtr cn("ADODB.Connection");  
      _RecordsetPtr rs("ADODB.Recordset");  
      _bstr_t strMissing(L"");  
      long oldPgSz = 0, newPgSz = 5;  
  
      // Note 1  
      cn->Provider = "sqloledb";  
      cn->Open("Data Source='(local)';Initial Catalog=pubs;Integrated Security=SSPI;", strMissing, "", adConnectUnspecified);  
  
      oldPgSz = rs->GetPageSize();  
      // -or-  
      // oldPgSz = rs->PageSize;  
  
      rs->PutPageSize(newPgSz);  
      // -or-  
      // rs->PageSize = newPgSz;  
  
      // Note 2  
      rs->PutRefActiveConnection( cn );  
      rs->Open("authors", vtMissing, adOpenStatic, adLockReadOnly, adCmdTable);  
      printf("Original pagesize = %d, new pagesize = %d\n", oldPgSz, rs->GetPageSize());  
      rs->Close();  
      cn->Close();  
  
   }  
   catch (_com_error &e) {  
      printf("Description = %s\n", (char*) e.Description());  
   }  
   ::CoUninitialize();  
}  

Использование GetItem(x) и Item[x]

В этом примере Visual Basic демонстрируется стандартный и альтернативный синтаксис для Item().

Public Sub GetItemItem  
Dim rs As New ADODB.Recordset  
Dim name as String  
rs = rs.Open "authors", "DSN=pubs;", adOpenDynamic, _  
         adLockBatchOptimistic, adTable  
name = rs(0)  
' -or-  
name = rs.Fields.Item(0)  
rs(0) = "Test"  
rs.UpdateBatch  
' Restore name  
rs(0) = name  
rs.UpdateBatch  
rs.Close  
End Sub  

В этом примере visual C++ демонстрируется элемент.

Примечание

Следующее примечание соответствует закомментированных разделам в примере кода: при обращении к коллекции с помощью Item индекс 2 должен быть приведен к long , чтобы вызвать соответствующий конструктор.

// Visual_CPP_ado_prog_3.cpp  
// compile with: /EHsc  
#import "msado15.dll" no_namespace rename("EOF", "EndOfFile")  
  
void main() {  
   CoInitialize(NULL);  
   try {  
      _ConnectionPtr cn("ADODB.Connection");  
      _RecordsetPtr rs("ADODB.Recordset");  
      _variant_t vtFirstName;  
  
      cn->Provider = "sqloledb";  
      cn->Open("Data Source='(local)';Initial Catalog=pubs;Integrated Security=SSPI;", "", "", adConnectUnspecified);  
  
      rs->PutRefActiveConnection( cn );  
      rs->Open("authors", vtMissing, adOpenStatic, adLockOptimistic, adCmdTable);  
      rs->MoveFirst();  
  
      // Note 1. Get a field.  
      vtFirstName = rs->Fields->GetItem((long)2)->GetValue();  
      // -or-  
      vtFirstName = rs->Fields->Item[(long)2]->Value;  
  
      printf( "First name = '%s'\n", (char*)( (_bstr_t)vtFirstName) );  
  
      rs->Fields->GetItem((long)2)->Value = L"TEST";  
      rs->Update(vtMissing, vtMissing);  
  
      // Restore name  
      rs->Fields->GetItem((long)2)->PutValue(vtFirstName);  
      // -or-  
      rs->Fields->GetItem((long)2)->Value = vtFirstName;  
      rs->Update(vtMissing, vtMissing);  
      rs->Close();  
   }  
   catch (_com_error &e) {  
      printf("Description = '%s'\n", (char*) e.Description());  
   }  
   ::CoUninitialize();  
}  

Приведение указателей объектов ADO с помощью (IDispatch *)

В следующем примере Visual C++ демонстрируется использование (IDispatch *) для приведения указателей объектов ADO.

Примечания

Следующие примечания соответствуют закомментированных разделам в примере кода.

  1. Укажите открытый объект Connection в явно закодированном варианте. Приведите его с помощью (IDispatch *), чтобы вызвать правильный конструктор. Кроме того, явно присвойте второму параметру _variant_t значение по умолчанию true, чтобы количество ссылок на объекты было правильным при завершении операции Recordset::Open .

  2. Выражение (_bstr_t), не является приведением, а оператором _variant_t , который извлекает строку _bstr_t из variant , возвращаемого значением Value.

Выражение , (char*)не является приведением, а оператором _bstr_t , который извлекает указатель на инкапсулированную строку в объекте _bstr_t .

В этом разделе кода демонстрируются некоторые полезные функции операторов _variant_t и _bstr_t .

// Visual_CPP_ado_prog_4.cpp  
// compile with: /EHsc  
#import "msado15.dll" no_namespace rename("EOF", "EndOfFile")  
  
int main() {  
   CoInitialize(NULL);  
   try {  
      _ConnectionPtr pConn("ADODB.Connection");  
      _RecordsetPtr pRst("ADODB.Recordset");  
  
      pConn->Provider = "sqloledb";  
      pConn->Open("Data Source='(local)';Initial Catalog='pubs';Integrated Security=SSPI", "", "", adConnectUnspecified);  
  
      // Note 1.  
      pRst->Open("authors", _variant_t((IDispatch *) pConn, true), adOpenStatic, adLockReadOnly, adCmdTable);  
      pRst->MoveLast();  
  
      // Note 2.  
      printf("Last name is '%s %s'\n",   
         (char*) ((_bstr_t) pRst->GetFields()->GetItem("au_fname")->GetValue()),  
         (char*) ((_bstr_t) pRst->Fields->Item["au_lname"]->Value));  
  
      pRst->Close();  
      pConn->Close();  
   }  
   catch (_com_error &e) {  
      printf("Description = '%s'\n", (char*) e.Description());  
   }     
   ::CoUninitialize();  
}