Share via


Como: realizar realizar marshaling um SAFEARRAY para o ADO.NET

Demonstra como adicionar um nativo SAFEARRAY para um banco de dados e como realizar realizar marshaling um gerenciado array de um banco de dados para um nativo SAFEARRAY.

Exemplo

Neste exemplo, a classe DatabaseClass é criada para interagir com um ADO.NET DataTable objeto. Observe que este clsistema autônomos é um C++ nativo class (sistema autônomo em comparação com um ref class ou value class). Isso é necessário porque queremos usar essa classe de código nativo e não é possível usar tipos gerenciado em código nativo.Este clsistema autônomos será ser compilado para direcionar o CLR sistema autônomo é indicado pelo #pragma managed diretiva antecedendo a declaração clsistema autônomos. Para obter mais informações sobre essa diretiva, consulte gerenciado, não gerenciado.

Observe o membro particular da classe DatabaseClass: gcroot<DataTable ^> table.Como tipos nativo não podem conter tipos gerenciado, a gcroot palavra-chave é necessária. Para obter mais informações sobre gcroot, consulte: Como: Declarar Handles em tipos nativo.

O restante do código no exemplo é o código C++ nativo, conforme indicado pelo #pragma unmanaged diretiva anterior main. Neste exemplo, estamos criando uma nova instância de DatabaseClass e chamando seus métodos para criar uma tabela e popular algumas linhas da tabela.Observe que nativo SAFEARRAY tipos estão sendo passados sistema autônomo valores da coluna do banco de dados ArrayIntsCol. DatabaseClass Inside, esses SAFEARRAY tipos são empacotados para objetos gerenciado usando a funcionalidade de marshaling encontrada na System.Runtime.InteropServices espaço para nome. Especificamente, o método Copy usado para realizar realizar marshaling uma SAFEARRAY a uma matriz de inteiros e o método gerenciada Copy é usado para realizar realizar marshaling uma matriz gerenciada de inteiros para um 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 

Compilando o código

  • Para compilar o código a partir da linha de comando, salvar o exemplo de código em um arquivo chamado adonet_marshal_safearray.cpp e insira a demonstrativo a seguir:

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

Segurança

Para obter informações sobre questões de segurança envolvendo o ADO.NET, consulte Protegendo aplicativos do ADO.NET.

Consulte também

Referência

System.Runtime.InteropServices

Outros recursos

Acesso de dados usando ADO.NET em C++

ADO.NET

Interoperabilidade

Nativo e interoperabilidade .NET