Ben_N_Athens

I have code that needs to marshal a two dimensional array of doubles to unmanaged code.

I have been working with an example from the MSDN that demonstrates marshalling a one-dimensional array.

http://msdn2.microsoft.com/en-us/library/9b1fy41s(VS.80).aspx

When I try to follow the example and pass a pointer to the two dimensional array, the unmanaged code only sees the first dimension. I think I can marshal these arrays if I use the right syntax, but because I am somewhat of a C++ noob, I am not quite getting it right. My dump of the pointer to the 2-d array, xmatrix, only shows numbers from the first dimension of the array.

The code is posted below. If you try this, simply create a C# class that creates a GSLMultiLinRegression object.

Can someone please help me with the syntax of passing a two dimensional array from managed C++ to unmanaged C++.

Thanks,

Ben

////////////Managed C#////////////////

GSLMultiLinRegression mlr = new GSLMultiLinRegression();
mlr.setXMatrix(indepArray,79,8); //I have a two dimensional array of
mlr.setYVector(predictedArray);
mlr.doMultiLinRegression();

Console.WriteLine("");
Console.WriteLine("Done Processing");
Console.ReadLine();
//////////////////////////////////////////////////

///////////Managed/Unmanaged C++//////////////////////////
#include "stdafx.h"
#include "gsl/gsl_multifit.h"
#include <time.h>
#using <System.dll>

// wrap_native_class_for_mgd_consumption.cpp
// compile with: /clr /LD
#include <windows.h>
#include <vcclr.h>

#include <stdio.h>
#using <System.dll>

using namespace System;

#pragma unmanaged
//a column of depenedent variable values
struct DepdendantVariableColumn{
double* col_values;
};

void computeMLRBestFit(double* xmatrix, double*yvector,double* coeffs,
double* cov, double* chisq,int matrix_length,int matrix_width){
gsl_matrix *X,*covmat;
gsl_vector *Y,*c;

X = gsl_matrix_alloc(matrix_length,matrix_width);
Y = gsl_vector_alloc(matrix_length);
c = gsl_vector_alloc(matrix_length);
covmat = gsl_matrix_alloc(matrix_length,matrix_width);
int i = 0;
int j = 0;

printf("Printing out dep array\n");
for (i =0; i < matrix_length;i++){
gsl_vector_set(Y,i,yvectorIdea);
printf("%d = %g\n",i,yvectorIdea);
}



for (i = 0; i < matrix_width;i++){
for (j= 0; j < matrix_length;j++){
gsl_matrix_set(X,i,j,xmatrix[i,j]);
printf("%d,%d = %g\n",i,j, xmatrix[i,j]);
}
}


}
#pragma managed
public ref class GSLMultiLinRegression{
//here's my logic. All I have to do is marshall arrays between the managed worlds
//and the unmanaged world. I will keep all the data local the managed class,
//shuffle the data over to the unmanaged class to do the computation,
//then keep the results back in the managed class.

public:
void doMultiLinRegression(){
pin_ptr<double> pp_xm = &XMatrix[0,0];
//pin_ptr<DepdendantVariableColumn> pp_dvc = &DepVarCols[0];
pin_ptr<double> pp_yv = &YVector[0];
Coeffs = gcnew array<double,1>(matrix_length); //just re-initialize the array
pin_ptr<double> pp_cf = &Coeffs[0];
Covs = gcnew array<double,2>(matrix_width,matrix_length);
pin_ptr<double> pp_cs = &chisq;
computeMLRBestFit(pp_xm,pp_yv,pp_cf,pp_cf,pp_cs,matrix_length,matrix_width);

//computeMLRBestFit(pp_dvc,pp_yv,pp_cf,pp_cf,chisq,matrix_length,matrix_width);
}
array<double,1>^ getCoeffs(){
return Coeffs;
}
void setXMatrix(array<double,2>^ xmatrix,int numObs, int numParams){
//XMatrix = xmatrix;
//initialize an array of dependentvarcolumns the size of numParams.
//loop over each column and value and load the dependentvar columns.
//store each "column" -- a double array -- in the double array property of the
//dependantvarcolumn. store the depvarcol objects in an array.

matrix_length = numObs;
matrix_width = numParams;
//XMatrix = gcnew array<double>(2);
XMatrix = xmatrix;

}
void setYVector(array<double,1>^ yvector){
YVector = yvector;
}
private:
array<double,2>^ XMatrix;
array<double,1>^ YVector;
array<double,1>^ Coeffs;
array<double,2>^ Covs;
int matrix_length; //note that vector lenght will be the same as matrix length;
int matrix_width;
double chisq;
};



Re: Visual C++ Language Marshall Multidimensional Array Using C++ Interop

Ramkrishna Pawar

Reading that much of code is real pain, can you tell us what kind of array is it Is it by any chance managed type






Re: Visual C++ Language Marshall Multidimensional Array Using C++ Interop

Rick Edwards

"I have code that needs to marshal a two dimensional array of doubles to unmanaged code."

Clue's in the question, don't have to read the code. I have exactly the same problem to solve here so any advice gratefully received.

Rick Edwards





Re: Visual C++ Language Marshall Multidimensional Array Using C++ Interop

Viorel.

If you have a 2-d array created like this:

array< double, 2 > ^ ar = gcnew array< double, 2 >(width, height);

