Dostęp do danych za pomocą ADO.NET (C++/CLI)

ADO.NET to interfejs API programu .NET Framework umożliwiający dostęp do danych i zapewnia możliwości i łatwość użycia niezgodnych przez poprzednie rozwiązania dostępu do danych. W tej sekcji opisano niektóre problemy związane z ADO.NET unikatowymi dla użytkowników języka Visual C++, takimi jak przeprowadzanie marshalingu typów natywnych.

ADO.NET działa w środowisku uruchomieniowym języka wspólnego (CLR). W związku z tym każda aplikacja, która wchodzi w interakcję z ADO.NET, musi być również skierowana do środowiska CLR. Nie oznacza to jednak, że aplikacje natywne nie mogą używać ADO.NET. W tych przykładach pokazano, jak korzystać z ADO.NET bazy danych z kodu natywnego.

Przeprowadzanie marshalingu ciągów ANSI dla ADO.NET

Pokazuje, jak dodać ciąg macierzysty (char *) do bazy danych i jak przeprowadzić marshaling System.String z bazy danych do ciągu natywnego.

Przykład

W tym przykładzie klasa DatabaseClass jest tworzona w celu interakcji z obiektem ADO.NET DataTable . Należy pamiętać, że ta klasa jest natywnym językiem C++ class (w porównaniu z klasą ref class lub value class). Jest to konieczne, ponieważ chcemy użyć tej klasy z kodu natywnego i nie można używać typów zarządzanych w kodzie natywnym. Ta klasa zostanie skompilowana w celu kierowania środowiska CLR, zgodnie z dyrektywą #pragma managed poprzedzającą deklarację klasy. Aby uzyskać więcej informacji na temat tej dyrektywy, zobacz managed, unmanaged (Zarządzanie niezarządzane).

Zanotuj prywatny element członkowski klasy DatabaseClass: gcroot<DataTable ^> table. Ponieważ typy natywne nie mogą zawierać typów zarządzanych, gcroot słowo kluczowe jest niezbędne. Aby uzyskać więcej informacji na temat gcrootprogramu , zobacz Instrukcje: deklarowanie dojść w typach natywnych.

Pozostała część kodu w tym przykładzie jest natywnym kodem języka C++, jak wskazano w poprzedniej #pragma unmanagedmaindyrektywie . W tym przykładzie tworzysz nowe wystąpienie klasy DatabaseClass i wywołujemy jego metody tworzenia tabeli i wypełniamy niektóre wiersze w tabeli. Należy pamiętać, że natywne ciągi języka C++ są przekazywane jako wartości dla kolumny Bazy danych StringCol. Wewnątrz klasy DatabaseClass te ciągi są marshalowane do zarządzanych ciągów przy użyciu funkcji marshalingu znalezionej System.Runtime.InteropServices w przestrzeni nazw. W szczególności metoda PtrToStringAnsi służy do marshalingu char * elementu do Stringklasy , a metoda StringToHGlobalAnsi służy do marshalingu String elementu do klasy char *.

Uwaga

Pamięć przydzielona przez StringToHGlobalAnsi program musi zostać cofnięto przydział przez wywołanie metody FreeHGlobal lub 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.

Kompilowanie kodu

  • Aby skompilować kod z wiersza polecenia, zapisz przykładowy kod w pliku o nazwie adonet_marshal_string_native.cpp i wprowadź następującą instrukcję:

    cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_string_native.cpp
    

Przeprowadzanie marshalingu ciągów BSTR dla ADO.NET

Demonstruje sposób dodawania ciągu COM (BSTR) do bazy danych i sposobu marshalingu z System.String bazy danych do elementu BSTR.

Przykład

W tym przykładzie klasa DatabaseClass jest tworzona w celu interakcji z obiektem ADO.NET DataTable . Należy pamiętać, że ta klasa jest natywnym językiem C++ class (w porównaniu z klasą ref class lub value class). Jest to konieczne, ponieważ chcemy użyć tej klasy z kodu natywnego i nie można używać typów zarządzanych w kodzie natywnym. Ta klasa zostanie skompilowana w celu kierowania środowiska CLR, zgodnie z dyrektywą #pragma managed poprzedzającą deklarację klasy. Aby uzyskać więcej informacji na temat tej dyrektywy, zobacz managed, unmanaged (Zarządzanie niezarządzane).

Zanotuj prywatny element członkowski klasy DatabaseClass: gcroot<DataTable ^> table. Ponieważ typy natywne nie mogą zawierać typów zarządzanych, gcroot słowo kluczowe jest niezbędne. Aby uzyskać więcej informacji na temat gcrootprogramu , zobacz Instrukcje: deklarowanie dojść w typach natywnych.

