I have a class in managed C++ that has all its member variables initialized inside the constructor. The member of interest is an array. I am calling it from the .cs file of a C# project, having linked the two projects with the dll of the first one. However, the function says that one or more of the parameters are incorrect and therefore, cannot be used successfully.
The class declaration and the function declaration is as follows. Both are in the .h file.
Now, I would like to call the function in the .cs file as follows:
var Driver = new Driver();
long status = Driver.Config2("CAN0", 8, Driver.AttrIdList, Driver.AttrValueList);
Console.WriteLine(status);
If the function Config executes correctly, it should output a 0. However, I am getting a negative number and upon the lookup with the table provided by the vendor, it states that one or more of the parameters are not setup correctly. I have no idea how to get past this point since I'm a newbie to managed C++. All help would be greatly appreciated. Thanks.
The code declaration is as follows:
public ref class Driver
{
public:
NCTYPE_STATUS Status;
NCTYPE_OBJH TxHandle;
MY_NCTYPE_CAN_FRAME Transmit;
array<NCTYPE_UINT32>^ AttrIdList;
array<NCTYPE_UINT32>^ AttrValueList;
array<char>^ Data;
NCTYPE_UINT32 Baudrate;
public:
Driver()
{
Baudrate = 1000000;
TxHandle = 0;
AttrIdList = gcnew array<NCTYPE_UINT32>(8);
AttrValueList = gcnew array<NCTYPE_UINT32>(8);
AttrIdList[0] = NC_ATTR_BAUD_RATE;
AttrValueList[0] = Baudrate;
AttrIdList[1] = NC_ATTR_START_ON_OPEN;
AttrValueList[1] = NC_TRUE;
AttrIdList[2] = NC_ATTR_READ_Q_LEN;
AttrValueList[2] = 0;
AttrIdList[3] = NC_ATTR_WRITE_Q_LEN;
AttrValueList[3] = 1;
AttrIdList[4] = NC_ATTR_CAN_COMP_STD;
AttrValueList[4] = 0;
AttrIdList[5] = NC_ATTR_CAN_MASK_STD;
AttrValueList[5] = NC_CAN_MASK_STD_DONTCARE;
AttrIdList[6] = NC_ATTR_CAN_COMP_XTD;
AttrValueList[6] = 0;
AttrIdList[7] = NC_ATTR_CAN_MASK_XTD;
AttrValueList[7] = NC_CAN_MASK_XTD_DONTCARE;
interior_ptr<NCTYPE_UINT32> pstart (&AttrIdList[0]);
interior_ptr<NCTYPE_UINT32> pend (&AttrIdList[7]);
Data = gcnew array<char>(8);
for (int i=0; i<8;i++)
Data[i]=i*2;
}
I also have another method right underneath the Config function that is declared as follows:
NCTYPE_STATUS Config2 (String^ objName, int numAttrs, array<unsigned long>^ AttrIdList, array<unsigned long>^ AttrValueList )
{
msclr::interop::marshal_context^ context = gcnew msclr::interop::marshal_context();
const char* name = context->marshal_as<const char*>(objName);
char* name_unconst = const_cast<char*>(name);
return ncConfig (name_unconst, 8, nullptr, nullptr);
delete context;
}
The program compiles and builds, this is a run-time error. I am guessing it has something to do with the two nullptr passed in the function Config2, but if I replace these with the parameters AttrIdList and AttrValueList, the compiler gives an error: cannot convert parameter 3 from 'cli::array^' to 'NCTYPE_ATTRID_P'
BTW: NCTYPE_STATUS is unsigned long, while NCTYPE_ATTRID_P is unsigned long*.
cannot convert parameter 3 from 'cli::array^' to 'NCTYPE_ATTRID_P'
NCTYPE_ATTRID_P is unsigned long*
You can't pass a managed array to a pure native C++ function, you first need to 'convert' it to a fixed unsigned long* pointer.
Here's a way to do it:
unsigned long* ManagedArrayToFixedPtr(array<unsigned long>^input)
{
pin_ptr<unsigned long> pinned = &input[0];
unsigned long* bufferPtr = pinned;
unsigned long* output = new unsigned long[input->Length];
memcpy_s(output, input->Length, bufferPtr, input->Length);
return output;
}
Testing the function:
array<unsigned long>^ larray = gcnew array<unsigned long> {2,4,6,8,10,12,14,16};
unsigned long* lptr = ManagedArrayToFixedPtr(larray); //returns pointer to 2
Edit:
Rememer to #include "windows.h"
to be able to use the memcpy_s function!