Partager via


Comment : marshaler des chaînes Unicode pour ADO.NET (C++/CLI)

Montre comment ajouter une chaîne Unicode native (wchar_t *) à une base de données et comment marshaler une String d'une base de données en une chaîne Unicode native.

Exemple

Dans cet exemple, la classe DatabaseClass est créée pour interagir avec un objet DataTable ADO.NET. Notez que cette classe est une class C++ native (comparée à une ref class ou value class). Cela est nécessaire, car nous souhaitons utiliser cette classe à partir de code natif et il est impossible d'utiliser des types managés en code natif. Cette classe sera compilée pour cibler le CLR, comme indiqué par la directive #pragma managed précédant la déclaration de classe. Pour plus d'informations sur cette directive, consultez managé, non managé.

Notez le membre privé de la classe DatabaseClass : gcroot<DataTable ^> table. Les types natifs ne pouvant pas contenir de types managés, le mot clé gcroot est nécessaire. Pour plus d'informations sur gcroot, consultez Comment : déclarer des handles dans les types natifs.

Le reste du code dans cet exemple est du code C++ natif, comme indiqué par la directive #pragma unmanaged précédant main. Dans cet exemple, nous créons une nouvelle instance de DatabaseClass et appelons ses méthodes pour créer une table et remplir quelques lignes dans la table. Notez que les chaînes Unicode C++ sont passées en tant que valeurs pour la colonne de base de données StringCol. Au sein de DatabaseClass, ces chaînes sont marshalées vers des chaînes managées à l'aide des fonctionnalités de marshaling trouvées dans l'espace de noms System.Runtime.InteropServices. En particulier, la méthode PtrToStringUni est utilisée pour marshaler un wchar_t * vers une String et la méthode StringToHGlobalUni est utilisée pour marshaler une String vers un wchar_t *.

Notes

La mémoire allouée par StringToHGlobalUni doit être libérée en appelant FreeHGlobal ou 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;
}
  

Compilation du code

  • Pour compiler le code depuis la ligne de commande, enregistrez l'exemple de code dans un fichier nommé adonet_marshal_string_wide.cpp et saisissez l'instruction suivante :

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

Sécurité

Pour plus d'informations sur les problèmes de sécurité impliquant ADO.NET, consultez Sécurisation des applications ADO.NET.

Voir aussi

Référence

System.Runtime.InteropServices

Autres ressources

Accès aux données à l'aide d'ADO.NET (C++/CLI)

ADO.NET

Interopérabilité

Interopérabilité native et .NET