ADO.NET을 사용하여 데이터 액세스(C++/CLI)

ADO.NET 데이터 액세스를 위한 .NET Framework API이며 이전 데이터 액세스 솔루션에서 타의 추종을 불허하는 강력한 사용 편의성을 제공합니다. 이 섹션에서는 네이티브 형식 마샬링과 같이 Visual C++ 사용자에게 고유한 ADO.NET 관련된 몇 가지 문제에 대해 설명합니다.

ADO.NET CLR(공용 언어 런타임)에서 실행됩니다. 따라서 ADO.NET 상호 작용하는 모든 애플리케이션도 CLR을 대상으로 해야 합니다. 그러나 네이티브 애플리케이션이 ADO.NET 사용할 수 없다는 의미는 아닙니다. 다음 예제에서는 네이티브 코드에서 ADO.NET 데이터베이스와 상호 작용하는 방법을 보여 줍니다.

ADO.NET 대한 ANSI 문자열 마샬링

데이터베이스에 네이티브 문자열(char *)을 추가하는 방법과 데이터베이스에서 네이 System.String 티브 문자열로 마샬링하는 방법을 보여 줍니다.

예시

이 예제에서는 ADO.NET DataTable 개체와 상호 작용하기 위해 DatabaseClass 클래스를 만듭니다. 이 클래스는 네이티브 C++ class (또는 value class비교)ref class입니다. 네이티브 코드에서 이 클래스를 사용하려고 하며 네이티브 코드에서 관리되는 형식을 사용할 수 없기 때문에 이 작업이 필요합니다. 이 클래스는 클래스 선언 앞의 지시문에 표시된 대로 CLR을 #pragma managed 대상으로 컴파일됩니다. 이 지시문에 대한 자세한 내용은 관리되는 비관리형을 참조하세요.

DatabaseClass 클래스의 프라이빗 멤버를 확인합니다 gcroot<DataTable ^> table. 네이티브 형식은 관리되는 형식을 gcroot 포함할 수 없으므로 키워드(keyword) 필요합니다. 자세한 gcroot내용은 방법: 네이티브 형식에서 핸들 선언을 참조 하세요.

이 예제의 나머지 코드는 앞main의 지시문에 #pragma unmanaged 표시된 대로 네이티브 C++ 코드입니다. 이 예제에서는 DatabaseClass의 새 인스턴스를 만들고 해당 메서드를 호출하여 테이블을 만들고 테이블의 일부 행을 채웁니다. 네이티브 C++ 문자열은 데이터베이스 열 StringCol에 대한 값으로 전달됩니다. DatabaseClass 내에서 이러한 문자열은 네임스페이스에 있는 마샬링 기능을 사용하여 관리되는 문자열로 System.Runtime.InteropServices 마샬링됩니다. 특히 메서드 PtrToStringAnsi 는 a를 마샬링 char * 하는 String데 사용되며 StringToHGlobalAnsi 메서드는 에 마샬링 String 하는 char *데 사용됩니다.

참고 항목

할당된 StringToHGlobalAnsi 메모리 중 하나 FreeHGlobal 또는 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.

코드 컴파일

  • 명령줄에서 코드를 컴파일하려면 adonet_marshal_string_native.cpp라는 파일에 코드 예제를 저장하고 다음 문을 입력합니다.

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

ADO.NET 대한 BSTR 문자열 마샬링

데이터베이스에 COM 문자열(BSTR)을 추가하는 방법과 데이터베이스에서 로 마샬링 System.String 하는 BSTR방법을 보여 줍니다.

예시

이 예제에서는 ADO.NET DataTable 개체와 상호 작용하기 위해 DatabaseClass 클래스를 만듭니다. 이 클래스는 네이티브 C++ class (또는 value class비교)ref class입니다. 네이티브 코드에서 이 클래스를 사용하려고 하며 네이티브 코드에서 관리되는 형식을 사용할 수 없기 때문에 이 작업이 필요합니다. 이 클래스는 클래스 선언 앞의 지시문에 표시된 대로 CLR을 #pragma managed 대상으로 컴파일됩니다. 이 지시문에 대한 자세한 내용은 관리되는 비관리형을 참조하세요.

DatabaseClass 클래스의 프라이빗 멤버를 확인합니다 gcroot<DataTable ^> table. 네이티브 형식은 관리되는 형식을 gcroot 포함할 수 없으므로 키워드(keyword) 필요합니다. 자세한 gcroot내용은 방법: 네이티브 형식에서 핸들 선언을 참조 하세요.

