在C ++ / CLI中将HANDLE变量传递到非托管.dll [英] passing a HANDLE variable to an unmanaged .dll in C++/CLI
问题描述
我试图包装一个非托管的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
), exposeIntPtr
- Don't expose raw C-arrays (e.g.
DWORD*
), exposearray<T>^
,ReadOnlyCollection<T>^
, orIEnumerable<T>^
(but don't exposearray<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 implementIDisposable
so the device can be closed with ausing
statement rather than forcing use oftry..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
andDisposeDevice
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 assumingAZ_DeviceCreate
is not expected to fail regularly thenCreateDevice
'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 ofm_bOpened
altogether
这篇关于在C ++ / CLI中将HANDLE变量传递到非托管.dll的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!