Delen via


Gegevenstoegang met behulp van ADO.NET (C++/CLI)

ADO.NET is de .NET Framework-API voor gegevenstoegang en biedt mogelijkheden en gebruiksgemak die niet overeenkomen met eerdere oplossingen voor gegevenstoegang. In dit gedeelte worden enkele problemen beschreven met betrekking tot ADO.NET die uniek zijn voor Visual C++-gebruikers, zoals marshaling native types.

ADO.NET wordt uitgevoerd onder Common Language Runtime (CLR). Daarom moet elke toepassing die communiceert met ADO.NET ook gericht zijn op de CLR. Dat betekent echter niet dat systeemeigen toepassingen geen gebruik kunnen maken van ADO.NET. Deze voorbeelden laten zien hoe u kunt communiceren met een ADO.NET-database vanuit systeemeigen code.

Marshal ANSI-strings voor ADO.NET

Demonstreert hoe u een systeemeigen tekenreeks (char *) toevoegt aan een database en hoe u een System.String van een database naar een systeemeigen tekenreeks kunt marshalen.

Voorbeeld

In dit voorbeeld wordt de klasse DatabaseClass gemaakt om te communiceren met een ADO.NET-object DataTable . Houd er rekening mee dat deze klasse een systeemeigen C++ class is (vergeleken met een ref class of value class). Dit is nodig omdat we deze klasse van systeemeigen code willen gebruiken en u geen beheerde typen in systeemeigen code kunt gebruiken. Deze klasse wordt gecompileerd om de CLR te bereiken, zoals wordt aangegeven door de #pragma managed richtlijn voorafgaand aan de klassedeclaratie. Zie voor meer informatie over deze richtlijn beheerde, onbeheerde.

Let op het privélid van de DatabaseClass-klasse: gcroot<DataTable ^> table. Omdat systeemeigen typen geen beheerde typen kunnen bevatten, is het gcroot trefwoord nodig. Voor meer informatie over gcroot, zie Hoe handles te declareren in native typen.

De rest van de code in dit voorbeeld is systeemeigen C++-code, zoals wordt aangegeven door de #pragma unmanaged voorgaande mainrichtlijn. In dit voorbeeld maken we een nieuw exemplaar van DatabaseClass en roepen we de bijbehorende methoden aan om een tabel te maken en enkele rijen in de tabel te vullen. Houd er rekening mee dat systeemeigen C++-tekenreeksen worden doorgegeven als waarden voor de databasekolom StringCol. In DatabaseClass worden deze tekenreeksen omgezet naar beheerde tekenreeksen via de marshaling-functionaliteit in de System.Runtime.InteropServices naamruimte. De methode PtrToStringAnsi wordt met name gebruikt om een char * te marshallen naar een String, en de methode StringToHGlobalAnsi wordt gebruikt om een String te marshallen naar een char *.

Opmerking

Het toegewezen geheugen StringToHGlobalAnsi moet ongedaan worden gemaakt door aan te roepen FreeHGlobal of 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.

De code compileren

  • Als u de code vanaf de opdrachtregel wilt compileren, slaat u het codevoorbeeld op in een bestand met de naam adonet_marshal_string_native.cpp en voert u de volgende instructie in:

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

Marshal BSTR-tekenreeksen voor ADO.NET

Demonstreert hoe u een COM-tekenreeks (BSTR) aan een database toevoegt en hoe u een System.String van een database naar een BSTR overbrengt.

Voorbeeld

In dit voorbeeld wordt de klasse DatabaseClass gemaakt om te communiceren met een ADO.NET-object DataTable . Houd er rekening mee dat deze klasse een systeemeigen C++ class is (vergeleken met een ref class of value class). Dit is nodig omdat we deze klasse van systeemeigen code willen gebruiken en u geen beheerde typen in systeemeigen code kunt gebruiken. Deze klasse wordt gecompileerd om de CLR te bereiken, zoals wordt aangegeven door de #pragma managed richtlijn voorafgaand aan de klassedeclaratie. Zie voor meer informatie over deze richtlijn beheerde, onbeheerde.

Let op het privélid van de DatabaseClass-klasse: gcroot<DataTable ^> table. Omdat systeemeigen typen geen beheerde typen kunnen bevatten, is het gcroot trefwoord nodig. Voor meer informatie over gcroot, zie Hoe handles te declareren in native typen.