이 예제의 나머지 코드는 앞main의 지시문에 #pragma unmanaged 표시된 대로 네이티브 C++ 코드입니다. 이 예제에서는 DatabaseClass의 새 인스턴스를 만들고 해당 메서드를 호출하여 테이블을 만들고 테이블의 일부 행을 채웁니다. COM 문자열은 데이터베이스 열 StringCol에 대한 값으로 전달됩니다. DatabaseClass 내에서 이러한 문자열은 네임스페이스에 있는 마샬링 기능을 사용하여 관리되는 문자열로 System.Runtime.InteropServices 마샬링됩니다. 특히 메서드 PtrToStringBSTR 는 a를 마샬링 BSTR 하는 String데 사용되며 StringToBSTR 메서드는 에 마샬링 String 하는 BSTR데 사용됩니다.

참고 항목

할당된 StringToBSTR 메모리 중 하나 FreeBSTR 또는 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.

코드 컴파일

  • 명령줄에서 코드를 컴파일하려면 adonet_marshal_string_native.cpp라는 파일에 코드 예제를 저장하고 다음 문을 입력합니다.

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

ADO.NET 유니코드 문자열 마샬링

데이터베이스에 네이티브 유니코드 문자열(wchar_t *)을 추가하는 방법과 데이터베이스에서 네이 System.String 티브 유니코드 문자열로 마샬링하는 방법을 보여 줍니다.

예시

이 예제에서는 ADO.NET DataTable 개체와 상호 작용하기 위해 DatabaseClass 클래스를 만듭니다. 이 클래스는 네이티브 C++ class (또는 value class비교)ref class입니다. 네이티브 코드에서 이 클래스를 사용하려고 하며 네이티브 코드에서 관리되는 형식을 사용할 수 없기 때문에 이 작업이 필요합니다. 이 클래스는 클래스 선언 앞의 지시문에 표시된 대로 CLR을 #pragma managed 대상으로 컴파일됩니다. 이 지시문에 대한 자세한 내용은 관리되는 비관리형을 참조하세요.

DatabaseClass 클래스의 프라이빗 멤버를 확인합니다 gcroot<DataTable ^> table. 네이티브 형식은 관리되는 형식을 gcroot 포함할 수 없으므로 키워드(keyword) 필요합니다. 자세한 gcroot내용은 방법: 네이티브 형식에서 핸들 선언을 참조 하세요.

이 예제의 나머지 코드는 앞main의 지시문에 #pragma unmanaged 표시된 대로 네이티브 C++ 코드입니다. 이 예제에서는 DatabaseClass의 새 인스턴스를 만들고 해당 메서드를 호출하여 테이블을 만들고 테이블의 일부 행을 채웁니다. 유니코드 C++ 문자열은 데이터베이스 열 StringCol에 대한 값으로 전달됩니다. DatabaseClass 내에서 이러한 문자열은 네임스페이스에 있는 마샬링 기능을 사용하여 관리되는 문자열로 System.Runtime.InteropServices 마샬링됩니다. 특히 메서드 PtrToStringUni 는 a를 마샬링 wchar_t * 하는 String데 사용되며 StringToHGlobalUni 메서드는 에 마샬링 String 하는 wchar_t *데 사용됩니다.

참고 항목

할당된 StringToHGlobalUni 메모리 중 하나 FreeHGlobal 또는 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.

코드 컴파일

  • 명령줄에서 코드를 컴파일하려면 코드 예제를 adonet_marshal_string_wide.cpp 파일에 저장하고 다음 문을 입력합니다.

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

ADO.NET 대한 VARIANT 마샬링

데이터베이스에 네이티브를 추가하는 방법과 데이터베이스에서 네이 System.Object 티브 VARIANTVARIANT로 마샬링하는 방법을 보여 줍니다.

예시

이 예제에서는 ADO.NET DataTable 개체와 상호 작용하기 위해 DatabaseClass 클래스를 만듭니다. 이 클래스는 네이티브 C++ class (또는 value class비교)ref class입니다. 네이티브 코드에서 이 클래스를 사용하려고 하며 네이티브 코드에서 관리되는 형식을 사용할 수 없기 때문에 이 작업이 필요합니다. 이 클래스는 클래스 선언 앞의 지시문에 표시된 대로 CLR을 #pragma managed 대상으로 컴파일됩니다. 이 지시문에 대한 자세한 내용은 관리되는 비관리형을 참조하세요.