Pozostała część kodu w tym przykładzie jest natywnym kodem języka C++, jak wskazano w poprzedniej #pragma unmanagedmaindyrektywie . W tym przykładzie tworzysz nowe wystąpienie klasy DatabaseClass i wywołujemy jego metody tworzenia tabeli i wypełniamy niektóre wiersze w tabeli. Pamiętaj, że ciągi COM są przekazywane jako wartości dla kolumny bazy danych StringCol. Wewnątrz klasy DatabaseClass te ciągi są marshalowane do zarządzanych ciągów przy użyciu funkcji marshalingu znalezionej System.Runtime.InteropServices w przestrzeni nazw. W szczególności metoda PtrToStringBSTR służy do marshalingu BSTR elementu do Stringklasy , a metoda StringToBSTR służy do marshalingu String elementu do klasy BSTR.

Uwaga

Pamięć przydzielona przez StringToBSTR program musi zostać cofnięto przydział przez wywołanie metody FreeBSTR lub 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.

Kompilowanie kodu

  • Aby skompilować kod z wiersza polecenia, zapisz przykładowy kod w pliku o nazwie adonet_marshal_string_native.cpp i wprowadź następującą instrukcję:

    cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_string_native.cpp
    

Przeprowadzanie marshalingu ciągów Unicode dla ADO.NET

Pokazuje, jak dodać natywny ciąg Unicode (wchar_t *) do bazy danych i jak przeprowadzić marshaling System.String z bazy danych do natywnego ciągu Unicode.

Przykład

W tym przykładzie klasa DatabaseClass jest tworzona w celu interakcji z obiektem ADO.NET DataTable . Należy pamiętać, że ta klasa jest natywnym językiem C++ class (w porównaniu z klasą ref class lub value class). Jest to konieczne, ponieważ chcemy użyć tej klasy z kodu natywnego i nie można używać typów zarządzanych w kodzie natywnym. Ta klasa zostanie skompilowana w celu kierowania środowiska CLR, zgodnie z dyrektywą #pragma managed poprzedzającą deklarację klasy. Aby uzyskać więcej informacji na temat tej dyrektywy, zobacz managed, unmanaged (Zarządzanie niezarządzane).

Zanotuj prywatny element członkowski klasy DatabaseClass: gcroot<DataTable ^> table. Ponieważ typy natywne nie mogą zawierać typów zarządzanych, gcroot słowo kluczowe jest niezbędne. Aby uzyskać więcej informacji na temat gcrootprogramu , zobacz Instrukcje: deklarowanie dojść w typach natywnych.

Pozostała część kodu w tym przykładzie jest natywnym kodem języka C++, jak wskazano w poprzedniej #pragma unmanagedmaindyrektywie . W tym przykładzie tworzysz nowe wystąpienie klasy DatabaseClass i wywołujemy jego metody tworzenia tabeli i wypełniamy niektóre wiersze w tabeli. Pamiętaj, że ciągi Unicode C++ są przekazywane jako wartości dla kolumny bazy danych StringCol. Wewnątrz klasy DatabaseClass te ciągi są marshalowane do zarządzanych ciągów przy użyciu funkcji marshalingu znalezionej System.Runtime.InteropServices w przestrzeni nazw. W szczególności metoda PtrToStringUni służy do marshalingu wchar_t * elementu do Stringklasy , a metoda StringToHGlobalUni służy do marshalingu String elementu do klasy wchar_t *.

Uwaga

Pamięć przydzielona przez StringToHGlobalUni program musi zostać cofnięto przydział przez wywołanie metody FreeHGlobal lub 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.

Kompilowanie kodu

  • Aby skompilować kod z wiersza polecenia, zapisz przykładowy kod w pliku o nazwie adonet_marshal_string_wide.cpp i wprowadź następującą instrukcję:

    cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_string_wide.cpp
    

Przeprowadzanie marshalingu WARIANTu dla ADO.NET

Demonstruje sposób dodawania natywnego VARIANT elementu do bazy danych i sposobu marshalingu elementu System.Object z bazy danych do natywnego VARIANTelementu .

Przykład

W tym przykładzie klasa DatabaseClass jest tworzona w celu interakcji z obiektem ADO.NET DataTable . Należy pamiętać, że ta klasa jest natywnym językiem C++ class (w porównaniu z klasą ref class lub value class). Jest to konieczne, ponieważ chcemy użyć tej klasy z kodu natywnego i nie można używać typów zarządzanych w kodzie natywnym. Ta klasa zostanie skompilowana w celu kierowania środowiska CLR, zgodnie z dyrektywą #pragma managed poprzedzającą deklarację klasy. Aby uzyskać więcej informacji na temat tej dyrektywy, zobacz managed, unmanaged (Zarządzanie niezarządzane).