then obtain a pin_ptr and pass it to unmanaged function, together with the width:

pin_ptr< double > p = &ar[ 0, 0 ];

MyUnmanagedFunction(p, width);

Inside unmanaged function, access elements using a special expression, like this:

void MyUnmanagedFunction(double * ar, int width)

{

int a = 10; // first index

int b = 20; // second index

double value = ar[width * a + b];

}

I hope this makes sense.





Re: Visual C++ Language Marshall Multidimensional Array Using C++ Interop

Rick Edwards

Hmm thanks for that, not sure it's what I'm after, I don't want to have to refactor any legacy code to accept a 2D array from a .NET control. I'm actually trying to create a class to act as a negotiator between managed and unmanaged code. We have used this for dealing with one dimensional arrays:

Code Block

ArDouble::ArDouble(void)

{

Set(1, true);

}

ArDouble::~ArDouble(void)

{

delete [] m_gcAr;

delete [] m_Ar;

}

bool ArDouble::Set(int nMax, bool bForce)

{

if(false == bForce && nMax <= m_Max) return false;

m_Max = nMax;

m_gcAr = gcnew array(m_Max);

delete [] m_Ar;

m_Ar = new double[m_Max];

return true;

}

void ArDouble::CopyFromGC(double **par, int nSize)

{

*par = m_Ar;

IntPtr ptr( *par );

Marshal::Copy( m_gcAr, 0, ptr, nSize );

}

void ArDouble::CopyToGC(double *ar, int nSize)

{

IntPtr ptr( ar );

Marshal::Copy( ptr, m_gcAr, 0, nSize );

}

Note that I didn't write this! Now I'm a complete and utter newbie at C++ (in fact this is my first bit of code I've had to deal with) so I was thinking I could create something similar for a two dimensional array:

Code Block

// constructor, takes the dimensions of the 2D array to convert

MArDouble::MArDouble(int size1, int size2)

{

m_Size1 = size1;

m_Size2 = size2;

Set();

}

// destructor

MArDouble::~MArDouble(void)

{

delete [] m_gcMAr;

delete [] m_MAr;

}

bool MArDouble::Set(void)

{

// create new managed 2D array

m_gcMAr = gcnew array<double,2>(m_Size1, m_Size2);

// create new unmanaged 2D array

delete [] m_MAr;

m_MAr = new double * [m_Size1];

for(int i=0; i < m_Size1; ++i)

{

m_MAr[i] = new double[m_Size2];

}

return true;

}

void MArDouble::CopyFromGC(double **par, int nSize1, int nSize2) { }

void MArDouble::CopyToGC(double *ar, int nSize1, int nSize2) { }

So in order to implement the CopyFromGC and CopyToGC methods I was looking into whether you can use Marshall:Copy on a two dimensional array which was pretty much the original question to this thread.

Rick Edwards

(p.s. yeah I know this isn't the best way to create a 2D array and I know it isn't the best way to destroy one but I don't want to get into that :-)





Re: Visual C++ Language Marshall Multidimensional Array Using C++ Interop

Viorel.

I think you can consider the same Marshal::Copy function, but instead of nCount use nSize1 * nSize2. Before this, allocate the unmanaged array using a single new statement: new double [nSize1 * nSize2].





Re: Visual C++ Language Marshall Multidimensional Array Using C++ Interop

Rick Edwards

Sorry I'm not sure I follow, can you provide an example of the Marshal::Copy method signature that you are using as there is no overloaded method that appears to allow me to define nSize1 * nSize2 as the array length I think I'm missing the point here somewhere.

Thanks in advance

Rick Edwards





Re: Visual C++ Language Marshall Multidimensional Array Using C++ Interop

Viorel.

Define the unmanaged member like this:

double * m_MAr;

In Set function, allocate it like this:

m_MAr = new double [m_Size1 * m_Size2];

The first copy operation will look like this:

Marshal::Copy( m_gcAr, 0, ptr, m_Size1 * m_Size2 );

The second copy operation will look like this:

Marshal::Copy( ptr, m_gcAr, 0, m_Size1 * m_Size2 );





Re: Visual C++ Language Marshall Multidimensional Array Using C++ Interop

Rick Edwards

Hmm all I get is:

Error 1 error C2665: 'System::Runtime::InteropServices::Marshal::Copy' : none of the 16 overloads could convert all the argument types

Am I missing something

Code Block

// constructor, takes the dimensions of the 2D array to convert

MArDouble::MArDouble(int size1, int size2)

{

m_Size1 = size1;

m_Size2 = size2;

Set();

}

// destructor

MArDouble::~MArDouble(void)

{

delete [] m_gcMAr;

delete [] m_MAr;

}

bool MArDouble::Set(void)

{

// create new managed 2D array

m_gcMAr = gcnew array<double,2>(m_Size1, m_Size2);

// create new unmanaged 2D array

delete [] m_MAr;

m_MAr = new double [m_Size1 * m_Size2];

return true;

}

void MArDouble::CopyFromGC(double **par)

{

IntPtr ptr( *par );

Marshal::Copy( m_gcMAr, 0, ptr, m_Size1 * m_Size2 );

}

void MArDouble::CopyToGC(double *ar)

{

IntPtr ptr( ar );

Marshal::Copy( ptr, m_gcMAr, 0, m_Size1 * m_Size2 );

}