Как упаковать класс c++/cli и передать как указатель в неуправляемый метод

192
21 февраля 2018, 10:48

Можно ли, и как упаковать каким-то образом объект управляемый в указатель, и передать его в неуправляемый объект, что бы неуправляемый объект делал вызовы из этого указателя?

Answer 1

В большинстве случаев достаточно неуправляемого класса gcroot<...>, который можно использовать вместо указателя. Считайте его разновидностью умного указателя.

В ситуации, когда нужен именно сырой указатель - можно использовать GCHandle.

Получение указателя:

GCHandle::ToIntPtr(GCHandle::Alloc(obj)).ToPointer()

Преобразование указателя обратно в объект:

GCHandle::FromIntPtr(gcnew IntPtr(ptr)).Target

Только не забудьте освободить GCHandle когда он перестанет быть нужен во избежание утечек памяти:

GCHandle::FromIntPtr(gcnew IntPtr(ptr)).Free()
Answer 2

Решил таким способом:

Добавил неуправляемый класс помощник, в котором есть map<int, gcroot<Object^>>. При записи в класс, сохраняем ссылку, и HashCode класса. Далее извлекаем класс из неуправляемого метода/кода, и в качестве параметра в коллбэке передаем наш хэш код, за счет этого вызываем и извлекаем именно нужный класс.

Вызовы происходят на ура! А так же вместо System::Object^ может быть любой управляемый класс.

В итоге получаем такой класс:

#pragma once
#include <msclr\auto_gcroot.h>
#include <msclr\gcroot.h>
#include <vector>
#include <map>
using namespace msclr;
typedef std::map<int, gcroot<System::Object^>> mypack;
class vlc_helper
{
    vlc_helper();
    mypack m_map;
    static vlc_helper* m_instance_;
public:
    static vlc_helper& instance();
    ~vlc_helper();
    void release();
    gcroot<System::Object^> get_class(int id);
    void remove_data(int id);
    void add_data(int id, gcroot<System::Object^> ptr);
};
#include "stdafx.h"
#include "vlc_helper.h"
#include <iostream>
#include <iterator>
#include <cassert>
vlc_helper* vlc_helper::m_instance_ = nullptr;
vlc_helper::vlc_helper()
{
    m_map = mypack();
}
vlc_helper::~vlc_helper()
{
    m_map.clear();
}
vlc_helper &vlc_helper::instance()
{
    if (!m_instance_)
    {
        m_instance_ = new vlc_helper();
    }
    return *m_instance_;
}
void vlc_helper::release()
{
    delete m_instance_;
}
gcroot<System::Object^> vlc_helper::get_class(int id)
{
    mypack::iterator data = m_map.find(id);
    return data != m_map.end() ? data->second : nullptr;
}
void vlc_helper::remove_data(int id)
{
    mypack::iterator data;
    m_map.erase(id);
}
void vlc_helper::add_data(int id, gcroot<System::Object^> ptr)
{
    m_map.insert(std::make_pair(id, ptr));
}
READ ALSO
уникальность SOCKET

уникальность SOCKET

Добрый деньУникален ли в рамках процесса дескриптор сокета (SOCKET), возвращаемый функциями создания сокета (socket(), accept())?

150
QGamepad назначения кнопок в C++

QGamepad назначения кнопок в C++

Смотрел документацию, но так и не нашел, как назначит к примеру QGamepad::buttonAChanged слушать свою собственную кнопку, которую мы назначили при старте...

166
Модифицировать значение(обновить) в sqlite

Модифицировать значение(обновить) в sqlite

Можно использовать следующий вариант:

187
MultipartFile: как переименовать?

MultipartFile: как переименовать?

Всем приветВ метод приходит MultipartFile

151