Zanotuj prywatny element członkowski klasy DatabaseClass: gcroot<DataTable ^> table. Ponieważ typy natywne nie mogą zawierać typów zarządzanych, gcroot słowo kluczowe jest niezbędne. Aby uzyskać więcej informacji na temat gcrootprogramu , zobacz Instrukcje: deklarowanie dojść w typach natywnych.

Pozostała część kodu w tym przykładzie jest natywnym kodem języka C++, jak wskazano w poprzedniej #pragma unmanagedmaindyrektywie . W tym przykładzie tworzysz nowe wystąpienie klasy DatabaseClass i wywołujemy jego metody tworzenia tabeli i wypełniamy niektóre wiersze w tabeli. Należy pamiętać, że typy natywne VARIANT są przekazywane jako wartości dla kolumny Database ObjectCol. Wewnątrz klasy DatabaseClass te VARIANT typy są marshalowane do obiektów zarządzanych przy użyciu funkcji marshalingu znalezionej System.Runtime.InteropServices w przestrzeni nazw. W szczególności metoda GetObjectForNativeVariant służy do marshalingu VARIANT elementu do Objectklasy , a metoda GetNativeVariantForObject służy do marshalingu Object elementu do klasy 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

Kompilowanie kodu

  • Aby skompilować kod z wiersza polecenia, zapisz przykładowy kod w pliku o nazwie adonet_marshal_variant.cpp i wprowadź następującą instrukcję:

    cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_variant.cpp
    

Marshaling a SAFEARRAY for ADO.NET

Pokazuje, jak dodać macierz natywną SAFEARRAY do bazy danych i jak przeprowadzić marshaling tablicy zarządzanej z bazy danych do natywnej SAFEARRAY.

Przykład

W tym przykładzie klasa DatabaseClass jest tworzona w celu interakcji z obiektem ADO.NET DataTable . Należy pamiętać, że ta klasa jest natywnym językiem C++ class (w porównaniu z klasą ref class lub value class). Jest to konieczne, ponieważ chcemy użyć tej klasy z kodu natywnego i nie można używać typów zarządzanych w kodzie natywnym. Ta klasa zostanie skompilowana w celu kierowania środowiska CLR, zgodnie z dyrektywą #pragma managed poprzedzającą deklarację klasy. Aby uzyskać więcej informacji na temat tej dyrektywy, zobacz managed, unmanaged (Zarządzanie niezarządzane).

Zanotuj prywatny element członkowski klasy DatabaseClass: gcroot<DataTable ^> table. Ponieważ typy natywne nie mogą zawierać typów zarządzanych, gcroot słowo kluczowe jest niezbędne. Aby uzyskać więcej informacji na temat gcrootprogramu , zobacz Instrukcje: deklarowanie dojść w typach natywnych.

Pozostała część kodu w tym przykładzie jest natywnym kodem języka C++, jak wskazano w poprzedniej #pragma unmanagedmaindyrektywie . W tym przykładzie tworzysz nowe wystąpienie klasy DatabaseClass i wywołujemy jego metody tworzenia tabeli i wypełniamy niektóre wiersze w tabeli. Należy pamiętać, że typy natywne SAFEARRAY są przekazywane jako wartości dla kolumny bazy danych ArrayIntsCol. Wewnątrz klasy DatabaseClass te SAFEARRAY typy są marshalowane do obiektów zarządzanych przy użyciu funkcji marshalingu znalezionej System.Runtime.InteropServices w przestrzeni nazw. W szczególności metoda Copy służy do marshalingu SAFEARRAY klasy do zarządzanej tablicy liczb całkowitych, a metoda Copy służy do marshalingu zarządzanej tablicy liczb całkowitych do klasy 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

Kompilowanie kodu

  • Aby skompilować kod z wiersza polecenia, zapisz przykładowy kod w pliku o nazwie adonet_marshal_safearray.cpp i wprowadź następującą instrukcję:

    cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_safearray.cpp
    

Zabezpieczenia.NET Framework

Aby uzyskać informacje na temat problemów z zabezpieczeniami związanych z ADO.NET, zobacz Zabezpieczanie aplikacji ADO.NET.

Sekcja opis
ADO.NET Zawiera omówienie ADO.NET, zestawu klas, które uwidaczniają usługi dostępu do danych programistom platformy .NET.

Zobacz też

Programowanie .NET w języku C++/interfejsie wiersza polecenia (Visual C++)

Współdziałanie natywne i .NET

System.Runtime.InteropServices

Współdziałanie