Dela via


Dataåtkomst med hjälp av ADO.NET (C++/CLI)

ADO.NET är .NET Framework-API:et för dataåtkomst och ger energi och användarvänlighet som inte matchas av tidigare dataåtkomstlösningar. I det här avsnittet beskrivs några av de problem som rör ADO.NET som är unika för Visual C++-användare, till exempel att konvertera interna typer.

ADO.NET körs under COMMON Language Runtime (CLR). Därför måste alla program som interagerar med ADO.NET även rikta in sig på CLR. Det innebär dock inte att interna program inte kan använda ADO.NET. De här exemplen visar hur du interagerar med en ADO.NET databas från inbyggd kod.

Hantering av ANSI-strängar för ADO.NET

Visar hur du lägger till en intern sträng (char *) i en databas och hur du konverterar en System.String från en databas till en intern sträng.

Exempel

I det här exemplet skapas klassen DatabaseClass för att interagera med ett ADO.NET DataTable objekt. Observera att den här klassen är en intern C++ class (jämfört med en ref class eller value class). Detta är nödvändigt eftersom vi vill använda den här klassen från inbyggd kod och du inte kan använda hanterade typer i inbyggd kod. Den här klassen kompileras för att rikta in sig på CLR, vilket anges i #pragma managed direktivet före klassdeklarationen. Mer information om det här direktivet finns i Hanterad, ohanterad.

Observera den privata medlemmen i klassen DatabaseClass: gcroot<DataTable ^> table. Eftersom interna typer inte kan innehålla hanterade typer är nyckelordet gcroot nödvändigt. Mer information om gcrootfinns i How to: Declare Handles in Native Types (Deklarera handtag i inbyggda typer).

Resten av koden i det här exemplet är inbyggd C++-kod, vilket anges i #pragma unmanaged direktivet före main. I det här exemplet skapar vi en ny instans av DatabaseClass och anropar dess metoder för att skapa en tabell och fylla i några rader i tabellen. Observera att interna C++-strängar skickas som värden för databaskolumnen StringCol. I DatabaseClass konverteras dessa strängar till hanterade strängar med hjälp av de marshaling-funktioner som finns i System.Runtime.InteropServices namnområdet. Mer specifikt används metoden PtrToStringAnsi för att konvertera en char * till en String, och metoden StringToHGlobalAnsi används för att konvertera en String till en char *.

Anmärkning

Det minne som allokeras av StringToHGlobalAnsi måste frigöras genom att anropa antingen FreeHGlobal eller 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.

Kompilera koden

  • Om du vill kompilera koden från kommandoraden sparar du kodexemplet i en fil med namnet adonet_marshal_string_native.cpp och anger följande instruktion:

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

Hantera BSTR-strängar för ADO.NET

Visar hur du lägger till en COM-sträng (BSTR) i en databas och hur du konverterar en System.String från en databas till en BSTR.

Exempel

I det här exemplet skapas klassen DatabaseClass för att interagera med ett ADO.NET DataTable objekt. Observera att den här klassen är en intern C++ class (jämfört med en ref class eller value class). Detta är nödvändigt eftersom vi vill använda den här klassen från inbyggd kod och du inte kan använda hanterade typer i inbyggd kod. Den här klassen kompileras för att rikta in sig på CLR, vilket anges i #pragma managed direktivet före klassdeklarationen. Mer information om det här direktivet finns i Hanterad, ohanterad.

Observera den privata medlemmen i klassen DatabaseClass: gcroot<DataTable ^> table. Eftersom interna typer inte kan innehålla hanterade typer är nyckelordet gcroot nödvändigt. Mer information om gcrootfinns i How to: Declare Handles in Native Types (Deklarera handtag i inbyggda typer).

Resten av koden i det här exemplet är inbyggd C++-kod, vilket anges i #pragma unmanaged direktivet före main. I det här exemplet skapar vi en ny instans av DatabaseClass och anropar dess metoder för att skapa en tabell och fylla i några rader i tabellen. Observera att COM-strängar skickas som värden för databaskolumnen StringCol. I DatabaseClass konverteras dessa strängar till hanterade strängar med hjälp av de marshaling-funktioner som finns i System.Runtime.InteropServices namnområdet. Mer specifikt används metoden PtrToStringBSTR för att konvertera en BSTR till en String, och metoden StringToBSTR används för att konvertera en String till en BSTR.

Anmärkning

Det minne som allokeras av StringToBSTR måste frigöras genom att anropa antingen FreeBSTR eller 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.

Kompilera koden

  • Om du vill kompilera koden från kommandoraden sparar du kodexemplet i en fil med namnet adonet_marshal_string_native.cpp och anger följande instruktion:

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

Marshal Unicode-strängar för ADO.NET

Visar hur du lägger till en intern Unicode-sträng (wchar_t *) i en databas och hur du konverterar en System.String från en databas till en intern Unicode-sträng.

Exempel

I det här exemplet skapas klassen DatabaseClass för att interagera med ett ADO.NET DataTable objekt. Observera att den här klassen är en intern C++ class (jämfört med en ref class eller value class). Detta är nödvändigt eftersom vi vill använda den här klassen från inbyggd kod och du inte kan använda hanterade typer i inbyggd kod. Den här klassen kompileras för att rikta in sig på CLR, vilket anges i #pragma managed direktivet före klassdeklarationen. Mer information om det här direktivet finns i Hanterad, ohanterad.

