Accès aux données à l'aide d'ADO.NET (C++/CLI)

ADO.NET est l’API .NET Framework pour l’accès aux données et fournit de la puissance et de la facilité d’utilisation sans correspondance par les solutions d’accès aux données précédentes. Cette section décrit certains des problèmes impliquant des ADO.NET propres aux utilisateurs Visual C++, tels que le marshaling de types natifs.

ADO.NET s’exécute sous Common Language Runtime (CLR). Par conséquent, toute application qui interagit avec ADO.NET doit également cibler le CLR. Toutefois, cela ne signifie pas que les applications natives ne peuvent pas utiliser ADO.NET. Ces exemples montrent comment interagir avec une base de données ADO.NET à partir du code natif.

Marshaler des chaînes ANSI pour ADO.NET

Montre comment ajouter une chaîne native (char *) à une base de données et comment marshaler une System.String base de données vers une chaîne native.

Exemple

Dans cet exemple, la classe DatabaseClass est créée pour interagir avec un objet ADO.NET DataTable . Notez que cette classe est un C++ class natif (par rapport à un ref class ou value class). Cela est nécessaire, car nous voulons utiliser cette classe à partir du code natif et vous ne pouvez pas utiliser de types managés dans du code natif. Cette classe sera compilée pour cibler le CLR, comme indiqué par la #pragma managed directive précédant la déclaration de classe. Pour plus d’informations sur cette directive, consultez managed, unmanaged.

Notez le membre privé de la classe DatabaseClass : gcroot<DataTable ^> table. Étant donné que les types natifs ne peuvent pas contenir de types managés, l’mot clé gcroot est nécessaire. Pour plus d’informations sur gcroot, consultez Comment : déclarer des handles dans des types natifs.

Le reste du code de cet exemple est du code C++ natif, comme indiqué par la #pragma unmanaged directive précédente main. Dans cet exemple, nous créons une nouvelle instance de DatabaseClass et nous appelons ses méthodes pour créer une table et remplir certaines lignes de la table. Notez que les chaînes C++ natives sont passées en tant que valeurs pour la colonne de base de données StringCol. Dans DatabaseClass, ces chaînes sont marshalées en chaînes managées à l’aide de la fonctionnalité de marshaling trouvée dans l’espace System.Runtime.InteropServices de noms. Plus précisément, la méthode PtrToStringAnsi est utilisée pour marshaler un char * à un String, et la méthode StringToHGlobalAnsi est utilisée pour marshaler un String à un char *.

Remarque

La mémoire allouée par StringToHGlobalAnsi doit être libérée en appelant ou FreeHGlobalGlobalFree.

// 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.

Compilation du code

  • Pour compiler le code à partir de la ligne de commande, enregistrez l’exemple de code dans un fichier nommé adonet_marshal_string_native.cpp et entrez l’instruction suivante :

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

Marshaler des chaînes BSTR pour ADO.NET

Montre comment ajouter une chaîne COM (BSTR) à une base de données et comment marshaler un System.String d’une base de données à un BSTR.

Exemple

Dans cet exemple, la classe DatabaseClass est créée pour interagir avec un objet ADO.NET DataTable . Notez que cette classe est un C++ class natif (par rapport à un ref class ou value class). Cela est nécessaire, car nous voulons utiliser cette classe à partir du code natif et vous ne pouvez pas utiliser de types managés dans du code natif. Cette classe sera compilée pour cibler le CLR, comme indiqué par la #pragma managed directive précédant la déclaration de classe. Pour plus d’informations sur cette directive, consultez managed, unmanaged.

Notez le membre privé de la classe DatabaseClass : gcroot<DataTable ^> table. Étant donné que les types natifs ne peuvent pas contenir de types managés, l’mot clé gcroot est nécessaire. Pour plus d’informations sur gcroot, consultez Comment : déclarer des handles dans des types natifs.

Le reste du code de cet exemple est du code C++ natif, comme indiqué par la #pragma unmanaged directive précédente main. Dans cet exemple, nous créons une nouvelle instance de DatabaseClass et nous appelons ses méthodes pour créer une table et remplir certaines lignes de la table. Notez que les chaînes COM sont passées en tant que valeurs pour la colonne de base de données StringCol. Dans DatabaseClass, ces chaînes sont marshalées en chaînes managées à l’aide de la fonctionnalité de marshaling trouvée dans l’espace System.Runtime.InteropServices de noms. Plus précisément, la méthode PtrToStringBSTR est utilisée pour marshaler un BSTR à un String, et la méthode StringToBSTR est utilisée pour marshaler un String à un BSTR.

Remarque

La mémoire allouée par StringToBSTR doit être libérée en appelant ou FreeBSTRSysFreeString.

// 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.

Compilation du code

  • Pour compiler le code à partir de la ligne de commande, enregistrez l’exemple de code dans un fichier nommé adonet_marshal_string_native.cpp et entrez l’instruction suivante :

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

Marshaler des chaînes Unicode pour ADO.NET

Montre comment ajouter une chaîne Unicode native (wchar_t *) à une base de données et comment marshaler une System.String base de données à une chaîne Unicode native.

Exemple

Dans cet exemple, la classe DatabaseClass est créée pour interagir avec un objet ADO.NET DataTable . Notez que cette classe est un C++ class natif (par rapport à un ref class ou value class). Cela est nécessaire, car nous voulons utiliser cette classe à partir du code natif et vous ne pouvez pas utiliser de types managés dans du code natif. Cette classe sera compilée pour cibler le CLR, comme indiqué par la #pragma managed directive précédant la déclaration de classe. Pour plus d’informations sur cette directive, consultez managed, unmanaged.

