Передача неуправляемых указателей в C ++ / CLI - PullRequest
5 голосов
/ 20 февраля 2009

Я создаю DLL-оболочку C ++ / CLI, которая зависит от многочисленных статических библиотек C ++. Некоторые вызовы функций ожидают передачи неуправляемых указателей. Как правильно их передать?

Кроме того, другие функции ожидают, что этот указатель будет передан как void *. Какой правильный способ передать «это»?

Вот мое определение класса ...

public ref class RTPClient
{
    public:
        RTPClient();
        ~RTPClient();

        bool Connect();
        void Disconnect();

    private:
        CIsmaClient* mClient;
};

Вот мое использование, где используются указанные указатели ...

RTPClient::RTPClient():
    mClient(NULL)
{
    CIsmaClient::Create(&mClient, NULL, &AllocBuffer, &GetDataPointer, this);
}

Использование & mClient и «this» вызывает следующие ошибки компилятора ... 1>. \ VBLoadSimulatorDll.cpp (40): ошибка C2664: «CIsmaClient :: Create»: невозможно преобразовать параметр 1 из «cli :: interior_ptr» в «CIsmaClient **» 1> с 1> [ 1> Тип = CIsmaClient * 1>]

1>. \ VBLoadSimulatorDll.cpp (40): ошибка C2664: 'CIsmaClient :: Create': невозможно преобразовать параметр 5 из VBLoadSimulator :: RTPClient ^ const в 'VOID *'

Ответы [ 2 ]

9 голосов
/ 20 февраля 2009

Если вы передаете указатель на управляемый класс, тогда легко преобразовать ссылку ^ в указатель, но вы должны закрепить управляемый объект, чтобы ГХ не перемещал его в памяти (таким образом, аннулируя указатель)

Это просто с pin_ptr

Однако ваш код выполняет две вещи, которые не будут работать

RTPClient::RTPClient():
        mClient(NULL)
{
    CIsmaClient::Create(
        &mClient,          // 1
        NULL, 
        &AllocBuffer, 
        &GetDataPointer, 
        this);            //2
}

1) Вы пытаетесь получить адрес чего-либо в управляемой куче (расположение указателя на указатель mClient находится в управляемой куче.

Как таковой, он может перемещаться в памяти, таким образом, внутренний указатель поставщика компилятора (значение которого сохраняется в операциях GC). Это должно быть закреплено , и это будет работать только в том случае, если функция Create не ожидает использовать указатель после того, как его область действия закончилась (если он передает его в другое место для хранения, это приведет к ошибкам). 1016 *

2) Вы передаете дескриптор (забавный символ шляпы), а не указатель. (Прочитайте раздел википедии об этом, они являются хорошим обзором) Это не (и не может быть) понято неуправляемым кодом.

Единственная причина, по которой я могу думать об этом параметре в этом контексте, - это явная переменная состояния, передаваемая последующим обратным вызовам функций (исправьте меня, если я ошибаюсь). «this» в этом контексте НИКОГДА не будет работать должным образом, так как это может перемещаться в памяти, как только pin_ptr выходит из области видимости.

Имея это в виду, здесь (частично) исправленная реализация проясняет, что можно, а что нельзя исправлять.

RTPClient::RTPClient():
        mClient(NULL)
{
    // make it clear you want the address of the instance variable
    pin_ptr<CIsmaClient*> pinnedClient = &this->mClient; 
    CIsmaClient::Create(
        pinnedClient,          // fixed
        NULL, 
        &AllocBuffer, 
        &GetDataPointer, 
        x /* pass something else in */);            //2
}

Если вы предоставите больше информации о том, для чего используется последний параметр, я могу предложить возможные решения

2 голосов
/ 12 ноября 2010

Я думаю, вы поймете, что это самый простой способ передачи управляемой ссылки через указатель void:

void SomeFunction(void* input)
{
  gcroot<ManagedClass^>* pointer = (gcroot<ManagedClass^>*)(input);
  (*pointer)->ManagedFunction();
}

void Example()
{
  ManagedClass^ handle = gcnew ManagedClass();
  gcroot<ManagedClass^>* pointer = new gcroot<ManagedClass^>(handle);
  SomeFunction((void*)pointer);
  delete pointer;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...