Привести собственный указатель к ссылке на управляемый объект C++\CLI?

У меня есть обратный вызов, который вызывается через делегата. Внутри него мне нужно будет обрабатывать данные буфера, поступающие из процедуры записи. Обычно в неуправляемом контексте я мог бы выполнить reinterpret_cast для dwParam1, чтобы получить ссылку на объект. Но в управляемом контексте, как я могу привести DWORD_PTR к управляемому объекту ref?

    static void WaveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) 
    {
        ControlLib::SoundDevice^ soudDevice = ?cast_native2managed?(dwParam1);

person Ruben Trancoso    schedule 04.01.2010    source источник


Ответы (2)


Вот, более или менее то, что делает gcroot (согласно моему комментарию выше):

using namespace System;
using namespace System::Runtime::InteropServices;

// track an object by a normal (not pinned) handle, encoded in a DWORD_PTR
DWORD_PTR ParamFromObject(Object^ obj)
{
    return reinterpret_cast<DWORD_PTR>(GCHandle::ToIntPtr(GCHandle::Alloc(obj)).ToPointer());
}

static void WaveInProc(PVOID hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) 
{
    // unwrap the encoded handle...
    GCHandle h = GCHandle::FromIntPtr(IntPtr(reinterpret_cast<void*>(dwParam1)));
    try
    {
        // and cast your object back out
        SoundDevice^ x = safe_cast<SoundDevice^>(h.Target);
    }
    finally
    {
        // remember to free the handle when you're done, otherwise your object will never be collected
        GCHandle::Free(h);
    }
}
person Nathan Howell    schedule 04.01.2010
comment
на данный момент я решил сделать аудио класс на чистом c++, но информация может быть удобной. спасибо за помощь! - person Ruben Trancoso; 06.01.2010

Я не эксперт по C++/CLI, но на первый взгляд не думаю, что это возможно. Если бы это было возможно, это было бы очень небезопасно. Основная проблема здесь заключается в том, что управляемые ссылки и собственные указатели являются не одно и то же и не поддерживает один и тот же набор операций.

Что заставляет меня думать, что это невозможно, так это то, что управляемые объекты могут перемещаться в памяти. Операции по сборке мусора, например, сжимают и перемещают память, что соответственно изменяет адреса объектов. Следовательно, невозможно иметь необработанное значение указателя/адреса управляемого объекта, потому что любой заданный GC может сделать его недействительным.

Это не совсем так, поскольку вы можете закрепить объект в памяти. Но даже тогда я не думаю, что есть способ заставить С++ рассматривать произвольный адрес как управляемый дескриптор.

Я думаю, что гораздо более безопасным подходом было бы следующее.

  1. Оберните управляемый объект внутри собственного объекта
  2. Передайте адрес нативного объекта через ваш API.
  3. Используйте reinterpret_cast, чтобы вернуться к собственному типу, а затем безопасно получить доступ к управляемому дескриптору.
person JaredPar    schedule 04.01.2010
comment
Конечно, вы можете получить необработанный указатель на управляемый объект, однако это небезопасно. Трехэтапный подход, о котором вы здесь говорите, уже реализован в шаблонах gcroot/auto_gcroot‹›. По сути, вы просто передаете значение GCHandle по значению IntPtr. - person Nathan Howell; 04.01.2010