Notez le membre privé de la classe DatabaseClass : gcroot<DataTable ^> table. Étant donné que les types natifs ne peuvent pas contenir de types managés, l’mot clé gcroot est nécessaire. Pour plus d’informations sur gcroot, consultez Comment : déclarer des handles dans des types natifs.

Le reste du code de cet exemple est du code C++ natif, comme indiqué par la #pragma unmanaged directive précédente main. Dans cet exemple, nous créons une nouvelle instance de DatabaseClass et nous appelons ses méthodes pour créer une table et remplir certaines lignes de la table. Notez que les chaînes Unicode C++ sont passées en tant que valeurs pour la colonne de base de données StringCol. Dans DatabaseClass, ces chaînes sont marshalées en chaînes managées à l’aide de la fonctionnalité de marshaling trouvée dans l’espace System.Runtime.InteropServices de noms. Plus précisément, la méthode PtrToStringUni est utilisée pour marshaler un wchar_t * à un String, et la méthode StringToHGlobalUni est utilisée pour marshaler un String à un wchar_t *.

Remarque

La mémoire allouée par StringToHGlobalUni doit être libérée en appelant ou FreeHGlobalGlobalFree.

// 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.

Compilation du code

  • Pour compiler le code à partir de la ligne de commande, enregistrez l’exemple de code dans un fichier nommé adonet_marshal_string_wide.cpp et entrez l’instruction suivante :

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

Marshaler un VARIANT pour ADO.NET

Montre comment ajouter un natif VARIANT à une base de données et comment marshaler une System.Object base de données d’une base de données vers une base de données native VARIANT.

Exemple

Dans cet exemple, la classe DatabaseClass est créée pour interagir avec un objet ADO.NET DataTable . Notez que cette classe est un C++ class natif (par rapport à un ref class ou value class). Cela est nécessaire, car nous voulons utiliser cette classe à partir du code natif et vous ne pouvez pas utiliser de types managés dans du code natif. Cette classe sera compilée pour cibler le CLR, comme indiqué par la #pragma managed directive précédant la déclaration de classe. Pour plus d’informations sur cette directive, consultez managed, unmanaged.

Notez le membre privé de la classe DatabaseClass : gcroot<DataTable ^> table. Étant donné que les types natifs ne peuvent pas contenir de types managés, l’mot clé gcroot est nécessaire. Pour plus d’informations sur gcroot, consultez Comment : déclarer des handles dans des types natifs.

Le reste du code de cet exemple est du code C++ natif, comme indiqué par la #pragma unmanaged directive précédente main. Dans cet exemple, nous créons une nouvelle instance de DatabaseClass et nous appelons ses méthodes pour créer une table et remplir certaines lignes de la table. Notez que les types natifs VARIANT sont passés en tant que valeurs pour la colonne de base de données ObjectCol. Dans DatabaseClass, ces VARIANT types sont marshalés en objets managés à l’aide de la fonctionnalité de marshaling trouvée dans l’espace System.Runtime.InteropServices de noms. Plus précisément, la méthode GetObjectForNativeVariant est utilisée pour marshaler un VARIANT à un Object, et la méthode GetNativeVariantForObject est utilisée pour marshaler un Object à un 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

Compilation du code

  • Pour compiler le code à partir de la ligne de commande, enregistrez l’exemple de code dans un fichier nommé adonet_marshal_variant.cpp et entrez l’instruction suivante :

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

Marshaler un SAFEARRAY pour ADO.NET

Montre comment ajouter un natif SAFEARRAY à une base de données et comment marshaler un tableau managé d’une base de données vers une base de données native SAFEARRAY.

Exemple

Dans cet exemple, la classe DatabaseClass est créée pour interagir avec un objet ADO.NET DataTable . Notez que cette classe est un C++ class natif (par rapport à un ref class ou value class). Cela est nécessaire, car nous voulons utiliser cette classe à partir du code natif et vous ne pouvez pas utiliser de types managés dans du code natif. Cette classe sera compilée pour cibler le CLR, comme indiqué par la #pragma managed directive précédant la déclaration de classe. Pour plus d’informations sur cette directive, consultez managed, unmanaged.

Notez le membre privé de la classe DatabaseClass : gcroot<DataTable ^> table. Étant donné que les types natifs ne peuvent pas contenir de types managés, l’mot clé gcroot est nécessaire. Pour plus d’informations sur gcroot, consultez Comment : déclarer des handles dans des types natifs.

Le reste du code de cet exemple est du code C++ natif, comme indiqué par la #pragma unmanaged directive précédente main. Dans cet exemple, nous créons une nouvelle instance de DatabaseClass et nous appelons ses méthodes pour créer une table et remplir certaines lignes de la table. Notez que les types natifs SAFEARRAY sont passés en tant que valeurs pour la colonne de base de données ArrayIntsCol. Dans DatabaseClass, ces SAFEARRAY types sont marshalés en objets managés à l’aide de la fonctionnalité de marshaling trouvée dans l’espace System.Runtime.InteropServices de noms. Plus précisément, la méthode Copy est utilisée pour marshaler un SAFEARRAY tableau managé d’entiers, et la méthode Copy est utilisée pour marshaler un tableau managé d’entiers à un 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

Compilation du code

  • Pour compiler le code à partir de la ligne de commande, enregistrez l’exemple de code dans un fichier nommé adonet_marshal_safearray.cpp et entrez l’instruction suivante :

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

Sécurité du .NET Framework

Pour plus d’informations sur les problèmes de sécurité impliquant ADO.NET, consultez Sécurisation des applications ADO.NET.

Section Description
ADO.NET Fournit une vue d’ensemble de ADO.NET, un ensemble de classes qui exposent les services d’accès aux données au programmeur .NET.

Voir aussi

Programmation .NET avec C++/CLI (Visual C++)

Interopérabilité native et .NET

System.Runtime.InteropServices

Interopérabilité