Share via


Comment : marshaler des chaînes BSTR pour ADO.NET

Mise à jour : novembre 2007

Montre comment ajouter une chaîne COM (BSTR) à une base de données et comment marshaler une System.String d'une base de données vers un BSTR.

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 managed, unmanaged.

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 COM 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 PtrToStringBSTR est utilisée pour marshaler un BSTR vers une String et la méthode StringToBSTR est utilisée pour marshaler une String vers un BSTR.

Remarque :

La mémoire allouée par StringToBSTR doit être libérée en appelant FreeBSTR ou 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.

Compilation du code

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

    cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_string_native.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 en C++

ADO.NET

Interopérabilité

Interopérabilité native et .NET