передача переменной HANDLE в неуправляемый .dll в C ++ / CLI - PullRequest
1 голос
/ 11 мая 2011

Я пытаюсь обернуть неуправляемую dll c ++, которая общается с картой захвата видео в c ++ / CLI, чтобы я мог ссылаться на функции из проекта c #, который у меня есть. У меня возникают проблемы с выполнением первого обернутого вызова, поскольку я новичок в синтаксисе c ++ / cli. вот что у меня есть.

вот функция declataion, которую я пытаюсь обернуть.

__declspec(dllimport) BOOL AZ_DeviceCreate(HANDLE& hLiveEvent, DWORD* hEncoderEvent, DWORD* pdwEncoderAddress, HANDLE& hAudioEvent, DWORD& dwAudioAddress);

вот мой файл c ++ / cli .h

namespace CaptureLibrary 
{
    public ref class CaptureCard
    {
    public:
        HANDLE m_hLiveEvent;
        DWORD *m_hEncoderEvent;
        HANDLE m_hAudioEvent;

    public:
        CaptureCard();
        bool CreateDevice();
        void DisposeDevice();
    };
}

и мой .cpp

namespace CaptureLibrary
{
    CaptureCard::CaptureCard()
    {
        m_hLiveEvent = INVALID_HANDLE_VALUE;

        m_hEncoderEvent = new DWORD[MAX_VIDEO_CHANNEL];
        for (BYTE i=0;i<MAX_VIDEO_CHANNEL;i++)
        {
            m_hEncoderEvent[i] = (DWORD)INVALID_HANDLE_VALUE;
        }

        m_hAudioEvent = INVALID_HANDLE_VALUE;
    }

    bool CaptureCard::CreateDevice()
    {
        DWORD dwEncoderBuff[MAX_VIDEO_CHANNEL];
        DWORD dwACaptureBuffer = 0;

        if(AZ_DeviceCreate(m_hLiveEvent, m_hEncoderEvent, dwEncoderBuff, m_hAudioEvent, dwACaptureBuffer)==FALSE)
        {
            return false;
        }

        return true;
    }

    void CaptureCard::DisposeDevice()
    {
        AZ_DeviceClose();
    }
}

когда я компилирую это с необходимыми заголовками, я получаю эту ошибку:

ошибка C2664: 'AZ_DeviceCreate': невозможно преобразовать параметр 1 из 'HANDLE' в 'HANDLE &'

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

Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 11 мая 2011

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

  • Не открывать поля, выставлять свойства (я предполагаю, что они должны быть только для получения для членов CaptureCard)
  • Не показывать необработанные типы указателей (например, HANDLE), выставлять IntPtr
  • Не открывать необработанные массивы C (например, DWORD*), выставлять array<T>^, ReadOnlyCollection<T>^ или IEnumerable<T>^ (но не открывать array<T>^, предназначенные только для чтения через свойства, только с помощью методов + Array::Copy)
  • Не только предоставьте метод DisposeDevice, но и заставьте класс фактически реализовать IDisposable, чтобы устройство можно было закрыть с помощью оператора using вместо принудительного использования try..finally
  • Поскольку класс управляет неуправляемыми ресурсами, ему требуется финализатор

.h

namespace CaptureLibrary 
{
    public ref class CaptureCard sealed
    {
    public:
        CaptureCard();
        ~CaptureCard();
        !CaptureCard();

        property IntPtr LiveEvent { IntPtr get(); }
        property IEnumerable<DWORD>^ EncoderEvent { IEnumerable<DWORD>^ get(); }
        property IntPtr AudioEvent { IntPtr get(); }

        bool CreateDevice();
        void DisposeDevice();

    private:
        bool m_bOpened;
        IntPtr m_hLiveEvent;
        array<DWORD>^ m_hEncoderEvent;
        IntPtr m_hAudioEvent;
    };
}

.cpp

namespace CaptureLibrary
{
    CaptureCard::CaptureCard()
      : m_hLiveEvent(INVALID_HANDLE_VALUE),
        m_hEncoderEvent(gcnew array<DWORD>(MAX_VIDEO_CHANNEL)),
        m_hAudioEvent(INVALID_HANDLE_VALUE)
    {
        for (int i = 0, i_max = m_hEncoderEvent->Length; i != i_max; ++i)
            m_hEncoderEvent[i] = reinterpret_cast<DWORD>(INVALID_HANDLE_VALUE);
    }

    CaptureCard::~CaptureCard()
    {
        this->!CaptureCard();
    }

    CaptureCard::!CaptureCard()
    {
        DisposeDevice();
    }

    IntPtr CaptureCard::LiveEvent::get()
    {
        return m_hLiveEvent;
    }

    IEnumerable<DWORD>^ CaptureCard::EncoderEvent::get()
    {
        return m_hEncoderEvent;
    }

    IntPtr CaptureCard::AudioEvent::get()
    {
        return m_hAudioEvent;
    }

    bool CaptureCard::CreateDevice()
    {
        DisposeDevice();

        DWORD dwAudioAddress = 0u;
        DWORD dwEncoderAddress[MAX_VIDEO_CHANNEL];

        HANDLE hLiveEvent = m_hLiveEvent.ToPointer();
        HANDLE hAudioEvent = m_hAudioEvent.ToPointer();
        {
            pin_ptr<DWORD> hEncoderEvent = &m_hEncoderEvent[0];
            m_bOpened = AZ_DeviceCreate(hLiveEvent, hEncoderEvent, dwEncoderAddress, hAudioEvent, dwAudioAddress) == TRUE;
        }
        m_hLiveEvent = IntPtr(hLiveEvent);
        m_hAudioEvent = IntPtr(hAudioEvent);

        return m_bOpened;
    }

    void CaptureCard::DisposeDevice()
    {
        if (m_bOpened)
        {
            AZ_DeviceClose();
            m_bOpened = false;
        }
    }
}

Предложения по дальнейшему улучшению:

  • Избавьтесь от CreateDevice и DisposeDevice в целом. У этого кода очень менталитет C-ish; Пользователи .NET ожидают, что созданный объект будет иметь значимое значение без вызова отдельной функции инициализации, поэтому, если предположить, что AZ_DeviceCreate не ожидается регулярного сбоя, тогда логика CreateDevice должна идти прямо в конструкторе класса, а исключение должно быть брошенным при неудаче
  • Если звонить AZ_DeviceClose несколько раз безвредно, избавьтесь от m_bOpened в целом
0 голосов
/ 12 мая 2011

Проблема здесь в том, что вы пытаетесь передать m_hLiveHandle в качестве ссылки (то есть HANDLE &), но для этого потребуется, чтобы на m_hLiveHandle мог указывать собственный указатель (то есть гарантированно не было бы перемещения в памяти).Однако m_hLiveHandle является членом класса ref (CaptureCard), что означает, что его экземпляры хранятся в управляемой куче.Это, в свою очередь, означает, что экземпляр CaptureCard можно переместить в память (с помощью действия сборки мусора).Итак, если вы хотите использовать m_hLiveHandle в качестве параметра указателя или ссылочного параметра, вам придется использовать pin_ptr, чтобы указать сборщику мусора не перемещать этот объект во время вызова собственного метода.Читайте здесь больше: http://msdn.microsoft.com/en-us/library/1dz8byfh(v=vs.80).aspx

...