Demonstrates how to add a native SAFEARRAY to a database and how to marshal a managed array from a database to a native SAFEARRAY.
Example
In this example, the class DatabaseClass is created to interact with an ADO.NET #pragma managed
directive preceding the class declaration. For more information on this directive, see
Note the private member of the DatabaseClass class: gcroot<DataTable ^> 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 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
В | Copy Code |
---|---|
// adonet_marshal_safearray.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(SAFEARRAY *arrayIntsColValue) { // Add a row to the table. DataRow ^row = table->NewRow(); int len = arrayIntsColValue->rgsabound[0].cElements; array<int> ^arr = gcnew array<int>(len); 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<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 array // of Int32s to a SAFEARRAY of type VT_I4. values[i] = SafeArrayCreateVector(VT_I4, 0, 10); int *pData; SafeArrayAccessData(values[i], (void **)&pData); Marshal::Copy((array<int> ^)rows[i][columnStr], 0, IntPtr(pData), 10); SafeArrayUnaccessData(values[i]); } 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(); // 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 < len; i++) { int *pData; SafeArrayAccessData(values[i], (void **)&pData); for (int j = 0; j < 10; j++) { cout << pData[j] << " "; } cout << endl; SafeArrayUnaccessData(values[i]); // Deallocate the memory allocated using // SafeArrayCreateVector. SafeArrayDestroy(values[i]); } SafeArrayDestroy(psa); delete db; return 0; } |
Output
В | |
---|---|
0 1 2 3 4 5 6 7 8 9 |
Compiling the Code
-
To compile the code from the command line, save the code example in a file named adonet_marshal_safearray.cpp and enter the following statement:
В Copy Code cl /clr /FU System.dll /FU System.Data.dll /FU System.Xml.dll adonet_marshal_safearray.cpp
Security
For information on security issues involving ADO.NET, see
See Also
Reference
Other Resources
Data Access Using ADO.NET in C++Native and .NET Interoperability