在C ++ / CLI中将HANDLE变量传递到非托管.dll [英] passing a HANDLE variable to an unmanaged .dll in C++/CLI

查看:174
本文介绍了在C ++ / CLI中将HANDLE变量传递到非托管.dll的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图包装一个非托管的c ++ dll,谈到c ++ / CLI中的视频捕获卡,所以我可以引用我有一个c#项目的功能。我有麻烦得到第一次包装调用工作,因为我是新的到c ++ / cli语法。这是我有的。



这里是我想要换行的函数declataion。

  __ declspec(dllimport)BOOL AZ_DeviceCreate(HANDLE& hLiveEvent,DWORD * hEncoderEvent,DWORD * pdwEncoderAddress,HANDLE& hAudioEvent,DWORD& dwAudioAddress) 

这里是我的c ++ / cli .h文件

 命名空间CaptureLibrary 
{
public ref class CaptureCard
{
public:
HANDLE m_hLiveEvent;
DWORD * m_hEncoderEvent;
HANDLE m_hAudioEvent;

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

和我的.cpp

 命名空间CaptureLibrary 
{
CaptureCard :: CaptureCard()
{
m_hLiveEvent = INVALID_HANDLE_VALUE;

m_hEncoderEvent = new DWORD [MAX_VIDEO_CHANNEL];
for(BYTE i = 0; 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&'


任何人都可以帮助我,因为我知道这是一个愚蠢的语法,我做错了。



提前感谢。

解决方案

我的意思是建设性的:你走错了脚。 C ++ / CLI的目标是以非托管库的方式包装非托管库,但是你的 CaptureCard 类不会这样做。 / p>


  • 不要公开字段,公开属性(我认为它们应该是 CaptureCard 的成员)

  • 不要暴露原始指针类型(例如 HANDLE ),暴露 IntPtr

  • 不要暴露原始C数组(例如 DWORD * ), $ c> array< T> ^ , ReadOnlyCollection< T> ^ IEnumerable< T& c $ c>(但是不要通过属性暴露数组< T> ^ :Copy

  • 不仅公开一个 DisposeDevice 方法, code> IDisposable ,因此可以用使用语句关闭设备,而不是强制使用 try ..最后

  • 由于类控制非托管资源,需要终结符



.h

 命名空间CaptureLibrary 
{
public ref class CaptureCard sealed
{
public:
CaptureCard();
〜CaptureCard();
!CaptureCard();

属性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

 命名空间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 完全


I am trying to wrap an unmanaged c++ dll that talks to a video capture card in c++/CLI so i can reference the functions from a c# project that i have. I am having trouble getting the 1st wrapped call to work as I am new to c++/cli syntax. here is what i have.

here is the function declataion i am trying to wrap.

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

here is my c++/cli .h file

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

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

and my .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();
    }
}

when i compile this with the required headers, i get this error:

error C2664: 'AZ_DeviceCreate' : cannot convert parameter 1 from 'HANDLE' to 'HANDLE &'

Can anyone help me as I know this is a stupid syntax thing that I am doing wrong.

Thanks in advance.

解决方案

I mean this constructively: you're off on the wrong foot. Your goal with C++/CLI here is to wrap the unmanaged library in a manner that won't seem foreign in .NET, but your CaptureCard class doesn't do that.

  • Don't expose fields, expose properties (I assume they should be get-only for CaptureCard's members)
  • Don't expose raw pointer types (e.g. HANDLE), expose IntPtr
  • Don't expose raw C-arrays (e.g. DWORD*), expose array<T>^, ReadOnlyCollection<T>^, or IEnumerable<T>^ (but don't expose array<T>^s intended to be read-only via properties, only via methods + Array::Copy)
  • Don't only expose a DisposeDevice method, also make the class actually implement IDisposable so the device can be closed with a using statement rather than forcing use of try..finally
  • As the class controls unmanaged resources, it needs a finalizer

.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;
        }
    }
}


Suggestions for further improvement:

  • Get rid of CreateDevice and DisposeDevice altogether. This code has a very C-ish mentality; .NET users would expect a constructed object to have a meaningful value without calling a separate initialization function, so assuming AZ_DeviceCreate is not expected to fail regularly then CreateDevice's logic should go straight in the class' constructor and an exception should be thrown upon failure
  • If calling AZ_DeviceClose multiple times is harmless then get rid of m_bOpened altogether

这篇关于在C ++ / CLI中将HANDLE变量传递到非托管.dll的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