Accesso ai dati tramite ADO.NET (C++/CLI)

ADO.NET è l'API .NET Framework per l'accesso ai dati e offre potenza e facilità d'uso non corrispondenti dalle soluzioni di accesso ai dati precedenti. Questa sezione descrive alcuni dei problemi che coinvolgono ADO.NET univoci per gli utenti di Visual C++, ad esempio il marshalling di tipi nativi.

ADO.NET viene eseguito in Common Language Runtime (CLR). Pertanto, qualsiasi applicazione che interagisce con ADO.NET deve anche avere come destinazione CLR. Tuttavia, ciò non significa che le applicazioni native non possono usare ADO.NET. Questi esempi illustrano come interagire con un database ADO.NET dal codice nativo.

Effettuare il marshalling di stringhe ANSI per ADO.NET

Viene illustrato come aggiungere una stringa nativa (char *) a un database e come effettuare il marshalling di un System.String oggetto da un database a una stringa nativa.

Esempio

In questo esempio viene creata la classe DatabaseClass per interagire con un oggetto ADO.NET DataTable . Si noti che questa classe è un linguaggio C++ class nativo (rispetto a o ref classvalue class). Ciò è necessario perché si vuole usare questa classe dal codice nativo e non è possibile usare i tipi gestiti nel codice nativo. Questa classe verrà compilata per specificare come destinazione CLR, come indicato dalla direttiva che precede la #pragma managed dichiarazione di classe. Per altre informazioni su questa direttiva, vedere managed, unmanaged.

Si noti il membro privato della classe DatabaseClass: gcroot<DataTable ^> table. Poiché i tipi nativi non possono contenere tipi gestiti, la gcroot parola chiave è necessaria. Per altre informazioni su gcroot, vedere Procedura: Dichiarare handle nei tipi nativi.

Il resto del codice in questo esempio è codice C++ nativo, come indicato dalla #pragma unmanaged direttiva precedente main. In questo esempio si crea una nuova istanza di DatabaseClass e si chiamano i relativi metodi per creare una tabella e popolare alcune righe nella tabella. Si noti che le stringhe C++ native vengono passate come valori per la colonna di database StringCol. All'interno di DatabaseClass, queste stringhe vengono sottoposto a marshalling a stringhe gestite usando la funzionalità di marshalling disponibile nello spazio dei System.Runtime.InteropServices nomi . In particolare, il metodo PtrToStringAnsi viene usato per effettuare il marshalling di un char * oggetto a un Stringoggetto e il metodo StringToHGlobalAnsi viene usato per effettuare il marshalling di un String oggetto a un oggetto char *.

Nota

La memoria allocata da StringToHGlobalAnsi deve essere deallocata chiamando FreeHGlobal o 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.

Compilazione del codice

  • Per compilare il codice dalla riga di comando, salvare l'esempio di codice in un file denominato adonet_marshal_string_native.cpp e immettere l'istruzione seguente:

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

Effettuare il marshalling di stringhe BSTR per ADO.NET

Viene illustrato come aggiungere una stringa COM (BSTR) a un database e come effettuare il marshalling di un System.String da un database a un oggetto BSTR.

Esempio

In questo esempio viene creata la classe DatabaseClass per interagire con un oggetto ADO.NET DataTable . Si noti che questa classe è un linguaggio C++ class nativo (rispetto a o ref classvalue class). Ciò è necessario perché si vuole usare questa classe dal codice nativo e non è possibile usare i tipi gestiti nel codice nativo. Questa classe verrà compilata per specificare come destinazione CLR, come indicato dalla direttiva che precede la #pragma managed dichiarazione di classe. Per altre informazioni su questa direttiva, vedere managed, unmanaged.

Si noti il membro privato della classe DatabaseClass: gcroot<DataTable ^> table. Poiché i tipi nativi non possono contenere tipi gestiti, la gcroot parola chiave è necessaria. Per altre informazioni su gcroot, vedere Procedura: Dichiarare handle nei tipi nativi.

