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
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 native SAFEARRAY types are being passed as values for the database column ArrayIntsCol. Inside DatabaseClass, these SAFEARRAY types are marshaled to managed objects using the marshaling functionality found in the System.Runtime.InteropServices namespace. Specifically, the method Copy is used to marshal a SAFEARRAY to a managed array of integers, and the method Copy is used to marshal a managed array of integers to a SAFEARRAY.
// adonet_marshal_safearray.cpp// compile with: /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll#include
#using
#define MAXCOLS 100
#pragma managedclass 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 *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
return len;}
private:// Using gcroot, you can use a managed type in// a native class.gcroot
#pragma unmanagedint 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 < j =" 0;">