De rest van de code in dit voorbeeld is systeemeigen C++-code, zoals wordt aangegeven door de #pragma unmanaged voorgaande mainrichtlijn. In dit voorbeeld maken we een nieuw exemplaar van DatabaseClass en roepen we de bijbehorende methoden aan om een tabel te maken en enkele rijen in de tabel te vullen. Com-tekenreeksen worden doorgegeven als waarden voor de databasekolom StringCol. In DatabaseClass worden deze tekenreeksen omgezet naar beheerde tekenreeksen via de marshaling-functionaliteit in de System.Runtime.InteropServices naamruimte. De methode PtrToStringBSTR wordt met name gebruikt om een BSTR te marshallen naar een String, en de methode StringToBSTR wordt gebruikt om een String te marshallen naar een BSTR.

Opmerking

Het toegewezen geheugen StringToBSTR moet ongedaan worden gemaakt door aan te roepen FreeBSTR of 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.

De code compileren

  • Als u de code vanaf de opdrachtregel wilt compileren, slaat u het codevoorbeeld op in een bestand met de naam adonet_marshal_string_native.cpp en voert u de volgende instructie in:

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

Marshal Unicode-tekenreeksen voor ADO.NET

Demonstreert hoe u een systeemeigen Unicode-tekenreeks (wchar_t *) toevoegt aan een database en hoe u een System.String uit een database omzet naar een systeemeigen Unicode-tekenreeks.

Voorbeeld

In dit voorbeeld wordt de klasse DatabaseClass gemaakt om te communiceren met een ADO.NET-object DataTable . Houd er rekening mee dat deze klasse een systeemeigen C++ class is (vergeleken met een ref class of value class). Dit is nodig omdat we deze klasse van systeemeigen code willen gebruiken en u geen beheerde typen in systeemeigen code kunt gebruiken. Deze klasse wordt gecompileerd om de CLR te bereiken, zoals wordt aangegeven door de #pragma managed richtlijn voorafgaand aan de klassedeclaratie. Zie voor meer informatie over deze richtlijn beheerde, onbeheerde.

Let op het privélid van de DatabaseClass-klasse: gcroot<DataTable ^> table. Omdat systeemeigen typen geen beheerde typen kunnen bevatten, is het gcroot trefwoord nodig. Voor meer informatie over gcroot, zie Hoe handles te declareren in native typen.

De rest van de code in dit voorbeeld is systeemeigen C++-code, zoals wordt aangegeven door de #pragma unmanaged voorgaande mainrichtlijn. In dit voorbeeld maken we een nieuw exemplaar van DatabaseClass en roepen we de bijbehorende methoden aan om een tabel te maken en enkele rijen in de tabel te vullen. Houd er rekening mee dat Unicode C++-tekenreeksen worden doorgegeven als waarden voor de databasekolom StringCol. In DatabaseClass worden deze tekenreeksen omgezet naar beheerde tekenreeksen via de marshaling-functionaliteit in de System.Runtime.InteropServices naamruimte. De methode PtrToStringUni wordt met name gebruikt om een wchar_t * te marshallen naar een String, en de methode StringToHGlobalUni wordt gebruikt om een String te marshallen naar een wchar_t *.

Opmerking

Het toegewezen geheugen StringToHGlobalUni moet ongedaan worden gemaakt door aan te roepen FreeHGlobal of 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.

De code compileren

  • Als u de code vanaf de opdrachtregel wilt compileren, slaat u het codevoorbeeld op in een bestand met de naam adonet_marshal_string_wide.cpp en voert u de volgende instructie in:

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

Marshal een VARIANT voor ADO.NET

Demonstreert hoe u een systeemeigen VARIANT aan een database toevoegt en hoe u een System.Object van een database moduleert naar een systeemeigen VARIANT.

Voorbeeld

In dit voorbeeld wordt de klasse DatabaseClass gemaakt om te communiceren met een ADO.NET-object DataTable . Houd er rekening mee dat deze klasse een systeemeigen C++ class is (vergeleken met een ref class of value class). Dit is nodig omdat we deze klasse van systeemeigen code willen gebruiken en u geen beheerde typen in systeemeigen code kunt gebruiken. Deze klasse wordt gecompileerd om de CLR te bereiken, zoals wordt aangegeven door de #pragma managed richtlijn voorafgaand aan de klassedeclaratie. Zie voor meer informatie over deze richtlijn beheerde, onbeheerde.