Il resto del codice in questo esempio è codice C++ nativo, come indicato dalla #pragma unmanaged direttiva precedente main. In questo esempio si crea una nuova istanza di DatabaseClass e si chiamano i relativi metodi per creare una tabella e popolare alcune righe nella tabella. Si noti che le stringhe COM vengono passate come valori per la colonna di database StringCol. All'interno di DatabaseClass, queste stringhe vengono sottoposto a marshalling a stringhe gestite usando la funzionalità di marshalling disponibile nello spazio dei System.Runtime.InteropServices nomi . In particolare, il metodo PtrToStringBSTR viene usato per effettuare il marshalling di un BSTR oggetto a un Stringoggetto e il metodo StringToBSTR viene usato per effettuare il marshalling di un String oggetto a un oggetto BSTR.

Nota

La memoria allocata da StringToBSTR deve essere deallocata chiamando FreeBSTR o 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.

Compilazione del codice

  • Per compilare il codice dalla riga di comando, salvare l'esempio di codice in un file denominato adonet_marshal_string_native.cpp e immettere l'istruzione seguente:

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

Effettuare il marshalling di stringhe Unicode per ADO.NET

Viene illustrato come aggiungere una stringa Unicode nativa (wchar_t *) a un database e come effettuare il marshalling di un System.String oggetto da un database a una stringa Unicode nativa.

Esempio

In questo esempio viene creata la classe DatabaseClass per interagire con un oggetto ADO.NET DataTable . Si noti che questa classe è un linguaggio C++ class nativo (rispetto a o ref classvalue class). Ciò è necessario perché si vuole usare questa classe dal codice nativo e non è possibile usare i tipi gestiti nel codice nativo. Questa classe verrà compilata per specificare come destinazione CLR, come indicato dalla direttiva che precede la #pragma managed dichiarazione di classe. Per altre informazioni su questa direttiva, vedere managed, unmanaged.

Si noti il membro privato della classe DatabaseClass: gcroot<DataTable ^> table. Poiché i tipi nativi non possono contenere tipi gestiti, la gcroot parola chiave è necessaria. Per altre informazioni su gcroot, vedere Procedura: Dichiarare handle nei tipi nativi.

Il resto del codice in questo esempio è codice C++ nativo, come indicato dalla #pragma unmanaged direttiva precedente main. In questo esempio si crea una nuova istanza di DatabaseClass e si chiamano i relativi metodi per creare una tabella e popolare alcune righe nella tabella. Si noti che le stringhe C++ Unicode vengono passate come valori per la colonna di database StringCol. All'interno di DatabaseClass, queste stringhe vengono sottoposto a marshalling a stringhe gestite usando la funzionalità di marshalling disponibile nello spazio dei System.Runtime.InteropServices nomi . In particolare, il metodo PtrToStringUni viene usato per effettuare il marshalling di un wchar_t * oggetto a un Stringoggetto e il metodo StringToHGlobalUni viene usato per effettuare il marshalling di un String oggetto a un oggetto wchar_t *.

Nota

La memoria allocata da StringToHGlobalUni deve essere deallocata chiamando FreeHGlobal o 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.

Compilazione del codice

  • Per compilare il codice dalla riga di comando, salvare l'esempio di codice in un file denominato adonet_marshal_string_wide.cpp e immettere l'istruzione seguente:

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

Effettuare il marshalling di un valore VARIANT per ADO.NET

Viene illustrato come aggiungere un oggetto nativo VARIANT a un database e come effettuare il marshalling di un System.Object oggetto da un database a un oggetto nativo VARIANT.

Esempio

In questo esempio viene creata la classe DatabaseClass per interagire con un oggetto ADO.NET DataTable . Si noti che questa classe è un linguaggio C++ class nativo (rispetto a o ref classvalue class). Ciò è necessario perché si vuole usare questa classe dal codice nativo e non è possibile usare i tipi gestiti nel codice nativo. Questa classe verrà compilata per specificare come destinazione CLR, come indicato dalla direttiva che precede la #pragma managed dichiarazione di classe. Per altre informazioni su questa direttiva, vedere managed, unmanaged.

