1
votes

I have a CLR DLL which serves as an interface for communicating with devices of different processor types. The DLL has been tested and works as expected when being called from a C# test program.

In a C++/CLI test program, I am unable to get values to be put into the buffer passed as a parameter in my read fuction (in the dll).

[Updated]
Here are the declarations for the functions I am using from the dll:

//changed pointers to arrays
bool connect(uint procType, String^ commPort);//Works as expected
bool read(uint16 addr, array<uint8>^% buf, uint bufSize, uint8 page);//data is not put into buf
bool write(uint16 addr, array<uint8>^% buf, uint bufSize, uint page);//Unknown behavior (cannot read to varify)
void close(void);//works as expected

[Updated]
And Here is the C++/CLI test program:

using namespace System;
using namespace ProcessorInterfaceCLR;//namespace in dll

int main(int argc, char * argv[])
{

    ProcessorCLR proc;

    /* connect to device */
    bool is_connected = proc.connect(1, "COM3");
    if (is_connected)/* connect successful */     //Connect passes and fails when expected
    {
        unsigned short addr = 0x1000; //test address
        const unsigned int size = 10;
        array<Byte>^ buf = gcnew array<Byte>(size);// <-------- init managed array

        /* read the data at the location */
        bool retval = proc.read(addr, buf, size, 0/*page*/);   //retval == true
        //buf  == {0,0,0...}, This is not the correct data

        /* close comm when done */
        proc.close();
    }
    return 0;
}

The Problem is that read() should place bytes in the buffer, but instead, the data in buffer is all 0's.

[Update]
Here is the implementation of my read function in the dll. It translates the managed array into an unmanaged array and passes it to the c++ functions being wrapped in the cli dll.

/*
Reads data from the device into the given buffer. */
bool ProcessorCLR::read(uint16 addr, array<uint8>^% buffer, uint size, uint8 page)
{
    pin_ptr<uint8> buf = &buffer[0];
    return proc->read(addr, buf, size, page);
}

I tested this by commenting out the call to proc->read() and adding buf[0] = 1 and I am able to get a return value. So, the Problem is that the array is that while proc->read() would normally change the values in an unmanaged array, it won't change the values for the pin_ptr of the managed array.

The Problem was fixed with the last update. I had to switch the unmanaged arrays to managed arrays AND add the % operator which specifies that a reference will be passed.

1
This is not a C++ question, so don't tag it as such. - Deduplicator
@Deduplicator I'm just learning CLR, but my impression is it's just a deviation of C++. Seeing as my project is a c++ project with a setting switched on to allow CLR support, I figured it qualified as a C++ question. - mdw7326
@md: That's where you went wrong. C++/CLI is derived from C++03 (Which is really old), just like C++ was inspired by C. (But C++/CLI was never updated since.) And yes, MS is horrible when it comes to determining what they are speaking about in that sentence. - Deduplicator
Why is your C++/CLI class exposing raw pointers in the first place? It's meant to do the heavy lifting of interop itself: It should take managed arrays as input, and do the job of pinning them and calling unmanaged functions on their contents. - Medinoc
@Medinoc I was having the same problem with managed arrays and tried it this way instead (which happened to work in C#). I will have to give it another go, however. - mdw7326

1 Answers

-1
votes

To solve my problem I had to:

  1. Switch unmanaged arrays in the c++/cli dll to managed arrays, then use pin_ptr to use them like unmanaged arrays in the dll's inner functions.

  2. Add the % operator to the managed array parameters to specify that they will be passed by reference.

See my question for more details.