Datenzugriff mit ADO.NET (C++/CLI)
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 die gcroot
Schlüsselwort (keyword) erforderlich. Weitere Informationen gcroot
finden 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 main
Direktive 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 GlobalFree
von ihnen zugewiesen werden.
// 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>
using namespace std;
#using <System.Data.dll>
using namespace System;
using namespace System::Data;
using namespace System::Runtime::InteropServices;
#define MAXCOLS 100
#pragma managed
class DatabaseClass
{
public:
DatabaseClass() : table(nullptr) { }
void AddRow(char *stringColValue)
{
// Add a row to the table.
DataRow ^row = table->NewRow();
row["StringCol"] = Marshal::PtrToStringAnsi(
(IntPtr)stringColValue);
table->Rows->Add(row);
}
void CreateAndPopulateTable()
{
// 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);
}
int GetValuesForColumn(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 unmanaged
int main()
{
// 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;
return 0;
}
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:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_string_native.cpp
Marshal BSTR Strings for ADO.NET
Veranschaulicht das Hinzufügen einer COM-Zeichenfolge (BSTR
) zu einer Datenbank und das Marshallen einer System.String Datenbank in einer BSTR
Datenbank.
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 die gcroot
Schlüsselwort (keyword) erforderlich. Weitere Informationen gcroot
finden 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 main
Direktive 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 BSTR
zu marshallen.
Hinweis
Der von StringToBSTR ihnen zugewiesene Speicher muss durch Aufrufen einer FreeBSTR oder SysFreeString
von ihnen zugewiesen werden.
// 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>
using namespace std;
#using <System.Data.dll>
using namespace System;
using namespace System::Data;
using namespace System::Runtime::InteropServices;
#define MAXCOLS 100
#pragma managed
class DatabaseClass
{
public:
DatabaseClass() : table(nullptr) { }
void AddRow(BSTR stringColValue)
{
// Add a row to the table.
DataRow ^row = table->NewRow();
row["StringCol"] = Marshal::PtrToStringBSTR(
(IntPtr)stringColValue);
table->Rows->Add(row);
}
void CreateAndPopulateTable()
{
// 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);
}
int GetValuesForColumn(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 unmanaged
int main()
{
// 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;
return 0;
}
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:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_string_native.cpp
Marshal Unicode Strings for ADO.NET
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 die gcroot
Schlüsselwort (keyword) erforderlich. Weitere Informationen gcroot
finden 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 main
Direktive 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 GlobalFree
von ihnen zugewiesen werden.
// 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>
using namespace std;
#using <System.Data.dll>
using namespace System;
using namespace System::Data;
using namespace System::Runtime::InteropServices;
#define MAXCOLS 100
#pragma managed
class DatabaseClass
{
public:
DatabaseClass() : table(nullptr) { }
void AddRow(wchar_t *stringColValue)
{
// Add a row to the table.
DataRow ^row = table->NewRow();
row["StringCol"] = Marshal::PtrToStringUni(
(IntPtr)stringColValue);
table->Rows->Add(row);
}
void CreateAndPopulateTable()
{
// 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);
}
int GetValuesForColumn(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 unmanaged
int main()
{
// 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;
return 0;
}
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:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_string_wide.cpp
Marshal a VARIANT für ADO.NET
Veranschaulicht das Hinzufügen einer systemeigenen VARIANT
Datenbank und das Marshallen einer System.Object Datenbank aus einer Datenbank zu einer systemeigenen VARIANT
Datenbank.
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 die gcroot
Schlüsselwort (keyword) erforderlich. Weitere Informationen gcroot
finden 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 main
Direktive 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 VARIANT
Objectmarshallen, und die Methode GetNativeVariantForObject wird verwendet, um eine zu VARIANT
marshallenObject.
// 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>
using namespace std;
#using <System.Data.dll>
using namespace System;
using namespace System::Data;
using namespace System::Runtime::InteropServices;
#define MAXCOLS 100
#pragma managed
class DatabaseClass
{
public:
DatabaseClass() : table(nullptr) { }
void AddRow(VARIANT *objectColValue)
{
// Add a row to the table.
DataRow ^row = table->NewRow();
row["ObjectCol"] = Marshal::GetObjectForNativeVariant(
IntPtr(objectColValue));
table->Rows->Add(row);
}
void CreateAndPopulateTable()
{
// 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);
}
int GetValuesForColumn(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 unmanaged
int main()
{
// 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;
return 0;
}
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:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_variant.cpp
Marshal a SAFEARRAY for ADO.NET
Veranschaulicht das Hinzufügen einer nativen SAFEARRAY
Datenbank und das Marshallen eines verwalteten Arrays aus einer Datenbank zu einer systemeigenen SAFEARRAY
Datenbank.
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 die gcroot
Schlüsselwort (keyword) erforderlich. Weitere Informationen gcroot
finden 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 main
Direktive 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
// 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>
using namespace std;
#using <System.Data.dll>
using namespace System;
using namespace System::Data;
using namespace System::Runtime::InteropServices;
#define MAXCOLS 100
#pragma managed
class DatabaseClass
{
public:
DatabaseClass() : table(nullptr) { }
void AddRow(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);
}
void CreateAndPopulateTable()
{
// 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);
}
int GetValuesForColumn(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 unmanaged
int main()
{
// 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;
return 0;
}
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:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_safearray.cpp
.NET Framework-Sicherheit
Informationen zu Sicherheitsproblemen, die ADO.NET betreffen, finden Sie unter Sichern von ADO.NET Anwendungen.
Verwandte Abschnitte
Abschnitt | Beschreibung |
---|---|
ADO.NET | Bietet eine Übersicht über ADO.NET, eine Reihe von Klassen, die Datenzugriffsdienste für .NET-Programmierer verfügbar machen. |
Siehe auch
.NET Programming with C++/CLI (Visual C++) (.NET-Programmierung mit C++/CLI (Visual C++))
Interoperabilität von nativem Code und .NET