Si noti il membro privato della classe DatabaseClass: gcroot<DataTable ^> table. Poiché i tipi nativi non possono contenere tipi gestiti, la gcroot parola chiave è necessaria. Per altre informazioni su gcroot, vedere Procedura: Dichiarare handle nei tipi nativi.

Il resto del codice in questo esempio è codice C++ nativo, come indicato dalla #pragma unmanaged direttiva precedente main. In questo esempio si crea una nuova istanza di DatabaseClass e si chiamano i relativi metodi per creare una tabella e popolare alcune righe nella tabella. Si noti che i tipi nativi VARIANT vengono passati come valori per la colonna di database ObjectCol. All'interno di DatabaseClass, questi VARIANT tipi vengono sottoposto a marshalling agli oggetti gestiti usando la funzionalità di marshalling disponibile nello spazio dei System.Runtime.InteropServices nomi . In particolare, il metodo GetObjectForNativeVariant viene usato per effettuare il marshalling di un VARIANT oggetto a un Objectoggetto e il metodo GetNativeVariantForObject viene usato per effettuare il marshalling di un Object oggetto a un oggetto 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

Compilazione del codice

  • Per compilare il codice dalla riga di comando, salvare l'esempio di codice in un file denominato adonet_marshal_variant.cpp e immettere l'istruzione seguente:

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

Effettuare il marshalling di un SAFEARRAY per ADO.NET

Illustra come aggiungere un oggetto nativo SAFEARRAY a un database e come effettuare il marshalling di una matrice gestita da un database a un oggetto nativo SAFEARRAY.

Esempio

In questo esempio viene creata la classe DatabaseClass per interagire con un oggetto ADO.NET DataTable . Si noti che questa classe è un linguaggio C++ class nativo (rispetto a o ref classvalue class). Ciò è necessario perché si vuole usare questa classe dal codice nativo e non è possibile usare i tipi gestiti nel codice nativo. Questa classe verrà compilata per specificare come destinazione CLR, come indicato dalla direttiva che precede la #pragma managed dichiarazione di classe. Per altre informazioni su questa direttiva, vedere managed, unmanaged.

Si noti il membro privato della classe DatabaseClass: gcroot<DataTable ^> table. Poiché i tipi nativi non possono contenere tipi gestiti, la gcroot parola chiave è necessaria. Per altre informazioni su gcroot, vedere Procedura: Dichiarare handle nei tipi nativi.

Il resto del codice in questo esempio è codice C++ nativo, come indicato dalla #pragma unmanaged direttiva precedente main. In questo esempio si crea una nuova istanza di DatabaseClass e si chiamano i relativi metodi per creare una tabella e popolare alcune righe nella tabella. Si noti che i tipi nativi SAFEARRAY vengono passati come valori per la colonna di database ArrayIntsCol. All'interno di DatabaseClass, questi SAFEARRAY tipi vengono sottoposto a marshalling agli oggetti gestiti usando la funzionalità di marshalling disponibile nello spazio dei System.Runtime.InteropServices nomi . In particolare, il metodo Copy viene usato per effettuare il marshalling di un SAFEARRAY oggetto a una matrice gestita di numeri interi e il metodo Copy viene usato per effettuare il marshalling di una matrice gestita di interi a un oggetto 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

Compilazione del codice

  • Per compilare il codice dalla riga di comando, salvare l'esempio di codice in un file denominato adonet_marshal_safearray.cpp e immettere l'istruzione seguente:

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

Sicurezza di .NET Framework

Per informazioni sui problemi di sicurezza relativi alle ADO.NET, vedere Protezione delle applicazioni ADO.NET.

Sezione Descrizione
ADO.NET Fornisce una panoramica delle ADO.NET, un set di classi che espongono i servizi di accesso ai dati al programmatore .NET.

Vedi anche

Programmazione .NET con C++/CLI (Visual C++)

Interoperabilità .NET e nativa

System.Runtime.InteropServices

Interoperabilità