2011-05-11 303 views
1

非托管的.dll我想换一个托管C++动态链接库会谈到视频采集卡在C++/CLI,所以我可以从我有一个C#项目中引用的功能。由于我是C++/cli语法的新手,因此无法使第一次打包的调用工作。这是我的。传递一个HANDLE变量在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(); 
    } 
} 

当我编译这与所需的头,我得到这个错误:

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

谁能帮助我,因为我知道这是一个愚蠢的语法,我做错了。

在此先感谢。

回答

1

我的意思是建设性的:你关上出师不利。你用C++/CLI这里的目标是包装的非托管库,将似乎没有外国在.NET的方式,但你的CaptureCard类没有做到这一点。

  • 不要暴露领域,公开属性(我认为他们应该得到,只为CaptureCard的成员)
  • 不要暴露原始指针类型(例如HANDLE),暴露IntPtr
  • 唐“T暴露生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; 
     } 
    } 
} 

建议进一步改进:

  • 获得完全摆脱CreateDeviceDisposeDevice。这个代码有一个非常C - ish的心态; 。NET用户希望一个构造对象具有一个有意义的值,而不需要调用一个单独的初始化函数,所以假设AZ_DeviceCreate不会定期失败,那么CreateDevice的逻辑应该在类的构造函数中直接执行,并且应该在失败时引发异常
  • 如果在调用AZ_DeviceClose多次是无害的,然后摆脱m_bOpened完全
+0

哇,这是一个巨大的帮助!感谢您的帮助。这真的让我可以说话了。再一次,谢谢! – 2011-05-12 14:49:32

0

这里的问题是,你试图通过m_hLiveHandle为基准(即HANDLE &),但是这将需要m_hLiveHandle可以指出由一个本地指针(即它将被保证不在内存中移动)。但是,m_hLiveHandle是类(CaptureCard)的成员,意味着它的实例存储在托管堆上。这又意味着CaptureCard的实例可以在内存中移动(通过垃圾收集操作)。所以,如果你想使用m_hLiveHandle作为指针参数或引用参数,你必须使用pin_ptr来告诉垃圾收集器在调用本地方法的持续时间内不要移动这个对象。在这里阅读更多: http://msdn.microsoft.com/en-us/library/1dz8byfh(v=vs.80).aspx