Observera den privata medlemmen i klassen DatabaseClass: gcroot<DataTable ^> table. Eftersom interna typer inte kan innehålla hanterade typer är nyckelordet gcroot nödvändigt. Mer information om gcrootfinns i How to: Declare Handles in Native Types (Deklarera handtag i inbyggda typer).

Resten av koden i det här exemplet är inbyggd C++-kod, vilket anges i #pragma unmanaged direktivet före main. I det här exemplet skapar vi en ny instans av DatabaseClass och anropar dess metoder för att skapa en tabell och fylla i några rader i tabellen. Observera att Unicode C++-strängar skickas som värden för databaskolumnen StringCol. I DatabaseClass konverteras dessa strängar till hanterade strängar med hjälp av de marshaling-funktioner som finns i System.Runtime.InteropServices namnområdet. Mer specifikt används metoden PtrToStringUni för att konvertera en wchar_t * till en String, och metoden StringToHGlobalUni används för att konvertera en String till en wchar_t *.

Anmärkning

Det minne som allokeras av StringToHGlobalUni måste frigöras genom att anropa antingen FreeHGlobal eller 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.

Kompilera koden

  • Om du vill kompilera koden från kommandoraden sparar du kodexemplet i en fil med namnet adonet_marshal_string_wide.cpp och anger följande instruktion:

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

Samordna en VARIANT för ADO.NET

Visar hur du lägger till en intern VARIANT i en databas och hur du konverterar en System.Object från en databas till en intern VARIANT.

Exempel

I det här exemplet skapas klassen DatabaseClass för att interagera med ett ADO.NET DataTable objekt. Observera att den här klassen är en intern C++ class (jämfört med en ref class eller value class). Detta är nödvändigt eftersom vi vill använda den här klassen från inbyggd kod och du inte kan använda hanterade typer i inbyggd kod. Den här klassen kompileras för att rikta in sig på CLR, vilket anges i #pragma managed direktivet före klassdeklarationen. Mer information om det här direktivet finns i Hanterad, ohanterad.

Observera den privata medlemmen i klassen DatabaseClass: gcroot<DataTable ^> table. Eftersom interna typer inte kan innehålla hanterade typer är nyckelordet gcroot nödvändigt. Mer information om gcrootfinns i How to: Declare Handles in Native Types (Deklarera handtag i inbyggda typer).

Resten av koden i det här exemplet är inbyggd C++-kod, vilket anges i #pragma unmanaged direktivet före main. I det här exemplet skapar vi en ny instans av DatabaseClass och anropar dess metoder för att skapa en tabell och fylla i några rader i tabellen. Observera att interna VARIANT typer skickas som värden för databaskolumnen ObjectCol. I DatabaseClass konverteras dessa VARIANT typer till hanterade objekt med hjälp av de marshaling-funktioner som finns i System.Runtime.InteropServices namnområdet. Mer specifikt används metoden GetObjectForNativeVariant för att konvertera en VARIANT till en Object, och metoden GetNativeVariantForObject används för att konvertera en Object till en 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

Kompilera koden

  • Om du vill kompilera koden från kommandoraden sparar du kodexemplet i en fil med namnet adonet_marshal_variant.cpp och anger följande instruktion:

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

Ordna en SAFEARRAY för ADO.NET

Visar hur du lägger till en intern SAFEARRAY till en databas och hur du konverterar en hanterad matris från en databas till en intern SAFEARRAY.

Exempel

I det här exemplet skapas klassen DatabaseClass för att interagera med ett ADO.NET DataTable objekt. Observera att den här klassen är en intern C++ class (jämfört med en ref class eller value class). Detta är nödvändigt eftersom vi vill använda den här klassen från inbyggd kod och du inte kan använda hanterade typer i inbyggd kod. Den här klassen kompileras för att rikta in sig på CLR, vilket anges i #pragma managed direktivet före klassdeklarationen. Mer information om det här direktivet finns i Hanterad, ohanterad.

Observera den privata medlemmen i klassen DatabaseClass: gcroot<DataTable ^> table. Eftersom interna typer inte kan innehålla hanterade typer är nyckelordet gcroot nödvändigt. Mer information om gcrootfinns i How to: Declare Handles in Native Types (Deklarera handtag i inbyggda typer).

Resten av koden i det här exemplet är inbyggd C++-kod, vilket anges i #pragma unmanaged direktivet före main. I det här exemplet skapar vi en ny instans av DatabaseClass och anropar dess metoder för att skapa en tabell och fylla i några rader i tabellen. Observera att interna SAFEARRAY typer skickas som värden för databaskolumnen ArrayIntsCol. I DatabaseClass konverteras dessa SAFEARRAY typer till hanterade objekt med hjälp av de marshaling-funktioner som finns i System.Runtime.InteropServices namnområdet. Mer specifikt används metoden Copy för att konvertera en SAFEARRAY till en hanterad matris med heltal och metoden Copy används för att konvertera en hanterad matris med heltal till en 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

Kompilera koden

  • Om du vill kompilera koden från kommandoraden sparar du kodexemplet i en fil med namnet adonet_marshal_safearray.cpp och anger följande instruktion:

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

.NET Framework-säkerhet

Information om säkerhetsproblem som rör ADO.NET finns i Skydda ADO.NET-program.

Sektion Beskrivning
ADO.NET Ger en översikt över ADO.NET, en uppsättning klasser som exponerar dataåtkomsttjänster för .NET-programmeraren.

Se även

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

Native och .NET-interoperabilitet

System.Runtime.InteropServices

Samverkan