Bagikan melalui


Akses Data Menggunakan ADO.NET (C++/CLI)

ADO.NET adalah .NET Framework API untuk akses data dan menyediakan daya dan kemudahan penggunaan yang tidak cocok dengan solusi akses data sebelumnya. Bagian ini menjelaskan beberapa masalah yang melibatkan ADO.NET yang unik untuk pengguna Visual C++, seperti marshaling jenis asli.

ADO.NET berjalan di bawah Common Language Runtime (CLR). Oleh karena itu, aplikasi apa pun yang berinteraksi dengan ADO.NET juga harus menargetkan CLR. Namun, itu tidak berarti bahwa aplikasi asli tidak dapat menggunakan ADO.NET. Contoh-contoh ini akan menunjukkan cara berinteraksi dengan database ADO.NET dari kode asli.

String ANSI Marsekal untuk ADO.NET

Menunjukkan cara menambahkan string asli (char *) ke database dan cara melakukan marshal System.String dari database ke string asli.

Contoh

Dalam contoh ini, kelas DatabaseClass dibuat untuk berinteraksi dengan objek ADO.NET DataTable . Perhatikan bahwa kelas ini adalah C++ class asli (dibandingkan dengan ref class atau value class). Ini diperlukan karena kami ingin menggunakan kelas ini dari kode asli, dan Anda tidak dapat menggunakan jenis terkelola dalam kode asli. Kelas ini akan dikompilasi untuk menargetkan CLR, seperti yang ditunjukkan oleh #pragma managed arahan sebelum deklarasi kelas. Untuk informasi selengkapnya tentang arahan ini, lihat terkelola, tidak dikelola.

Perhatikan anggota privat kelas DatabaseClass: gcroot<DataTable ^> table. Karena jenis asli tidak boleh berisi jenis terkelola gcroot , kata kunci diperlukan. Untuk informasi selengkapnya tentang gcroot, lihat Cara: Mendeklarasikan Handel dalam Jenis Asli.

Sisa kode dalam contoh ini adalah kode C++ asli, seperti yang ditunjukkan oleh direktif #pragma unmanaged sebelumnya main. Dalam contoh ini, kita membuat instans baru DatabaseClass dan memanggil metodenya untuk membuat tabel dan mengisi beberapa baris dalam tabel. Perhatikan bahwa string C++ asli sedang diteruskan sebagai nilai untuk kolom database StringCol. Di dalam DatabaseClass, string ini dinamai ke string terkelola menggunakan fungsionalitas marshaling yang ditemukan di System.Runtime.InteropServices namespace layanan. Secara khusus, metode PtrToStringAnsi ini digunakan untuk marshal a char * ke String, dan metode StringToHGlobalAnsi ini digunakan untuk marshal a String ke char *.

Catatan

Memori yang dialokasikan oleh StringToHGlobalAnsi harus dibatalkan alokasinya dengan memanggil atau 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.

Mengompilasi Kode

  • Untuk mengkompilasi kode dari baris perintah, simpan contoh kode dalam file bernama adonet_marshal_string_native.cpp dan masukkan pernyataan berikut:

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

String BSTR Marsekal untuk ADO.NET

Menunjukkan cara menambahkan string COM (BSTR) ke database dan cara melakukan marshal System.String dari database ke BSTR.

Contoh

Dalam contoh ini, kelas DatabaseClass dibuat untuk berinteraksi dengan objek ADO.NET DataTable . Perhatikan bahwa kelas ini adalah C++ class asli (dibandingkan dengan ref class atau value class). Ini diperlukan karena kami ingin menggunakan kelas ini dari kode asli, dan Anda tidak dapat menggunakan jenis terkelola dalam kode asli. Kelas ini akan dikompilasi untuk menargetkan CLR, seperti yang ditunjukkan oleh #pragma managed arahan sebelum deklarasi kelas. Untuk informasi selengkapnya tentang arahan ini, lihat terkelola, tidak dikelola.

Perhatikan anggota privat kelas DatabaseClass: gcroot<DataTable ^> table. Karena jenis asli tidak boleh berisi jenis terkelola gcroot , kata kunci diperlukan. Untuk informasi selengkapnya tentang gcroot, lihat Cara: Mendeklarasikan Handel dalam Jenis Asli.