Let op het privélid van de DatabaseClass-klasse: gcroot<DataTable ^> table. Omdat systeemeigen typen geen beheerde typen kunnen bevatten, is het gcroot trefwoord nodig. Voor meer informatie over gcroot, zie Hoe handles te declareren in native typen.

De rest van de code in dit voorbeeld is systeemeigen C++-code, zoals wordt aangegeven door de #pragma unmanaged voorgaande mainrichtlijn. In dit voorbeeld maken we een nieuw exemplaar van DatabaseClass en roepen we de bijbehorende methoden aan om een tabel te maken en enkele rijen in de tabel te vullen. Systeemeigen VARIANT typen worden doorgegeven als waarden voor de databasekolom ObjectCol. Binnen DatabaseClass worden deze VARIANT typen omgezet naar beheerde objecten met behulp van de marshalingfunctionaliteit in de System.Runtime.InteropServices naamruimte. De methode GetObjectForNativeVariant wordt met name gebruikt om een VARIANT naar een Object te marshallen, en de methode GetNativeVariantForObject wordt gebruikt om een Object naar een VARIANT te marshallen.

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

De code compileren

  • Als u de code vanaf de opdrachtregel wilt compileren, slaat u het codevoorbeeld op in een bestand met de naam adonet_marshal_variant.cpp en voert u de volgende instructie in:

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

Marshal een SAFEARRAY voor ADO.NET

Demonstreert hoe u een systeemeigen SAFEARRAY aan een database toevoegt en hoe u een beheerde array van een database naar een systeemeigen SAFEARRAY kunt marshalen.

Voorbeeld

In dit voorbeeld wordt de klasse DatabaseClass gemaakt om te communiceren met een ADO.NET-object DataTable . Houd er rekening mee dat deze klasse een systeemeigen C++ class is (vergeleken met een ref class of value class). Dit is nodig omdat we deze klasse van systeemeigen code willen gebruiken en u geen beheerde typen in systeemeigen code kunt gebruiken. Deze klasse wordt gecompileerd om de CLR te bereiken, zoals wordt aangegeven door de #pragma managed richtlijn voorafgaand aan de klassedeclaratie. Zie voor meer informatie over deze richtlijn beheerde, onbeheerde.

Let op het privélid van de DatabaseClass-klasse: gcroot<DataTable ^> table. Omdat systeemeigen typen geen beheerde typen kunnen bevatten, is het gcroot trefwoord nodig. Voor meer informatie over gcroot, zie Hoe handles te declareren in native typen.

De rest van de code in dit voorbeeld is systeemeigen C++-code, zoals wordt aangegeven door de #pragma unmanaged voorgaande mainrichtlijn. In dit voorbeeld maken we een nieuw exemplaar van DatabaseClass en roepen we de bijbehorende methoden aan om een tabel te maken en enkele rijen in de tabel te vullen. Let op dat native SAFEARRAY typen als waarden worden doorgegeven voor de databasekolom ArrayIntsCol. Binnen DatabaseClass worden deze SAFEARRAY typen omgezet naar beheerde objecten met behulp van de marshalingfunctionaliteit in de System.Runtime.InteropServices naamruimte. De methode Copy wordt met name gebruikt om een SAFEARRAY naar een beheerde array met gehele getallen te marshalen, en de methode Copy wordt gebruikt om een beheerde array met gehele getallen te marshalen naar een 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

De code compileren

  • Als u de code vanaf de opdrachtregel wilt compileren, slaat u het codevoorbeeld op in een bestand met de naam adonet_marshal_safearray.cpp en voert u de volgende instructie in:

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

.NET Framework-beveiliging

Zie ADO.NET-toepassingen beveiligen voor informatie over beveiligingsproblemen met betrekking tot ADO.NET.

Afdeling Beschrijving
ADO.NET Biedt een overzicht van ADO.NET, een set klassen die gegevenstoegangsservices beschikbaar maken voor de .NET-programmeur.

Zie ook

.NET-programmering met C++/CLI (Visual C++)

Systeemeigen en .NET-interoperabiliteit

System.Runtime.InteropServices

Interoperabiliteit