Programmazione ADO in Visual C++
Il riferimento all'API ADO descrive la funzionalità dell'API (Application Programming Interface) ADO usando una sintassi simile a Microsoft Visual Basic. Anche se il pubblico previsto è tutti gli utenti, i programmatori ADO usano linguaggi diversi, ad esempio Visual Basic, Visual C++ (con e senza la direttiva #import) e Visual J++ (con il pacchetto di classe ADO/WFC).
Nota
Microsoft ha terminato il supporto per Visual J++ nel 2004.
Per soddisfare questa diversità, gli indici di sintassi ADO per Visual C++ forniscono la sintassi specifica del linguaggio Visual C++ con collegamenti a descrizioni comuni di funzionalità, parametri, comportamenti eccezionali e così via, nelle Informazioni di riferimento sulle API.
ADO viene implementato con interfacce COM (Component Object Model). Tuttavia, per i programmatori è più facile lavorare con COM in determinati linguaggi di programmazione rispetto ad altri. Ad esempio, quasi tutti i dettagli dell'utilizzo di COM vengono gestiti in modo implicito per i programmatori di Visual Basic, mentre i programmatori di Visual C++ devono gestire direttamente tali dettagli.
Le sezioni seguenti riepilogano i dettagli per i programmatori di C e C++ che usano ADO e la direttiva #import. Sono incentrate sui tipi di dati specifici di COM (Variant, BSTR e SafeArray) e sulla gestione degli errori (_com_error).
Utilizzo della direttiva del compilatore #import
La direttiva del compilatore Visual C++ #import semplifica l'utilizzo dei metodi e delle proprietà ADO. La direttiva accetta il nome di un file contenente una libreria di tipi, ad esempio la .dll ADO (Msado15.dll) e genera file di intestazione contenenti dichiarazioni typedef, puntatori intelligenti per interfacce e costanti enumerate. Ogni interfaccia è incapsulata, o sottoposta a wrapping, in una classe.
Per ogni operazione all'interno di una classe, ovvero una chiamata di metodo o proprietà, è presente una dichiarazione per chiamare direttamente l'operazione, ovvero la forma "raw" dell'operazione, e una dichiarazione per chiamare l'operazione non elaborata e generare un errore COM se l'operazione non viene eseguita correttamente. Se l'operazione è una proprietà, in genere esiste una direttiva del compilatore che crea una sintassi alternativa per l'operazione con sintassi come Visual Basic.
Operazioni che recuperano il valore di una proprietà hanno nomi del modulo, GetProperty. Operazioni che recuperano il valore di una proprietà hanno nomi del modulo, PutProperty. Operazioni che impostano il valore di una proprietà con un puntatore a un oggetto ADO hanno nomi del modulo, PutRefProperty.
È possibile ottenere o impostare una proprietà con chiamate di questi moduli:
variable = objectPtr->GetProperty(); // get property value
objectPtr->PutProperty(value); // set property value
objectPtr->PutRefProperty(&value); // set property with object pointer
Utilizzo delle direttive delle proprietà
La direttiva del compilatore __declspec(property...) è un'estensione del linguaggio C specifica di Microsoft che dichiara una funzione usata come proprietà per avere una sintassi alternativa. Di conseguenza, è possibile impostare o ottenere valori di una proprietà in modo simile a Visual Basic. Ad esempio, è possibile impostare e ottenere una proprietà in questo modo:
objectPtr->property = value; // set property value
variable = objectPtr->property; // get property value
Si noti che non è necessario scrivere codice:
objectPtr->PutProperty(value); // set property value
variable = objectPtr->GetProperty; // get property value
Il compilatore genererà la chiamata Get-, Put- o PutRefProperty appropriata in base alla sintassi alternativa dichiarata e se la proprietà è in corso di lettura o scrittura.
La direttiva del compilatore __declspec(property...) può dichiarare solo la sintassi alternativa get, put o get e put per una funzione. Le operazioni di sola lettura hanno solo una dichiarazione get; le operazioni di sola scrittura hanno solo una dichiarazione put; le operazioni sia di lettura che di scrittura hanno dichiarazioni get e put.
Con questa direttiva sono possibili solo due dichiarazioni; tuttavia, ogni proprietà può avere tre funzioni di proprietà: GetProperty, PutProperty e PutRefProperty. In questo caso, solo due forme della proprietà hanno la sintassi alternativa.
Ad esempio, la proprietà ActiveConnection dell'oggetto Command viene dichiarata con una sintassi alternativa per GetActiveConnection e PutRefActiveConnection. La sintassi PutRef- è una scelta ottimale perché in pratica, in genere è necessario inserire un oggetto Connection aperto (ovvero un puntatore dell'oggetto Connection) in questa proprietà. D'altra parte, l'oggetto Recordset include operazioni Get-, Put- e PutRefActiveConnection, ma nessuna sintassi alternativa.
Raccolte, metodo GetItem e proprietà Item
ADO definisce diverse raccolte, tra cui Campi, Parametri, Proprietà ed Errori. In Visual C++, il metodo GetItem(index) restituisce un membro della raccolta. Index è una Variant, il cui valore è un indice numerico del membro della raccolta o una stringa contenente il nome del membro.
La direttiva del compilatore __declspec(property...) dichiara la proprietà Item come sintassi alternativa al metodo GetItem() fondamentale di ogni raccolta. La sintassi alternativa usa parentesi quadre e appare simile a un riferimento alla matrice. In generale, i due moduli sono simili al seguente:
collectionPtr->GetItem(index);
collectionPtr->Item[index];
Ad esempio, assegnare un valore a un campo di un oggetto Recordset denominato rs, derivato dalla tabella authors del database pubs. Utilizzare la proprietà Item() per accedere al terzo Campo della raccolta Campi dell'oggetto Recordset (le raccolte vengono indicizzate da zero; si supponga che il terzo campo sia denominato au_fname). Chiamare quindi il metodo Value() nell'oggetto Field per assegnare un valore stringa.
Ciò può essere espresso in Visual Basic nei quattro modi seguenti (gli ultimi due moduli sono univoci per Visual Basic; altri linguaggi non hanno equivalenti):
rs.Fields.Item(2).Value = "value"
rs.Fields.Item("au_fname").Value = "value"
rs(2) = "value"
rs!au_fname = "value"
L'equivalente in Visual C++ dei primi due moduli precedenti è:
rs->Fields->GetItem(long(2))->PutValue("value");
rs->Fields->GetItem("au_fname")->PutValue("value");
-or- (viene visualizzata anche la sintassi alternativa per la proprietà Value)
rs->Fields->Item[long(2)]->Value = "value";
rs->Fields->Item["au_fname"]->Value = "value";
Per esempi di iterazione tramite una raccolta, vedere la sezione "Raccolte ADO" di "Informazioni di riferimento sull'API ADO".
Tipi di dati specifici di COM.
In generale, qualsiasi tipo di dati di Visual Basic trovato nelle Informazioni di riferimento sull'API ADO ha un equivalente di Visual C++. Questi includono tipi di dati standard, ad esempio unsigned char per un Byte di Visual Basic, short per Integer e long per Long. Cercare negli Indici di sintassi per vedere esattamente ciò che è necessario per gli operandi di un determinato metodo o proprietà.
Le eccezioni a questa regola sono i tipi di dati specifici per COM: Variant, BSTR e SafeArray.
Variante
Un valore Variant è un tipo di dati strutturato che contiene un membro valore e un membro del tipo di dati. Un valore Variant può contenere un'ampia gamma di altri tipi di dati, tra cui un altro valore Variant, BSTR, Boolean, IDispatch o IUnknown pointer, valuta, data e così via. COM fornisce anche metodi che semplificano la conversione di un tipo di dati in un altro.
La classe _variant_t incapsula e gestisce il tipo di dati Variant.
Quando il Riferimento dell'API ADO indica che un operando di metodo o proprietà accetta un valore, in genere significa che il valore viene passato in un _variant_t.
Questa regola è vera in modo esplicito quando la sezione Parameters negli argomenti del Riferimento dell'API ADO indica che un operando è un valore Variant. Un'eccezione è quando la documentazione indica in modo esplicito che l'operando accetta un tipo di dati standard, ad esempio Long o Byte, o un'enumerazione. Un'altra eccezione è quando l'operando accetta un valore String.
BSTR
Una BSTR (Basic STRing) è un tipo di dati strutturato che contiene una stringa di caratteri e la lunghezza della stringa. COM fornisce metodi per allocare, modificare e liberare una BSTR.
La classe _bstr_t incapsula e gestisce il tipo di dati BSTR.
Quando il Riferimento dell'API ADO indica che un metodo o una proprietà accetta un valore String, significa che il valore è sotto forma di _bstr_t.
Esecuzione del cast di classi _variant_t e _bstr_t
Spesso non è necessario codificare in modo esplicito un _variant_t o un _bstr_t in un argomento per un'operazione. Se la classe _variant_t o _bstr_t ha un costruttore che corrisponde al tipo di dati dell'argomento, il compilatore genererà il _variant_t o _bstr_t appropriato.
Tuttavia, se l'argomento è ambiguo, ovvero, il tipo di dati dell'argomento corrisponde a più di un costruttore, è necessario eseguire il cast dell'argomento con il tipo di dati appropriato per richiamare il costruttore corretto.
Ad esempio, la dichiarazione per il metodo Recordset::Open è:
HRESULT Open (
const _variant_t & Source,
const _variant_t & ActiveConnection,
enum CursorTypeEnum CursorType,
enum LockTypeEnum LockType,
long Options );
L'argomento ActiveConnection
accetta un riferimento a un _variant_t, che può essere codificato come una stringa di connessione o un puntatore a un oggetto Connection aperto.
Il _variant_t corretto verrà costruito in modo implicito se si passa una stringa come "DSN=pubs;uid=MyUserName;pwd=MyPassword;
" o un puntatore come "(IDispatch *) pConn
".
Nota
Se ci si connette a un provider di origine dati che supporta l'autenticazione di Windows, è necessario specificare Trusted_Connection=yes o Integrated Security = SSPI anziché le informazioni sull'ID utente e sulla password nella stringa di connessione.
Oppure è possibile codificare in modo esplicito un _variant_t contenente un puntatore, ad esempio "_variant_t((IDispatch *) pConn, true)
". Il cast, (IDispatch *)
, risolve l'ambiguità con un altro costruttore che accetta un puntatore a un'interfaccia IUnknown.
È fondamentale, anche se raramente menzionato, che ADO sia un'interfaccia IDispatch. Ogni volta che un puntatore a un oggetto ADO deve essere passato come Variant, è necessario eseguirne il cast come puntatore a un'interfaccia IDispatch.
L'ultimo caso codifica in modo esplicito il secondo argomento booleano del costruttore con il relativo valore predefinito facoltativo di true
. Questo argomento causa la chiamata al metodo AddRef() del costruttore Variant, che compensa automaticamente la chiamata automatica al metodo _variant_t::Release() quando viene completata la chiamata al metodo o alla proprietà ADO.
SafeArray
Un oggetto SafeArray è un tipo di dati strutturato che contiene una matrice di altri tipi di dati. Un oggetto SafeArray viene chiamato sicuro perché contiene informazioni sui limiti di ogni dimensione della matrice e limita l'accesso agli elementi della matrice all'interno di tali limiti.
Quando il Riferimento dell'API ADO indica che un metodo o una proprietà accetta o restituisce una matrice, significa che il metodo o la proprietà accetta o restituisce una matrice SafeArray, non una matrice C/C++ nativa.
Ad esempio, il secondo parametro del metodo OpenSchema dell'oggetto Connection richiede una matrice di valori Variant. Tali valori Variant devono essere passati come elementi di un oggetto SafeArray e la matrice SafeArray deve essere impostata come valore di un'altra Variant. È l'altra Variant che viene passata come secondo argomento di OpenSchema.
Come altri esempi, il primo argomento del metodo Find è una Variant il cui valore è un valore safeArray unidimensionale; ognuno dei primi e secondi argomenti facoltativi di AddNew è un SafeArray unidimensionale; e il valore restituito del metodo GetRows è una Variant il cui valore è un SafeArray bidimensionale.
Parametri mancanti e predefiniti
Visual Basic consente parametri mancanti nei metodi. Ad esempio, il metodo Open dell'oggetto Recordset include cinque parametri, ma è possibile ignorare i parametri intermedi e lasciare i parametri finali. Una BSTR o Variant predefinita verrà sostituita a seconda del tipo di dati dell'operando mancante.
In C/C++, è necessario specificare tutti gli operandi. Se si vuole specificare un parametro mancante il cui tipo di dati è una stringa, specificare una _bstr_t contenente una stringa Null. Se si vuole specificare un parametro mancante il cui tipo di dati è una Variant, specificare una _variant_t con valore di DISP_E_PARAMNOTFOUND e tipo VT_ERROR. In alternativa, specificare la costante _variant_t equivalente, vtMissing, fornita dalla direttiva #import.
Tre metodi sono eccezioni all'uso tipico di vtMissing. Si tratta dei metodi Execute degli oggetti Connection e Command e del metodo NextRecordset dell'oggetto Recordset. Di seguito sono riportate le rispettive firme:
_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
I parametri RecordsAffected e Parameters sono puntatori a un valore Variant. Parameters è un parametro di input che specifica l'indirizzo di una Variant contenente un singolo parametro o una matrice di parametri che modificherà il comando in esecuzione. RecordsAffected è un parametro di output che specifica l'indirizzo di un valore Variant in cui viene restituito il numero di righe interessate dal metodo.
Nel metodo Execute dell'oggetto Command indicare che nessun parametro viene specificato impostando Parameters su &vtMissing
(scelta consigliata) o sul puntatore Null (ovvero NULL o zero (0)). Se Parameters è impostato sul puntatore Null, il metodo sostituisce internamente l'equivalente di vtMissing e quindi completa l'operazione.
In tutti i metodi indicare che il numero di record interessati non deve essere restituito impostando RecordsAffected sul puntatore Null. In questo caso, il puntatore Null non è tanto un parametro mancante, quanto un'indicazione che il metodo deve rimuovere il numero di record interessati.
Pertanto, per questi tre metodi, è valido codificare qualcosa come ad esempio:
pConnection->Execute("commandText", NULL, adCmdText);
pCommand->Execute(NULL, NULL, adCmdText);
pRecordset->NextRecordset(NULL);
Gestione errori
In COM, la maggior parte delle operazioni restituisce un codice restituito HRESULT, che indica se una funzione è stata completata correttamente. La direttiva #import genera il codice wrapper intorno a ogni metodo o proprietà "raw" e controlla il valore HRESULT restituito. Se HRESULT indica un errore, il codice wrapper genera un errore COM chiamando _com_issue_errorex() con il codice restituito HRESULT come argomento. Gli oggetti di errore COM possono essere rilevati in un blocco try-catch. Per motivi di efficienza, individuare un riferimento a un oggetto _com_error.
Tenere presente che si tratta di errori ADO: il risultato dell'operazione ADO ha esito negativo. Gli errori restituiti dal provider sottostante vengono visualizzati come oggetti Error nella raccolta Errors dell'oggetto Connection.
La direttiva #import crea solo routine di gestione degli errori per i metodi e le proprietà dichiarate nel file DLL di ADO. Tuttavia, è possibile sfruttare questo stesso meccanismo di gestione degli errori scrivendo una macro o una funzione inline di controllo degli errori. Per esempi, vedere l'argomento Estensioni di Visual C++ o il codice nelle sezioni seguenti.
Equivalenti di Visual C++ delle convenzioni di Visual Basic
Di seguito è riportato un riepilogo di diverse convenzioni nella documentazione di ADO, codificate in Visual Basic, nonché dei relativi equivalenti in Visual C++.
Dichiarazione di un oggetto ADO
In Visual Basic, una variabile oggetto ADO (in questo caso per un oggetto Recordset) viene dichiarata come segue:
Dim rst As ADODB.Recordset
La clausola "ADODB.Recordset
" è il ProgID dell'oggetto Recordset, come definito nel Registro di sistema. Una nuova istanza di un oggetto Record viene dichiarata come segue:
Dim rst As New ADODB.Recordset
oppure
Dim rst As ADODB.Recordset
Set rst = New ADODB.Recordset
In Visual C++, la direttiva #import genera dichiarazioni di tipo puntatore intelligente per tutti gli oggetti ADO. Ad esempio, una variabile che punta a un oggetto _Recordset è di tipo _RecordsetPtr e viene dichiarata come segue:
_RecordsetPtr rs;
Una variabile che punta a una nuova istanza di un oggetto _Recordset viene dichiarata come segue:
_RecordsetPtr rs("ADODB.Recordset");
oppure
_RecordsetPtr rs;
rs.CreateInstance("ADODB.Recordset");
oppure
_RecordsetPtr rs;
rs.CreateInstance(__uuidof(_Recordset));
Dopo aver chiamato il metodo CreateInstance, è possibile usare la variabile come segue:
rs->Open(...);
Si noti che in un caso, l'operatore ".
" viene usato come se la variabile fosse un'istanza di una classe (rs.CreateInstance
) e in un altro caso, l'operatore "->
" viene usato come se la variabile fosse un puntatore a un'interfaccia (rs->Open
).
Una variabile può essere usata in due modi perché l'operatore "->
" è sottoposto a overload per consentire a un'istanza di una classe di comportarsi come un puntatore a un'interfaccia. Un membro della classe privata della variabile di istanza contiene un puntatore all'interfaccia _Recordset; l'operatore "->
" restituisce tale puntatore e il puntatore restituito accede ai membri dell'oggetto _Recordset.
Codifica di un parametro mancante - Stringa
Quando è necessario codificare un operando String mancante in Visual Basic, è sufficiente omettere l'operando. È necessario specificare l'operando in Visual C++. Codificare una _bstr_t con una stringa vuota come valore.
_bstr_t strMissing(L"");
Codifica di un parametro mancante - Variante
Quando è necessario codificare un operando Variant mancante in Visual Basic, è sufficiente ometterlo. In Visual C++ è necessario specificare tutti gli operandi. Codificare un parametro Variant mancante con un _variant_t impostato sul valore speciale, DISP_E_PARAMNOTFOUND e tipo VT_ERROR. In alternativa, specificare vtMissing, ovvero una costante equivalente predefinita fornita dalla direttiva #import.
_variant_t vtMissingYours(DISP_E_PARAMNOTFOUND, VT_ERROR);
in alternativa usare:
...vtMissing...;
Dichiarazione di un valore Variant
In Visual Basic, un valore Variant viene dichiarato con l'istruzione Dim come indicato di seguito:
Dim VariableName As Variant
In Visual C++ dichiarare una variabile come tipo _variant_t. Di seguito sono riportate alcune dichiarazioni _variant_t schematiche.
Nota
Queste dichiarazioni offrono semplicemente un'idea approssimativa di ciò che si codificherebbe nel proprio programma. Per altre informazioni, vedere gli esempi seguenti e la documentazione di 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);
Uso di matrici di varianti
In Visual Basic le matrici di Variants possono essere codificate con l'istruzione Dim oppure è possibile usare la funzione Array, come dimostrato nel codice di esempio seguente:
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
Nell'esempio di Visual C++ seguente viene illustrato l'utilizzo di SafeArray con un _variant_t.
Note
Le note seguenti corrispondono alle sezioni commentate nell'esempio di codice.
Anche in questo caso, si definisce la funzione inline TESTHR() per sfruttare il meccanismo di gestione degli errori esistente.
È necessaria solo una matrice unidimensionale, quindi è possibile usare SafeArrayCreateVector, anziché la dichiarazione di utilizzo generico SAFEARRAYBOUND e la funzione SafeArrayCreate. Di seguito è riportato l'aspetto del codice con l'utilizzo di SafeArrayCreate:
SAFEARRAYBOUND sabound[1]; sabound[0].lLbound = 0; sabound[0].cElements = 4; pSa = SafeArrayCreate(VT_VARIANT, 1, sabound);
Lo schema identificato dalla costante enumerata, adSchemaColumns, è associato a quattro colonne di vincolo: TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME e COLUMN_NAME. Viene pertanto creata una matrice di valori Variant con quattro elementi. Viene specificato un valore di vincolo corrispondente alla terza colonna, TABLE_NAME.
L'oggetto Recordset restituito è costituito da diverse colonne, un subset del quale è costituito dalle colonne di vincolo. I valori delle colonne di vincolo per ogni riga restituita devono essere gli stessi dei valori dei vincoli corrispondenti.
Coloro che hanno familiarità con SafeArrays potrebbero essere sorpresi che SafeArrayDestroy() non venga chiamato prima dell'uscita. In questo caso, la chiamata a SafeArrayDestroy() causa un'eccezione di runtime. Il motivo è che il distruttore per
vtCriteria
chiamerà VariantClear() quando _variant_t esce dall'ambito, liberando SafeArray. Chiamando SafeArrayDestroy, senza cancellare manualmente _variant_t, il distruttore proverebbe a cancellare un puntatore SafeArray non valido.Se è stato chiamato SafeArrayDestroy, il codice sarà simile al seguente:
TESTHR(SafeArrayDestroy(pSa)); vtCriteria.vt = VT_EMPTY; vtCriteria.parray = NULL;
Tuttavia, è molto più semplice lasciare che _variant_t gestisca il 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();
}
Utilizzo della proprietà Get/Put/PutRef
In Visual Basic, il nome di una proprietà non è qualificato dal fatto che venga recuperato, assegnato o assegnato un riferimento.
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
In questo esempio di Visual C++ viene illustrata la Proprietà/Get/PutPutRef.
Note
Le note seguenti corrispondono alle sezioni commentate nell'esempio di codice.
In questo esempio vengono utilizzate due forme di un argomento stringa mancante: una costante esplicita, strMissing e una stringa che verrà usata dal compilatore per creare una _bstr_t temporanea che esisterà per l'ambito del metodo Open.
Non è necessario eseguire il cast dell'operando di
rs->PutRefActiveConnection(cn)
a(IDispatch *)
perché il tipo dell'operando è già(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();
}
Utilizzo di GetItem(x) e Item[x]
In questo esempio di Visual Basic viene illustrata la sintassi standard e alternativa per 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
In questo esempio di Visual C++ viene dimostrato Item.
Nota
La nota seguente corrisponde alle sezioni commentate nell'esempio di codice: quando si accede alla raccolta con Item, è necessario eseguire il cast dell'indice 2 su long, in modo che venga richiamato un costruttore appropriato.
// 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();
}
Cast dei puntatori di oggetti ADO con (IDispatch *)
L'esempio di Visual C++ seguente dimostra l'utilizzo di (IDispatch *) per eseguire il cast dei puntatori di oggetti ADO.
Note
Le note seguenti corrispondono alle sezioni commentate nell'esempio di codice.
Specificare un oggetto Connection aperto in un valore Variant codificato in modo esplicito. Eseguirne il cast con (IDispatch *) in modo che venga richiamato il costruttore corretto. Inoltre, impostare in modo esplicito il secondo parametro _variant_t sul valore predefinito true, in modo che il conteggio dei riferimenti all'oggetto sarà corretto al termine dell'operazione Recordset::Open.
L'espressione
(_bstr_t)
non è un cast, ma un operatore _variant_t che estrae una stringa _bstr_t dalla Variant restituita da Value.
L'espressione (char*)
non è un cast, ma un operatore _bstr_t che estrae un puntatore alla stringa incapsulata in un oggetto _bstr_t.
Questa sezione del codice illustra alcuni dei comportamenti utili degli operatori _variant_t e _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();
}