我正在尝试包装一个非托管的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 &'
任何人都可以帮助我,因为我知道这是一个愚蠢的语法,我做错了。
提前致谢。
答案 0 :(得分:1)
我的意思是建设性的:你走错了路。这里使用C ++ / CLI的目的是以一种在.NET中看起来不像外来的方式包装非托管库,但是你的CaptureCard
类不会这样做。
CaptureCard
成员提供)HANDLE
),公开IntPtr
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;
}
}
}
进一步改进的建议:
CreateDevice
和DisposeDevice
。这段代码具有很强的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