ADO.NET ist die .NET Framework-API für den Datenzugriff und bietet Leistung und Benutzerfreundlichkeit, die von früheren Datenzugriffslösungen nicht übereinstimmen. In diesem Abschnitt werden einige der Probleme beschrieben, die ADO.NET betreffen, die für Visual C++-Benutzer eindeutig sind, z. B. das Marshallen systemeigener Typen.
ADO.NET wird unter der Common Language Runtime (CLR) ausgeführt. Daher muss jede Anwendung, die mit ADO.NET interagiert, auch auf die CLR abzielen. Das bedeutet jedoch nicht, dass systemeigene Anwendungen ADO.NET nicht verwenden können. In diesen Beispielen wird die Interaktion mit einer ADO.NET Datenbank aus systemeigenem Code veranschaulicht.
Marshal ANSI-Zeichenfolgen für ADO.NET
Veranschaulicht das Hinzufügen einer systemeigenen Zeichenfolge (char *) zu einer Datenbank und das Marshallen einer System.String Datenbank in eine systemeigene Zeichenfolge.
Beispiel
In diesem Beispiel wird die Klasse DatabaseClass erstellt, um mit einem ADO.NET-Objekt DataTable zu interagieren. Beachten Sie, dass es sich bei dieser Klasse um ein systemeigenes C++ class handelt (im Vergleich zu einem ref class oder value class). Dies ist erforderlich, da wir diese Klasse aus systemeigenem Code verwenden möchten, und Sie können keine verwalteten Typen in systemeigenem Code verwenden. Diese Klasse wird so kompiliert, dass sie auf die CLR ausgerichtet ist, wie durch die #pragma managed Direktive vor der Klassendeklaration angegeben. Weitere Informationen zu dieser Direktive finden Sie unter verwalteter, nicht verwalteter Richtlinie.
Beachten Sie das private Mitglied der DatabaseClass-Klasse: gcroot<DataTable ^> table. Da systemeigene Typen keine verwalteten Typen enthalten können, ist das gcroot Schlüsselwort erforderlich. Weitere Informationen gcrootfinden Sie unter How to: Declare Handles in Native Types.
Der rest des Codes in diesem Beispiel ist systemeigener C++-Code, wie durch die #pragma unmanaged vorangehende mainDirektive angegeben. In diesem Beispiel erstellen wir eine neue Instanz von DatabaseClass und rufen die zugehörigen Methoden auf, um eine Tabelle zu erstellen und einige Zeilen in der Tabelle aufzufüllen. Beachten Sie, dass systemeigene C++-Zeichenfolgen als Werte für die Datenbankspalte StringCol übergeben werden. Innerhalb von DatabaseClass werden diese Zeichenfolgen mithilfe der Im Namespace gefundenen System.Runtime.InteropServices Marshaling-Funktionalität an verwaltete Zeichenfolgen gemarstet. Insbesondere wird die Methode PtrToStringAnsi verwendet, um ein bis char * a Stringzu marshallen, und die Methode StringToHGlobalAnsi wird verwendet, um ein String an ein char *zu marshallen.
Hinweis
Der von StringToHGlobalAnsi ihnen zugewiesene Speicher muss durch Aufrufen einer FreeHGlobal oder GlobalFreevon ihnen zugewiesen werden.
C++
// adonet_marshal_string_native.cpp// compile with: /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll#include<comdef.h>#include<gcroot.h>#include<iostream>usingnamespacestd;
#using <System.Data.dll>usingnamespace System;
usingnamespace System::Data;
usingnamespace System::Runtime::InteropServices;
#define MAXCOLS 100#pragma managedclassDatabaseClass
{public:
DatabaseClass() : table(nullptr) { }
voidAddRow(char *stringColValue){
// Add a row to the table.
DataRow ^row = table->NewRow();
row["StringCol"] = Marshal::PtrToStringAnsi(
(IntPtr)stringColValue);
table->Rows->Add(row);
}
voidCreateAndPopulateTable(){
// Create a simple DataTable.
table = gcnew DataTable("SampleTable");
// Add a column of type String to the table.
DataColumn ^column1 = gcnew DataColumn("StringCol",
Type::GetType("System.String"));
table->Columns->Add(column1);
}
intGetValuesForColumn(char *dataColumn, char **values,
int valuesLength){
// Marshal the name of the column to a managed// String.
String ^columnStr = Marshal::PtrToStringAnsi(
(IntPtr)dataColumn);
// Get all rows in the table.array<DataRow ^> ^rows = table->Select();
int len = rows->Length;
len = (len > valuesLength) ? valuesLength : len;
for (int i = 0; i < len; i++)
{
// Marshal each column value from a managed string// to a char *.
values[i] = (char *)Marshal::StringToHGlobalAnsi(
(String ^)rows[i][columnStr]).ToPointer();
}
return len;
}
private:
// Using gcroot, you can use a managed type in// a native class.
gcroot<DataTable ^> table;
};
#pragma unmanagedintmain(){
// Create a table and add a few rows to it.
DatabaseClass *db = new DatabaseClass();
db->CreateAndPopulateTable();
db->AddRow("This is string 1.");
db->AddRow("This is string 2.");
// Now retrieve the rows and display their contents.char *values[MAXCOLS];
int len = db->GetValuesForColumn(
"StringCol", values, MAXCOLS);
for (int i = 0; i < len; i++)
{
cout << "StringCol: " << values[i] << endl;
// Deallocate the memory allocated using// Marshal::StringToHGlobalAnsi.
GlobalFree(values[i]);
}
delete db;
return0;
}
Output
StringCol: This is string 1.
StringCol: This is string 2.
Kompilieren des Codes
Um den Code aus der Befehlszeile zu kompilieren, speichern Sie das Codebeispiel in einer Datei namens adonet_marshal_string_native.cpp, und geben Sie die folgende Anweisung ein:
Veranschaulicht das Hinzufügen einer COM-Zeichenfolge (BSTR) zu einer Datenbank und das Marshallen einer System.String Datenbank in einer BSTRDatenbank.
Beispiel
In diesem Beispiel wird die Klasse DatabaseClass erstellt, um mit einem ADO.NET-Objekt DataTable zu interagieren. Beachten Sie, dass es sich bei dieser Klasse um ein systemeigenes C++ class handelt (im Vergleich zu einem ref class oder value class). Dies ist erforderlich, da wir diese Klasse aus systemeigenem Code verwenden möchten, und Sie können keine verwalteten Typen in systemeigenem Code verwenden. Diese Klasse wird so kompiliert, dass sie auf die CLR ausgerichtet ist, wie durch die #pragma managed Direktive vor der Klassendeklaration angegeben. Weitere Informationen zu dieser Direktive finden Sie unter verwalteter, nicht verwalteter Richtlinie.
Beachten Sie das private Mitglied der DatabaseClass-Klasse: gcroot<DataTable ^> table. Da systemeigene Typen keine verwalteten Typen enthalten können, ist das gcroot Schlüsselwort erforderlich. Weitere Informationen gcrootfinden Sie unter How to: Declare Handles in Native Types.
Der rest des Codes in diesem Beispiel ist systemeigener C++-Code, wie durch die #pragma unmanaged vorangehende mainDirektive angegeben. In diesem Beispiel erstellen wir eine neue Instanz von DatabaseClass und rufen die zugehörigen Methoden auf, um eine Tabelle zu erstellen und einige Zeilen in der Tabelle aufzufüllen. Beachten Sie, dass COM-Zeichenfolgen als Werte für die Datenbankspalte StringCol übergeben werden. Innerhalb von DatabaseClass werden diese Zeichenfolgen mithilfe der Im Namespace gefundenen System.Runtime.InteropServices Marshaling-Funktionalität an verwaltete Zeichenfolgen gemarstet. Insbesondere wird die Methode PtrToStringBSTR verwendet, um ein bis BSTR a Stringzu marshallen, und die Methode StringToBSTR wird verwendet, um ein String an ein BSTRzu marshallen.
Hinweis
Der von StringToBSTR ihnen zugewiesene Speicher muss durch Aufrufen einer FreeBSTR oder SysFreeStringvon ihnen zugewiesen werden.
C++
// adonet_marshal_string_bstr.cpp// compile with: /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll#include<comdef.h>#include<gcroot.h>#include<iostream>usingnamespacestd;
#using <System.Data.dll>usingnamespace System;
usingnamespace System::Data;
usingnamespace System::Runtime::InteropServices;
#define MAXCOLS 100#pragma managedclassDatabaseClass
{public:
DatabaseClass() : table(nullptr) { }
voidAddRow(BSTR stringColValue){
// Add a row to the table.
DataRow ^row = table->NewRow();
row["StringCol"] = Marshal::PtrToStringBSTR(
(IntPtr)stringColValue);
table->Rows->Add(row);
}
voidCreateAndPopulateTable(){
// Create a simple DataTable.
table = gcnew DataTable("SampleTable");
// Add a column of type String to the table.
DataColumn ^column1 = gcnew DataColumn("StringCol",
Type::GetType("System.String"));
table->Columns->Add(column1);
}
intGetValuesForColumn(BSTR dataColumn, BSTR *values,
int valuesLength){
// Marshal the name of the column to a managed// String.
String ^columnStr = Marshal::PtrToStringBSTR(
(IntPtr)dataColumn);
// Get all rows in the table.array<DataRow ^> ^rows = table->Select();
int len = rows->Length;
len = (len > valuesLength) ? valuesLength : len;
for (int i = 0; i < len; i++)
{
// Marshal each column value from a managed string// to a BSTR.
values[i] = (BSTR)Marshal::StringToBSTR(
(String ^)rows[i][columnStr]).ToPointer();
}
return len;
}
private:
// Using gcroot, you can use a managed type in// a native class.
gcroot<DataTable ^> table;
};
#pragma unmanagedintmain(){
// Create a table and add a few rows to it.
DatabaseClass *db = new DatabaseClass();
db->CreateAndPopulateTable();
BSTR str1 = SysAllocString(L"This is string 1.");
db->AddRow(str1);
BSTR str2 = SysAllocString(L"This is string 2.");
db->AddRow(str2);
// Now retrieve the rows and display their contents.
BSTR values[MAXCOLS];
BSTR str3 = SysAllocString(L"StringCol");
int len = db->GetValuesForColumn(
str3, values, MAXCOLS);
for (int i = 0; i < len; i++)
{
wcout << "StringCol: " << values[i] << endl;
// Deallocate the memory allocated using// Marshal::StringToBSTR.
SysFreeString(values[i]);
}
SysFreeString(str1);
SysFreeString(str2);
SysFreeString(str3);
delete db;
return0;
}
Output
StringCol: This is string 1.
StringCol: This is string 2.
Kompilieren des Codes
Um den Code aus der Befehlszeile zu kompilieren, speichern Sie das Codebeispiel in einer Datei namens adonet_marshal_string_native.cpp, und geben Sie die folgende Anweisung ein:
Veranschaulicht das Hinzufügen einer systemeigenen Unicode-Zeichenfolge (wchar_t *) zu einer Datenbank und das Marshallen einer System.String Datenbank in eine systemeigene Unicode-Zeichenfolge.
Beispiel
In diesem Beispiel wird die Klasse DatabaseClass erstellt, um mit einem ADO.NET-Objekt DataTable zu interagieren. Beachten Sie, dass es sich bei dieser Klasse um ein systemeigenes C++ class handelt (im Vergleich zu einem ref class oder value class). Dies ist erforderlich, da wir diese Klasse aus systemeigenem Code verwenden möchten, und Sie können keine verwalteten Typen in systemeigenem Code verwenden. Diese Klasse wird so kompiliert, dass sie auf die CLR ausgerichtet ist, wie durch die #pragma managed Direktive vor der Klassendeklaration angegeben. Weitere Informationen zu dieser Direktive finden Sie unter verwalteter, nicht verwalteter Richtlinie.
Beachten Sie das private Mitglied der DatabaseClass-Klasse: gcroot<DataTable ^> table. Da systemeigene Typen keine verwalteten Typen enthalten können, ist das gcroot Schlüsselwort erforderlich. Weitere Informationen gcrootfinden Sie unter How to: Declare Handles in Native Types.
Der rest des Codes in diesem Beispiel ist systemeigener C++-Code, wie durch die #pragma unmanaged vorangehende mainDirektive angegeben. In diesem Beispiel erstellen wir eine neue Instanz von DatabaseClass und rufen die zugehörigen Methoden auf, um eine Tabelle zu erstellen und einige Zeilen in der Tabelle aufzufüllen. Beachten Sie, dass Unicode-C++-Zeichenfolgen als Werte für die Datenbankspalte StringCol übergeben werden. Innerhalb von DatabaseClass werden diese Zeichenfolgen mithilfe der Im Namespace gefundenen System.Runtime.InteropServices Marshaling-Funktionalität an verwaltete Zeichenfolgen gemarstet. Insbesondere wird die Methode PtrToStringUni verwendet, um ein bis wchar_t * a Stringzu marshallen, und die Methode StringToHGlobalUni wird verwendet, um ein String an ein wchar_t *zu marshallen.
Hinweis
Der von StringToHGlobalUni ihnen zugewiesene Speicher muss durch Aufrufen einer FreeHGlobal oder GlobalFreevon ihnen zugewiesen werden.
C++
// adonet_marshal_string_wide.cpp// compile with: /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll#include<comdef.h>#include<gcroot.h>#include<iostream>usingnamespacestd;
#using <System.Data.dll>usingnamespace System;
usingnamespace System::Data;
usingnamespace System::Runtime::InteropServices;
#define MAXCOLS 100#pragma managedclassDatabaseClass
{public:
DatabaseClass() : table(nullptr) { }
voidAddRow(wchar_t *stringColValue){
// Add a row to the table.
DataRow ^row = table->NewRow();
row["StringCol"] = Marshal::PtrToStringUni(
(IntPtr)stringColValue);
table->Rows->Add(row);
}
voidCreateAndPopulateTable(){
// Create a simple DataTable.
table = gcnew DataTable("SampleTable");
// Add a column of type String to the table.
DataColumn ^column1 = gcnew DataColumn("StringCol",
Type::GetType("System.String"));
table->Columns->Add(column1);
}
intGetValuesForColumn(wchar_t *dataColumn, wchar_t **values,
int valuesLength){
// Marshal the name of the column to a managed// String.
String ^columnStr = Marshal::PtrToStringUni(
(IntPtr)dataColumn);
// Get all rows in the table.array<DataRow ^> ^rows = table->Select();
int len = rows->Length;
len = (len > valuesLength) ? valuesLength : len;
for (int i = 0; i < len; i++)
{
// Marshal each column value from a managed string// to a wchar_t *.
values[i] = (wchar_t *)Marshal::StringToHGlobalUni(
(String ^)rows[i][columnStr]).ToPointer();
}
return len;
}
private:
// Using gcroot, you can use a managed type in// a native class.
gcroot<DataTable ^> table;
};
#pragma unmanagedintmain(){
// Create a table and add a few rows to it.
DatabaseClass *db = new DatabaseClass();
db->CreateAndPopulateTable();
db->AddRow(L"This is string 1.");
db->AddRow(L"This is string 2.");
// Now retrieve the rows and display their contents.wchar_t *values[MAXCOLS];
int len = db->GetValuesForColumn(
L"StringCol", values, MAXCOLS);
for (int i = 0; i < len; i++)
{
wcout << "StringCol: " << values[i] << endl;
// Deallocate the memory allocated using// Marshal::StringToHGlobalUni.
GlobalFree(values[i]);
}
delete db;
return0;
}
Output
StringCol: This is string 1.
StringCol: This is string 2.
Kompilieren des Codes
Um den Code aus der Befehlszeile zu kompilieren, speichern Sie das Codebeispiel in einer Datei namens adonet_marshal_string_wide.cpp, und geben Sie die folgende Anweisung ein:
Veranschaulicht das Hinzufügen einer systemeigenen VARIANT Datenbank und das Marshallen einer System.Object Datenbank aus einer Datenbank zu einer systemeigenen VARIANTDatenbank.
Beispiel
In diesem Beispiel wird die Klasse DatabaseClass erstellt, um mit einem ADO.NET-Objekt DataTable zu interagieren. Beachten Sie, dass es sich bei dieser Klasse um ein systemeigenes C++ class handelt (im Vergleich zu einem ref class oder value class). Dies ist erforderlich, da wir diese Klasse aus systemeigenem Code verwenden möchten, und Sie können keine verwalteten Typen in systemeigenem Code verwenden. Diese Klasse wird so kompiliert, dass sie auf die CLR ausgerichtet ist, wie durch die #pragma managed Direktive vor der Klassendeklaration angegeben. Weitere Informationen zu dieser Direktive finden Sie unter verwalteter, nicht verwalteter Richtlinie.
Beachten Sie das private Mitglied der DatabaseClass-Klasse: gcroot<DataTable ^> table. Da systemeigene Typen keine verwalteten Typen enthalten können, ist das gcroot Schlüsselwort erforderlich. Weitere Informationen gcrootfinden Sie unter How to: Declare Handles in Native Types.
Der rest des Codes in diesem Beispiel ist systemeigener C++-Code, wie durch die #pragma unmanaged vorangehende mainDirektive angegeben. In diesem Beispiel erstellen wir eine neue Instanz von DatabaseClass und rufen die zugehörigen Methoden auf, um eine Tabelle zu erstellen und einige Zeilen in der Tabelle aufzufüllen. Beachten Sie, dass systemeigene VARIANT Typen als Werte für die Datenbankspalte ObjectCol übergeben werden. Innerhalb von DatabaseClass werden diese VARIANT Typen mithilfe der Marshaling-Funktionalität im System.Runtime.InteropServices Namespace an verwaltete Objekte gemarstet. Insbesondere wird die Methode GetObjectForNativeVariant verwendet, um eine an zu VARIANTObjectmarshallen, und die Methode GetNativeVariantForObject wird verwendet, um eine zu VARIANTmarshallenObject.
C++
// adonet_marshal_variant.cpp// compile with: /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll#include<comdef.h>#include<gcroot.h>#include<iostream>usingnamespacestd;
#using <System.Data.dll>usingnamespace System;
usingnamespace System::Data;
usingnamespace System::Runtime::InteropServices;
#define MAXCOLS 100#pragma managedclassDatabaseClass
{public:
DatabaseClass() : table(nullptr) { }
voidAddRow(VARIANT *objectColValue){
// Add a row to the table.
DataRow ^row = table->NewRow();
row["ObjectCol"] = Marshal::GetObjectForNativeVariant(
IntPtr(objectColValue));
table->Rows->Add(row);
}
voidCreateAndPopulateTable(){
// Create a simple DataTable.
table = gcnew DataTable("SampleTable");
// Add a column of type String to the table.
DataColumn ^column1 = gcnew DataColumn("ObjectCol",
Type::GetType("System.Object"));
table->Columns->Add(column1);
}
intGetValuesForColumn(wchar_t *dataColumn, VARIANT *values,
int valuesLength){
// Marshal the name of the column to a managed// String.
String ^columnStr = Marshal::PtrToStringUni(
(IntPtr)dataColumn);
// Get all rows in the table.array<DataRow ^> ^rows = table->Select();
int len = rows->Length;
len = (len > valuesLength) ? valuesLength : len;
for (int i = 0; i < len; i++)
{
// Marshal each column value from a managed object// to a VARIANT.
Marshal::GetNativeVariantForObject(
rows[i][columnStr], IntPtr(&values[i]));
}
return len;
}
private:
// Using gcroot, you can use a managed type in// a native class.
gcroot<DataTable ^> table;
};
#pragma unmanagedintmain(){
// Create a table and add a few rows to it.
DatabaseClass *db = new DatabaseClass();
db->CreateAndPopulateTable();
BSTR bstr1 = SysAllocString(L"This is a BSTR in a VARIANT.");
VARIANT v1;
v1.vt = VT_BSTR;
v1.bstrVal = bstr1;
db->AddRow(&v1);
int i = 42;
VARIANT v2;
v2.vt = VT_I4;
v2.lVal = i;
db->AddRow(&v2);
// Now retrieve the rows and display their contents.
VARIANT values[MAXCOLS];
int len = db->GetValuesForColumn(
L"ObjectCol", values, MAXCOLS);
for (int i = 0; i < len; i++)
{
switch (values[i].vt)
{
case VT_BSTR:
wcout << L"ObjectCol: " << values[i].bstrVal << endl;
break;
case VT_I4:
cout << "ObjectCol: " << values[i].lVal << endl;
break;
default:
break;
}
}
SysFreeString(bstr1);
delete db;
return0;
}
Output
ObjectCol: This is a BSTR in a VARIANT.
ObjectCol: 42
Kompilieren des Codes
Um den Code aus der Befehlszeile zu kompilieren, speichern Sie das Codebeispiel in einer Datei namens adonet_marshal_variant.cpp, und geben Sie die folgende Anweisung ein:
Veranschaulicht das Hinzufügen einer nativen SAFEARRAY Datenbank und das Marshallen eines verwalteten Arrays aus einer Datenbank zu einer systemeigenen SAFEARRAYDatenbank.
Beispiel
In diesem Beispiel wird die Klasse DatabaseClass erstellt, um mit einem ADO.NET-Objekt DataTable zu interagieren. Beachten Sie, dass es sich bei dieser Klasse um ein systemeigenes C++ class handelt (im Vergleich zu einem ref class oder value class). Dies ist erforderlich, da wir diese Klasse aus systemeigenem Code verwenden möchten, und Sie können keine verwalteten Typen in systemeigenem Code verwenden. Diese Klasse wird so kompiliert, dass sie auf die CLR ausgerichtet ist, wie durch die #pragma managed Direktive vor der Klassendeklaration angegeben. Weitere Informationen zu dieser Direktive finden Sie unter verwalteter, nicht verwalteter Richtlinie.
Beachten Sie das private Mitglied der DatabaseClass-Klasse: gcroot<DataTable ^> table. Da systemeigene Typen keine verwalteten Typen enthalten können, ist das gcroot Schlüsselwort erforderlich. Weitere Informationen gcrootfinden Sie unter How to: Declare Handles in Native Types.
Der rest des Codes in diesem Beispiel ist systemeigener C++-Code, wie durch die #pragma unmanaged vorangehende mainDirektive angegeben. In diesem Beispiel erstellen wir eine neue Instanz von DatabaseClass und rufen die zugehörigen Methoden auf, um eine Tabelle zu erstellen und einige Zeilen in der Tabelle aufzufüllen. Beachten Sie, dass systemeigene SAFEARRAY Typen als Werte für die Datenbankspalte ArrayIntsCol übergeben werden. Innerhalb von DatabaseClass werden diese SAFEARRAY Typen mithilfe der Marshaling-Funktionalität im System.Runtime.InteropServices Namespace an verwaltete Objekte gemarstet. Insbesondere wird die Methode Copy verwendet, um ein SAFEARRAY verwaltetes Array von ganzen Zahlen zu marshallen, und die Methode Copy wird verwendet, um ein verwaltetes Array von ganzen Zahlen zu marshallen.SAFEARRAY
C++
// adonet_marshal_safearray.cpp// compile with: /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll#include<comdef.h>#include<gcroot.h>#include<iostream>usingnamespacestd;
#using <System.Data.dll>usingnamespace System;
usingnamespace System::Data;
usingnamespace System::Runtime::InteropServices;
#define MAXCOLS 100#pragma managedclassDatabaseClass
{public:
DatabaseClass() : table(nullptr) { }
voidAddRow(SAFEARRAY *arrayIntsColValue){
// Add a row to the table.
DataRow ^row = table->NewRow();
int len = arrayIntsColValue->rgsabound[0].cElements;
array<int> ^arr = gcnew array<int>(len);
int *pData;
SafeArrayAccessData(arrayIntsColValue, (void **)&pData);
Marshal::Copy(IntPtr(pData), arr, 0, len);
SafeArrayUnaccessData(arrayIntsColValue);
row["ArrayIntsCol"] = arr;
table->Rows->Add(row);
}
voidCreateAndPopulateTable(){
// Create a simple DataTable.
table = gcnew DataTable("SampleTable");
// Add a column of type String to the table.
DataColumn ^column1 = gcnew DataColumn("ArrayIntsCol",
Type::GetType("System.Int32[]"));
table->Columns->Add(column1);
}
intGetValuesForColumn(wchar_t *dataColumn, SAFEARRAY **values,
int valuesLength){
// Marshal the name of the column to a managed// String.
String ^columnStr = Marshal::PtrToStringUni(
(IntPtr)dataColumn);
// Get all rows in the table.array<DataRow ^> ^rows = table->Select();
int len = rows->Length;
len = (len > valuesLength) ? valuesLength : len;
for (int i = 0; i < len; i++)
{
// Marshal each column value from a managed array// of Int32s to a SAFEARRAY of type VT_I4.
values[i] = SafeArrayCreateVector(VT_I4, 0, 10);
int *pData;
SafeArrayAccessData(values[i], (void **)&pData);
Marshal::Copy((array<int> ^)rows[i][columnStr], 0,
IntPtr(pData), 10);
SafeArrayUnaccessData(values[i]);
}
return len;
}
private:
// Using gcroot, you can use a managed type in// a native class.
gcroot<DataTable ^> table;
};
#pragma unmanagedintmain(){
// Create a table and add a few rows to it.
DatabaseClass *db = new DatabaseClass();
db->CreateAndPopulateTable();
// Create a standard array.int originalArray[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
// Create a SAFEARRAY.
SAFEARRAY *psa;
psa = SafeArrayCreateVector(VT_I4, 0, 10);
// Copy the data from the original array to the SAFEARRAY.int *pData;
HRESULT hr = SafeArrayAccessData(psa, (void **)&pData);
memcpy(pData, &originalArray, 40);
SafeArrayUnaccessData(psa);
db->AddRow(psa);
// Now retrieve the rows and display their contents.
SAFEARRAY *values[MAXCOLS];
int len = db->GetValuesForColumn(
L"ArrayIntsCol", values, MAXCOLS);
for (int i = 0; i < len; i++)
{
int *pData;
SafeArrayAccessData(values[i], (void **)&pData);
for (int j = 0; j < 10; j++)
{
cout << pData[j] << " ";
}
cout << endl;
SafeArrayUnaccessData(values[i]);
// Deallocate the memory allocated using// SafeArrayCreateVector.
SafeArrayDestroy(values[i]);
}
SafeArrayDestroy(psa);
delete db;
return0;
}
Output
0 1 2 3 4 5 6 7 8 9
Kompilieren des Codes
Um den Code aus der Befehlszeile zu kompilieren, speichern Sie das Codebeispiel in einer Datei namens adonet_marshal_safearray.cpp, und geben Sie die folgende Anweisung ein:
Hier erfahren Sie mehr über die Datenbanksysteme, mit denen .NET Aspire eine Verbindung mit integrierten Komponenten herstellen kann. Anschließend erfahren Sie, wie Sie Verbindungen mit relationalen und nicht-relationalen Datenbanken herstellen und Daten darin speichern können.