Sisa kode dalam contoh ini adalah kode C++ asli, seperti yang ditunjukkan oleh direktif #pragma unmanaged sebelumnya main. Dalam contoh ini, kita membuat instans baru DatabaseClass dan memanggil metodenya untuk membuat tabel dan mengisi beberapa baris dalam tabel. Perhatikan bahwa string COM sedang diteruskan sebagai nilai untuk kolom database StringCol. Di dalam DatabaseClass, string ini dinamai ke string terkelola menggunakan fungsionalitas marshaling yang ditemukan di System.Runtime.InteropServices namespace layanan. Secara khusus, metode PtrToStringBSTR ini digunakan untuk marshal a BSTR ke String, dan metode StringToBSTR ini digunakan untuk marshal a String ke BSTR.

Catatan

Memori yang dialokasikan oleh StringToBSTR harus dibatalkan alokasinya dengan memanggil atau 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.

Mengompilasi Kode

  • Untuk mengkompilasi kode dari baris perintah, simpan contoh kode dalam file bernama adonet_marshal_string_native.cpp dan masukkan pernyataan berikut:

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

String Marshal Unicode untuk ADO.NET

Menunjukkan cara menambahkan string Unicode asli (wchar_t *) ke database dan cara melakukan marshal System.String dari database ke string Unicode asli.

Contoh

Dalam contoh ini, kelas DatabaseClass dibuat untuk berinteraksi dengan objek ADO.NET DataTable . Perhatikan bahwa kelas ini adalah C++ class asli (dibandingkan dengan ref class atau value class). Ini diperlukan karena kami ingin menggunakan kelas ini dari kode asli, dan Anda tidak dapat menggunakan jenis terkelola dalam kode asli. Kelas ini akan dikompilasi untuk menargetkan CLR, seperti yang ditunjukkan oleh #pragma managed arahan sebelum deklarasi kelas. Untuk informasi selengkapnya tentang arahan ini, lihat terkelola, tidak dikelola.

Perhatikan anggota privat kelas DatabaseClass: gcroot<DataTable ^> table. Karena jenis asli tidak boleh berisi jenis terkelola gcroot , kata kunci diperlukan. Untuk informasi selengkapnya tentang gcroot, lihat Cara: Mendeklarasikan Handel dalam Jenis Asli.

Sisa kode dalam contoh ini adalah kode C++ asli, seperti yang ditunjukkan oleh direktif #pragma unmanaged sebelumnya main. Dalam contoh ini, kita membuat instans baru DatabaseClass dan memanggil metodenya untuk membuat tabel dan mengisi beberapa baris dalam tabel. Perhatikan bahwa string Unicode C++ sedang diteruskan sebagai nilai untuk kolom database StringCol. Di dalam DatabaseClass, string ini dinamai ke string terkelola menggunakan fungsionalitas marshaling yang ditemukan di System.Runtime.InteropServices namespace layanan. Secara khusus, metode PtrToStringUni ini digunakan untuk marshal a wchar_t * ke String, dan metode StringToHGlobalUni ini digunakan untuk marshal a String ke wchar_t *.

Catatan

Memori yang dialokasikan oleh StringToHGlobalUni harus dibatalkan alokasinya dengan memanggil atau 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.

Mengompilasi Kode

  • Untuk mengkompilasi kode dari baris perintah, simpan contoh kode dalam file bernama adonet_marshal_string_wide.cpp dan masukkan pernyataan berikut:

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

Marsekal VARIAN untuk ADO.NET

Menunjukkan cara menambahkan asli VARIANT ke database dan cara melakukan marshal System.Object dari database ke asli VARIANT.

Contoh

Dalam contoh ini, kelas DatabaseClass dibuat untuk berinteraksi dengan objek ADO.NET DataTable . Perhatikan bahwa kelas ini adalah C++ class asli (dibandingkan dengan ref class atau value class). Ini diperlukan karena kami ingin menggunakan kelas ini dari kode asli, dan Anda tidak dapat menggunakan jenis terkelola dalam kode asli. Kelas ini akan dikompilasi untuk menargetkan CLR, seperti yang ditunjukkan oleh #pragma managed arahan sebelum deklarasi kelas. Untuk informasi selengkapnya tentang arahan ini, lihat terkelola, tidak dikelola.