DatabaseClass 클래스의 프라이빗 멤버를 확인합니다 gcroot<DataTable ^> table. 네이티브 형식은 관리되는 형식을 gcroot 포함할 수 없으므로 키워드(keyword) 필요합니다. 자세한 gcroot내용은 방법: 네이티브 형식에서 핸들 선언을 참조 하세요.

이 예제의 나머지 코드는 앞main의 지시문에 #pragma unmanaged 표시된 대로 네이티브 C++ 코드입니다. 이 예제에서는 DatabaseClass의 새 인스턴스를 만들고 해당 메서드를 호출하여 테이블을 만들고 테이블의 일부 행을 채웁니다. 네이티브 VARIANT 형식은 데이터베이스 열 ObjectCol에 대한 값으로 전달됩니다. DatabaseClass 내에서 이러한 VARIANT 형식은 네임스페이스에 있는 마샬링 기능을 사용하여 관리되는 개체로 System.Runtime.InteropServices 마샬링됩니다. 특히 메서드 GetObjectForNativeVariant 는 에 마샬링 VARIANT 하는 Object데 사용되며 GetNativeVariantForObject 메서드는 에 마샬링하는 ObjectVARIANT데 사용됩니다.

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

코드 컴파일

  • 명령줄에서 코드를 컴파일하려면 코드 예제를 adonet_marshal_variant.cpp 파일에 저장하고 다음 문을 입력합니다.

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

ADO.NET SAFEARRAY 마샬링

데이터베이스에 네이티브 SAFEARRAY 를 추가하는 방법과 관리되는 배열을 데이터베이스에서 네이티브 SAFEARRAY로 마샬링하는 방법을 보여 줍니다.

예시

이 예제에서는 ADO.NET DataTable 개체와 상호 작용하기 위해 DatabaseClass 클래스를 만듭니다. 이 클래스는 네이티브 C++ class (또는 value class비교)ref class입니다. 네이티브 코드에서 이 클래스를 사용하려고 하며 네이티브 코드에서 관리되는 형식을 사용할 수 없기 때문에 이 작업이 필요합니다. 이 클래스는 클래스 선언 앞의 지시문에 표시된 대로 CLR을 #pragma managed 대상으로 컴파일됩니다. 이 지시문에 대한 자세한 내용은 관리되는 비관리형을 참조하세요.

DatabaseClass 클래스의 프라이빗 멤버를 확인합니다 gcroot<DataTable ^> table. 네이티브 형식은 관리되는 형식을 gcroot 포함할 수 없으므로 키워드(keyword) 필요합니다. 자세한 gcroot내용은 방법: 네이티브 형식에서 핸들 선언을 참조 하세요.

이 예제의 나머지 코드는 앞main의 지시문에 #pragma unmanaged 표시된 대로 네이티브 C++ 코드입니다. 이 예제에서는 DatabaseClass의 새 인스턴스를 만들고 해당 메서드를 호출하여 테이블을 만들고 테이블의 일부 행을 채웁니다. 네이티브 SAFEARRAY 형식은 데이터베이스 열 ArrayIntsCol에 대한 값으로 전달됩니다. DatabaseClass 내에서 이러한 SAFEARRAY 형식은 네임스페이스에 있는 마샬링 기능을 사용하여 관리되는 개체로 System.Runtime.InteropServices 마샬링됩니다. 특히 이 메서드 Copy 는 관리되는 정수 배열로 마샬링 SAFEARRAY 하는 데 사용되며, 이 메서드 Copy 는 정수의 관리되는 배열을 마샬링하는 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

코드 컴파일

  • 명령줄에서 코드를 컴파일하려면 코드 예제를 adonet_marshal_safearray.cpp 파일에 저장하고 다음 문을 입력합니다.

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

.NET Framework 보안

ADO.NET 관련된 보안 문제에 대한 자세한 내용은 ADO.NET 애플리케이션 보안을 참조 하세요.

섹션 설명
ADO.NET .NET 프로그래머에 데이터 액세스 서비스를 노출하는 클래스 집합인 ADO.NET 대한 개요를 제공합니다.

참고 항목

C++/CLI를 사용한 .NET 프로그래밍 (Visual C++)

네이티브 및 .NET 상호 운용성

System.Runtime.InteropServices

상호 운용성