Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
ADO.NET — это API .NET Framework для доступа к данным, обеспечивающий мощь и простоту использования, непревзойдённые предыдущими решениями по доступу к данным. В этом разделе описываются некоторые проблемы, связанные с ADO.NET, уникальные для пользователей Visual C++, например маршалирование нативных типов.
ADO.NET выполняется в среде CLR. Поэтому любое приложение, взаимодействующее с ADO.NET, также должно быть предназначено для среды CLR. Однако это не означает, что собственные приложения не могут использовать ADO.NET. В этих примерах показано, как взаимодействовать с базой данных ADO.NET из машинного кода.
Маршал строк ANSI для ADO.NET
Демонстрирует добавление собственной строки (char *) в базу данных и конвертирование System.String из базы данных в собственную строку.
Пример
В этом примере класс DatabaseClass создается для взаимодействия с объектом ADO.NET DataTable . Обратите внимание, что этот класс является нативным C++ class (по сравнению с ref class или value class). Это необходимо, так как мы хотим использовать этот класс из машинного кода, и нельзя использовать управляемые типы в машинном коде. Этот класс будет скомпилирован, нацеленный на CLR, как указано директивой #pragma managed, предшествующей объявлению класса. Дополнительные сведения об этой директиве см. в разделе управляемый, неуправляемый.
Обратите внимание на частный член класса DatabaseClass: gcroot<DataTable ^> table Так как собственные типы не могут содержать управляемые типы, ключевое gcroot слово необходимо. Дополнительные сведения о gcroot смотрите в разделе «Практическое руководство: объявление дескрипторов в собственных типах».
Остальная часть кода в этом примере является машинным кодом C++, как показано в приведенной #pragma unmanaged выше mainдирективе. В этом примере мы создадим новый экземпляр DatabaseClass и вызываем его методы для создания таблицы и заполнения некоторых строк в таблице. Обратите внимание, что собственные строки C++ передаются в качестве значений для столбца базы данных StringCol. В классе DatabaseClass эти строки маршалируются в управляемые строки с использованием функции маршалинга, которая находится в пространстве имен System.Runtime.InteropServices. В частности, метод PtrToStringAnsi используется для маршалинга char * в объект String, а метод StringToHGlobalAnsi используется для маршалинга String в объект char *.
Примечание.
Память, выделенная с помощью StringToHGlobalAnsi, должна быть освобождена вызовом FreeHGlobal или GlobalFree.
// 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.
Компиляция кода
Чтобы скомпилировать код из командной строки, сохраните пример кода в файле с именем adonet_marshal_string_native.cpp и введите следующую инструкцию:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_string_native.cpp
Маршалирование строк BSTR для ADO.NET
Демонстрирует, как добавить COM-строку (BSTR) в базу данных и как маршалировать System.String из базы данных в BSTR.
Пример
В этом примере класс DatabaseClass создается для взаимодействия с объектом ADO.NET DataTable . Обратите внимание, что этот класс является нативным для C++ class (по сравнению с ref class или value class). Это необходимо, так как мы хотим использовать этот класс из машинного кода, и нельзя использовать управляемые типы в машинном коде. Этот класс будет скомпилирован для целевой платформы CLR, как указано директивой #pragma managed, предшествующей объявлению класса. Дополнительные сведения об этой директиве см. в разделе «Управляемый», неуправляемый.
Обратите внимание на частный член класса DatabaseClass: gcroot<DataTable ^> table Так как собственные типы не могут содержать управляемые типы, ключевое gcroot слово необходимо. Дополнительные сведения о gcroot см. в разделе "Практическое руководство: Объявление дескрипторов в собственных типах".
Остальная часть кода в этом примере является машинным кодом C++, как показано в приведенной #pragma unmanaged выше mainдирективе. В этом примере мы создадим новый экземпляр DatabaseClass и вызываем его методы для создания таблицы и заполнения некоторых строк в таблице. Обратите внимание, что com-строки передаются в качестве значений для столбца базы данных StringCol. В классе DatabaseClass эти строки маршалируются в управляемые строки с помощью функции маршалинга, расположенной в пространстве имен System.Runtime.InteropServices. В частности, метод PtrToStringBSTR используется для маршалинга BSTR в объект String, а метод StringToBSTR используется для маршалинга String в объект BSTR.
Примечание.
Память, выделенная с помощью StringToBSTR, должна быть освобождена вызовом FreeBSTR или SysFreeString.
// 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.
Компиляция кода
Чтобы скомпилировать код из командной строки, сохраните пример кода в файле с именем adonet_marshal_string_native.cpp и введите следующую инструкцию:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_string_native.cpp
Маршал строк Юникода для ADO.NET
Демонстрируется добавление строки Юникода (wchar_t *) в базу данных и преобразование System.String из базы данных в строку Юникода.
Пример
В этом примере класс DatabaseClass создается для взаимодействия с объектом ADO.NET DataTable . Обратите внимание, что этот класс является собственным C++ class (по сравнению с ref class или value class). Это необходимо, так как мы хотим использовать этот класс из машинного кода, и нельзя использовать управляемые типы в машинном коде. Этот класс будет скомпилирован для целевой платформы CLR, как указано директивой #pragma managed, предшествующей объявлению класса. Дополнительные сведения об этой директиве см. в разделе «управляемый», «неуправляемый».
Обратите внимание на приватный элемент класса DatabaseClass: gcroot<DataTable ^> table Так как собственные типы не могут содержать управляемые типы, ключевое gcroot слово необходимо. Дополнительные сведения о gcroot можно найти в разделе "Практическое руководство: Объявление дескрипторов в собственных типах".
Остальная часть кода в этом примере является машинным кодом C++, как показано в приведенной #pragma unmanaged выше mainдирективе. В этом примере мы создадим новый экземпляр DatabaseClass и вызываем его методы для создания таблицы и заполнения некоторых строк в таблице. Обратите внимание, что строки C++ Юникода передаются в качестве значений для столбца базы данных StringCol. В DatabaseClass эти строки маршалируются в управляемые строки с использованием механизма маршалинга, найденного в пространстве имен System.Runtime.InteropServices. В частности, метод PtrToStringUni используется для маршалинга wchar_t * в объект String, а метод StringToHGlobalUni используется для маршалинга String в объект wchar_t *.
Примечание.
Выделенная память StringToHGlobalUni должна быть освобождена путем вызова FreeHGlobal или GlobalFree.
// 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.
Компиляция кода
Чтобы скомпилировать код из командной строки, сохраните пример кода в файле с именем adonet_marshal_string_wide.cpp и введите следующую инструкцию:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_string_wide.cpp
Маршал вариант для ADO.NET
Демонстрирует, как добавить нативный VARIANT в базу данных и как маршализовать System.Object из базы данных в нативный VARIANT.
Пример
В этом примере класс DatabaseClass создается для взаимодействия с объектом ADO.NET DataTable . Обратите внимание, что этот класс является собственным C++ class, в отличие от класса ref class или value class. Это необходимо, так как мы хотим использовать этот класс из машинного кода, и нельзя использовать управляемые типы в машинном коде. Этот класс будет компилирован для целевой среды CLR, как указано директивой #pragma managed, предшествующей объявлению класса. Дополнительные сведения об этой директиве см. в разделе управляемый, неуправляемый.
Обратите внимание на частный член класса DatabaseClass: gcroot<DataTable ^> table Так как собственные типы не могут содержать управляемые типы, ключевое gcroot слово необходимо. Дополнительные сведения gcrootсм. в разделе "Практическое руководство. Объявление дескрипторов в собственных типах".
Остальная часть кода в этом примере является машинным кодом C++, как показано в приведенной #pragma unmanaged выше mainдирективе. В этом примере мы создадим новый экземпляр DatabaseClass и вызываем его методы для создания таблицы и заполнения некоторых строк в таблице. Обратите внимание, что собственные VARIANT типы передаются как значения для столбца базы данных ObjectCol. В DatabaseClass эти VARIANT типы преобразуются в управляемые объекты с помощью маршалинга из пространства имен System.Runtime.InteropServices. В частности, метод GetObjectForNativeVariant используется для маршалинга VARIANT в объект Object, а метод GetNativeVariantForObject используется для маршалинга Object в объект VARIANT.
// 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
Компиляция кода
Чтобы скомпилировать код из командной строки, сохраните пример кода в файле с именем adonet_marshal_variant.cpp и введите следующую инструкцию:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_variant.cpp
Маршал SAFEARRAY для ADO.NET
Демонстрирует, как добавить нативный SAFEARRAY в базу данных и как переносить управляемый массив из базы данных в нативный SAFEARRAY.
Пример
В этом примере класс DatabaseClass создается для взаимодействия с объектом ADO.NET DataTable . Обратите внимание, что этот класс является собственным C++ class (по сравнению с ref class или value class). Это необходимо, так как мы хотим использовать этот класс из машинного кода, и нельзя использовать управляемые типы в машинном коде. Этот класс будет компилирован для целевой платформы CLR, как указано директивой #pragma managed, предшествующей объявлению класса. Дополнительные сведения об этой директиве см. в разделе «Управляемый», «неуправляемый».
Обратите внимание на приватный элемент класса DatabaseClass: gcroot<DataTable ^> table Так как собственные типы не могут содержать управляемые типы, ключевое gcroot слово необходимо. Дополнительную информацию о gcroot см. в разделе "Инструкция: Объявление дескрипторов в нативных типах".
Остальная часть кода в этом примере является машинным кодом C++, как показано в приведенной #pragma unmanaged выше mainдирективе. В этом примере мы создадим новый экземпляр DatabaseClass и вызываем его методы для создания таблицы и заполнения некоторых строк в таблице. Обратите внимание, что собственные SAFEARRAY типы передаются в качестве значений для столбца базы данных ArrayIntsCol. В DatabaseClass эти SAFEARRAY типы преобразуются в управляемые объекты с помощью маршалинга из пространства имен System.Runtime.InteropServices. В частности, метод Copy используется для маршалинга SAFEARRAY в управляемый массив целых чисел, а метод Copy используется для маршалинга управляемого массива целых чисел в 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
Компиляция кода
Чтобы скомпилировать код из командной строки, сохраните пример кода в файле с именем adonet_marshal_safearray.cpp и введите следующую инструкцию:
cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_safearray.cpp
Безопасность .NET Framework
Сведения о проблемах безопасности, связанных с ADO.NET, см. в разделе "Защита приложений ADO.NET".
Связанные разделы
| Раздел | Описание |
|---|---|
| ADO.NET | Содержит обзор ADO.NET, набор классов, предоставляющих службы доступа к данным программисту .NET. |
См. также
Программирование .NET с использованием C++/CLI (Visual C++)
Взаимодействие исходного кода и платформы.NET