在C ++ / CLI中将HANDLE变量传递给非托管的.dll

时间:2011-05-11 15:00:05

标签: pointers c++-cli unmanaged wrapper handle

我正在尝试包装一个非托管的c ++ dll,它与c ++ / CLI中的视频捕获卡通信,因此我可以从我拥有的c#项目中引用这些函数。由于我是c ++ / cli语法的新手,因此无法获得第一个包装调用。这就是我所拥有的。

这是我试图包装的函数声明。

__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 个答案:

答案 0 :(得分:1)

我的意思是建设性的:你走错了路。这里使用C ++ / CLI的目的是以一种在.NET中看起来不像外来的方式包装非托管库,但是你的CaptureCard类不会这样做。

  • 不要公开字段,公开属性(我认为它们应该只为CaptureCard成员提供)
  • 不要公开原始指针类型(例如HANDLE),公开IntPtr
  • 不要暴露原始C阵列(例如DWORD*),公开array<T>^ReadOnlyCollection<T>^IEnumerable<T>^(但不要公开array<T>^ s只能通过属性进行只读,只能通过方法+ 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;
        }
    }
}

进一步改进的建议:

  • 完全摆脱CreateDeviceDisposeDevice。这段代码具有很强的C-ish心态; .NET用户希望构造对象具有有意义的值而无需调用单独的初始化函数,因此假设AZ_DeviceCreate不会定期失败,那么CreateDevice的逻辑应直接在类的构造函数中
  • 时应该抛出异常
  • 如果多次致电AZ_DeviceClose无害,那么完全摆脱m_bOpened

答案 1 :(得分:0)

这里的问题是你试图传递m_hLiveHandle作为参考(即HANDLE&amp;),但是这需要m_hLiveHandle可以由本机指针指向(即保证不会在内存中移动) 。但是,m_hLiveHandle是 ref 类(CaptureCard)的成员,这意味着它的实例存储在托管堆上。这反过来意味着CaptureCard的实例可以在内存中移动(通过垃圾收集操作)。因此,如果要将m_hLiveHandle用作指针参数或引用参数,则必须使用pin_ptr告诉垃圾收集器在调用本机方法期间不要移动此对象。在这里阅读更多信息: http://msdn.microsoft.com/en-us/library/1dz8byfh(v=vs.80).aspx