Bagikan melalui


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

ADO.NET adalah API dari .NET Framework untuk mengakses data dan menyediakan kekuatan serta kemudahan penggunaan yang tanpa banding dibandingkan solusi akses data sebelumnya. Bagian ini menjelaskan beberapa masalah yang melibatkan ADO.NET, yang khusus untuk pengguna Visual C++, seperti pengaturan tipe 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.

Pengelolaan String ANSI untuk ADO.NET

Menunjukkan cara menambahkan string asli (char *) ke database dan cara mengonversi 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 tipe asli tidak dapat mengandung tipe terkelola, kata kunci gcroot diperlukan. Untuk informasi selengkapnya tentang gcroot, lihat Cara: Mendeklarasikan Handle 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 dikonversi ke string terkelola menggunakan fungsi marshaling yang ditemukan di namespace System.Runtime.InteropServices. 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 dibebaskan dengan memanggil baik FreeHGlobal atau 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.

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
    

Pengelolaan String BSTR 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 tipe asli tidak dapat mengandung tipe terkelola, kata kunci gcroot diperlukan. Untuk informasi selengkapnya tentang gcroot, lihat Cara: Mendeklarasikan Handle 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 dikonversi ke string terkelola menggunakan fungsi marshaling yang ditemukan di namespace System.Runtime.InteropServices. 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 dibebaskan dengan memanggil baik FreeBSTR atau 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.

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
    

Pengelolaan String Unicode untuk ADO.NET

Menunjukkan cara menambahkan string Unicode asli (wchar_t *) ke dalam database dan cara mentransfer data 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 dapat berisi jenis terkelola, kata kunci gcroot diperlukan. Untuk informasi selengkapnya tentang gcroot, lihat Cara: Mendeklarasikan Handle dalam Tipe Native.

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 dikonversi ke string terkelola menggunakan fungsi marshaling yang ditemukan di namespace System.Runtime.InteropServices. 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 dibebaskan dengan memanggil baik FreeHGlobal atau 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.

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
    

Memproses VARIANT untuk ADO.NET

Menunjukkan cara menambahkan VARIANT bawaan ke database dan cara mengonversi System.Object dari database ke VARIANT bawaan.

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 direktif 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 dapat berisi jenis terkelola, kata kunci gcroot diperlukan. Untuk informasi selengkapnya tentang gcroot, lihat Cara: Mendeklarasikan Handle dalam Tipe Native.

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 diarahkan ke objek terkelola menggunakan fungsionalitas marshaling yang ditemukan di namespace System.Runtime.InteropServices. Secara khusus, metode GetObjectForNativeVariant digunakan untuk mengarahkan VARIANT ke Object, dan metode GetNativeVariantForObject digunakan untuk mengarahkan 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
    

Mengatur SAFEARRAY untuk ADO.NET

Menunjukkan cara menambahkan komponen native SAFEARRAY ke database dan cara memindahkan array terkelola dari database ke komponen native 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 tipe asli tidak dapat mengandung tipe terkelola, kata kunci gcroot diperlukan. Untuk informasi selengkapnya tentang gcroot, lihat Cara: Mendeklarasikan Handle 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 diarahkan ke objek terkelola menggunakan fungsionalitas marshaling yang ditemukan di namespace System.Runtime.InteropServices. Secara khusus, metode Copy digunakan untuk melakukan pengubahan SAFEARRAY menjadi array bilangan bulat yang terkelola, dan metode Copy digunakan untuk mengubah array bilangan bulat yang terkelola menjadi 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