How to: Marshal BSTR Strings for ADO.NET

Demonstrates how to add a COM string (BSTR) to a database and how to marshal a System.String from a database to a BSTR.
ExampleIn this example, the class DatabaseClass is created to interact with an ADO.NET DataTable object. Note that this class is a native C++ class (as compared to a ref class or value class). This is necessary because we want to use this class from native code, and you cannot use managed types in native code. This class will be compiled to target the CLR, as is indicated by the #pragma managed directive preceding the class declaration. For more information on this directive, see managed, unmanaged.
Note the private member of the DatabaseClass class: gcroot table. Since native types cannot contain managed types, the gcroot keyword is necessary. For more information on gcroot, see How to: Declare Handles in Native Types.
The rest of the code in this example is native C++ code, as is indicated by the #pragma unmanaged directive preceding main. In this example, we are creating a new instance of DatabaseClass and calling its methods to create a table and populate some rows in the table. Note that COM strings are being passed as values for the database column StringCol. Inside DatabaseClass, these strings are marshaled to managed strings using the marshaling functionality found in the System.Runtime.InteropServices namespace. Specifically, the method PtrToStringBSTR is used to marshal a BSTR to a String, and the method StringToBSTR is used to marshal a String to a BSTR.
Note The memory allocated by StringToBSTR must be deallocated by calling either FreeBSTR or SysFreeString.// adonet_marshal_string_bstr.cpp// compile with: /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll#include #include #include using namespace std;
#using using namespace System;using namespace System::Data;using namespace System::Runtime::InteropServices;
#define MAXCOLS 100
#pragma managedclass 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 ^rows = table->Select();int len = rows->Length;len = (len > valuesLength) ? valuesLength : len;for (int i = 0; i <> table;};
#pragma unmanagedint 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 <>