Perhatikan anggota privat kelas DatabaseClass: gcroot<DataTable ^> table. Karena jenis asli tidak boleh berisi jenis terkelola gcroot , kata kunci diperlukan. Untuk informasi selengkapnya tentang gcroot, lihat Cara: Mendeklarasikan Handel dalam Jenis Asli.

Sisa kode dalam contoh ini adalah kode C++ asli, seperti yang ditunjukkan oleh direktif #pragma unmanaged sebelumnya main. Dalam contoh ini, kita membuat instans baru DatabaseClass dan memanggil metodenya untuk membuat tabel dan mengisi beberapa baris dalam tabel. Perhatikan bahwa jenis asli VARIANT sedang diteruskan sebagai nilai untuk kolom database ObjectCol. Di dalam DatabaseClass, jenis ini VARIANT dinamai ke objek terkelola menggunakan fungsionalitas marshaling yang ditemukan di System.Runtime.InteropServices namespace layanan. Secara khusus, metode GetObjectForNativeVariant ini digunakan untuk melakukan marshal VARIANT ke Object, dan metode GetNativeVariantForObject ini digunakan untuk melakukan marsekal Object ke 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

Mengompilasi Kode

  • Untuk mengkompilasi kode dari baris perintah, simpan contoh kode dalam file bernama adonet_marshal_variant.cpp dan masukkan pernyataan berikut:

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

Marsekal SAFEARRAY untuk ADO.NET

Menunjukkan cara menambahkan asli SAFEARRAY ke database dan cara melakukan marshal array terkelola dari database ke asli SAFEARRAY.

Contoh

Dalam contoh ini, kelas DatabaseClass dibuat untuk berinteraksi dengan objek ADO.NET DataTable . Perhatikan bahwa kelas ini adalah C++ class asli (dibandingkan dengan ref class atau value class). Ini diperlukan karena kami ingin menggunakan kelas ini dari kode asli, dan Anda tidak dapat menggunakan jenis terkelola dalam kode asli. Kelas ini akan dikompilasi untuk menargetkan CLR, seperti yang ditunjukkan oleh #pragma managed arahan sebelum deklarasi kelas. Untuk informasi selengkapnya tentang arahan ini, lihat terkelola, tidak dikelola.

Perhatikan anggota privat kelas DatabaseClass: gcroot<DataTable ^> table. Karena jenis asli tidak boleh berisi jenis terkelola gcroot , kata kunci diperlukan. Untuk informasi selengkapnya tentang gcroot, lihat Cara: Mendeklarasikan Handel dalam Jenis Asli.

Sisa kode dalam contoh ini adalah kode C++ asli, seperti yang ditunjukkan oleh direktif #pragma unmanaged sebelumnya main. Dalam contoh ini, kita membuat instans baru DatabaseClass dan memanggil metodenya untuk membuat tabel dan mengisi beberapa baris dalam tabel. Perhatikan bahwa jenis asli SAFEARRAY sedang diteruskan sebagai nilai untuk kolom database ArrayIntsCol. Di dalam DatabaseClass, jenis ini SAFEARRAY dinamai ke objek terkelola menggunakan fungsionalitas marshaling yang ditemukan di System.Runtime.InteropServices namespace layanan. Secara khusus, metode Copy ini digunakan untuk melakukan marshal SAFEARRAY ke array bilangan bulat terkelola, dan metode Copy ini digunakan untuk marshal array bilangan bulat terkelola ke 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

Mengompilasi Kode

  • Untuk mengkompilasi kode dari baris perintah, simpan contoh kode dalam file bernama adonet_marshal_safearray.cpp dan masukkan pernyataan berikut:

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

Keamanan .NET Framework

Untuk informasi tentang masalah keamanan yang melibatkan ADO.NET, lihat Mengamankan Aplikasi ADO.NET.

Bagian Deskripsi
ADO.NET Memberikan gambaran umum tentang ADO.NET, sekumpulan kelas yang mengekspos layanan akses data ke programmer .NET.

Lihat juga

Pemrograman .NET dengan C++/CLI (Visual C++)

Interoperabilitas Native dan .NET

System.Runtime.InteropServices

Interoperabilitas