Freigeben über


Gewusst wie: Marshallen von Unicode-Zeichenfolgen für ADO.NET

Aktualisiert: November 2007

Veranschaulicht das Hinzufügen einer systemeigenen Unicode-Zeichenfolge (wchar_t *) zu einer Datenbank und das Marshallen einer System.String aus einer Datenbank in eine systemeigene Unicode-Zeichenfolge.

Beispiel

In diesem Beispiel wird die Klasse DatabaseClass erstellt, die mit einem ADO.NET-DataTable-Objekt interagiert. Beachten Sie, dass diese Klasse eine systemeigene C++-class ist (im Vergleich zu einer ref class oder einer value class). Dies ist notwendig, weil diese Klasse von systemeigenem Code aus verwendet werden soll und verwaltete Typen in systemeigenem Code nicht verwendet werden können. Diese Klasse wird für die CLR kompiliert. Dies wird durch die der Klassendeklaration vorausgehende #pragma managed-Direktive angezeigt. Weitere Informationen über diese Direktive finden Sie unter managed, unmanaged.

Beachten Sie den privaten Member der DatabaseClass-Klasse: gcroot<DataTable ^> table. Da systemeigene Typen keine verwalteten Typen enthalten können, ist das gcroot-Schlüsselwort erforderlich. Weitere Informationen zu gcroot finden Sie unter Gewusst wie: Deklarieren von Handles in systemeigenen Typen.

Bei dem übrigen Code in diesem Beispiel handelt es sich um systemeigenen C++-Code, was durch die #pragma unmanaged-Direktive vor main angezeigt wird. In diesem Beispiel wird eine neue Instanz von DatabaseClass erstellt und ihre Methoden aufgerufen, um eine Tabelle zu erstellen und einige Zeilen darin zu füllen. Beachten Sie, dass Unicode-C++-Zeichenfolgen als Werte für die Datenbankspalte StringCol übergeben werden. Innerhalb der DatabaseClass werden diese Zeichenfolgen mit der Marshalling-Funktionalität des System.Runtime.InteropServices-Namespaces in verwaltete Zeichenfolgen gemarshallt. Dabei wird die Methode PtrToStringUni zum Marshallen einer wchar_t * in eine String und die Methode StringToHGlobalUni zum Marshallen einer String in eine wchar_t * verwendet.

Hinweis:

Der durch StringToHGlobalUni reservierte Arbeitsspeicher muss durch Aufrufen von FreeHGlobal oder GlobalFree freigegeben werden.

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

Kompilieren des Codes

  • Um den Code über die Kommandozeile zu kompilieren, speichern Sie das Codebeispiel in einer Datei mit dem Namen adonet_marshal_string_wide.cpp, und geben Sie die folgende Anweisung ein:

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

Sicherheit

Informationen zu Sicherheitsaspekten bezüglich ADO.NET finden Sie unter Sichern von ADO.NET-Anwendungen.

Siehe auch

Referenz

System.Runtime.InteropServices

Weitere Ressourcen

Datenzugriff mit ADO.NET in C++

ADO.NET

Interoperabilität

Interoperabilität von systemeigenem Code und .NET