C#调用C++ DLL时遇到的问题 C++定义了一个回调函数集
C#调用DLL时如何实现这个回调函数集 用接口和抽象类都试了都无法完成   请达人赐教
回调函数集
class IHikClientAdviseSink
{
public:
/******************************************************************
在Setup时被调用,获取总的播放长度.nLength为总的播放长度,以1/64秒为单位
*/
virtual int OnPosLength( unsigned long nLength ) = 0; /******************************************************************
     在Setup后被调用,表示URL已经被成功打开,sucess为1表示成功,0表示失败
*/
virtual int OnPresentationOpened(int success) = 0;  /************************************************************************
     在Player被停止销毁后调用
     */
virtual int OnPresentationClosed() = 0;  /************************************************************************
     未使用
     */
virtual int OnPreSeek( unsigned long uOldTime, unsigned long uNewTime ) = 0;  /************************************************************************
     未使用
     */
virtual int OnPostSeek( unsigned long uOldTime, unsigned long uNewTime ) = 0;  /************************************************************************
     未使用
 */
virtual int OnStop() = 0;  /************************************************************************
     在Pause时被调用,uTime目前都是0
     */
virtual int OnPause( unsigned long uTime ) = 0; /************************************************************************
     在开始播放时调用,uTime目前都是0
     */
virtual int OnBegin( unsigned long uTime ) = 0;     /************************************************************************
     在随机播放时调用,uTime目前都是0
     */
virtual int OnRandomBegin( unsigned long uTime ) = 0; /************************************************************************
     在Setup前调用,pszHost表示正在连接的服务器
     */
virtual int OnContacting( const char* pszHost ) = 0;
    
/************************************************************************
在服务器端返回出错信息是调用, pError中为出错信息内容
*/
virtual int OnPutErrorMsg( const char* pError ) = 0;

/************************************************************************
    未使用
     */
virtual int OnBuffering( unsigned int uFlag, unsigned short uPercentComplete ) = 0; virtual int OnChangeRate(int flag)=0; virtual int OnDisconnect()=0;
};
------------------------------------------------------------------------------------------------------
class CclientTestDlg : public CDialog, public IHikClientAdviseSink
{
// 构造
public:
    CclientTestDlg(CWnd* pParent = NULL); // 标准构造函数
virtual int OnPosLength(unsigned long nLength );
virtual int OnPresentationOpened(int success);//int totaltime
virtual int OnPresentationClosed();
virtual int OnPreSeek( unsigned long uOldTime, unsigned long uNewTime );
virtual int OnPostSeek( unsigned long uOldTime, unsigned long uNewTime );
virtual int OnStop();
virtual int OnPause( unsigned long uTime );
virtual int OnBegin( unsigned long uTime );
virtual int OnRandomBegin( unsigned long uTime );
virtual int OnContacting( const char* pszHost );
virtual int OnBuffering( unsigned int uFlag, unsigned short uPercentComplete );
virtual int OnPutErrorMsg( const char* pError );
virtual int OnChangeRate(int flag);
virtual int OnDisconnect();
------------------------------------------------------------------------------------------------------
API:CLIENT_API HSESSION __stdcall HIKS_CreatePlayer(IHikClientAdviseSink* pSink, void* pWndSiteHandle, pDataRec pRecFunc, pMsgBack pMsgFunc=0,int TransMethod=0);//创建Player

解决方案 »

  1.   

    Platform invoke支持回调。你的接口接受一个IHikClientAdviseSink* pSink, 这就必然要求传入一个对象。
    而你的类IHikClientAdviseSink有只包含函数。要知道Platform对类(结构)的支持只是Marshaling Data。C#端肯定是无法知道这些函数的。因此估计你只能将回调函数拿出到全局范围内。HIKS_CreatePlayer的参数接受这些回调函数。int OnPosLength( unsigned long nLength );
    typedef int(*OnPosLength)(unsigned long nLength );   CLIENT_API HSESSION __stdcall HIKS_CreatePlayer(OnPosLength on****, ...)
    这样在C#端可以定义callback供C#端调用。
    参见:
    using System;
    using System.Runtime.InteropServices;public delegate bool CallBack(int hwnd, int lParam);public class EnumReportApp {    [DllImport("user32")]
        public static extern int EnumWindows(CallBack x, int y);     public static void Main() 
        {
            CallBack myCallBack = new CallBack(EnumReportApp.Report);
            EnumWindows(myCallBack, 0);
        }   public static bool Report(int hwnd, int lParam) { 
            Console.Write("Window handle is ");
            Console.WriteLine(hwnd);
            return true;
        }
    }
      

  2.   

    You might try marshaling the IHikClientAdviseSink as COM interface so the CLR will create a stub for interop.1. On the C# side, we marshal the interface as IUnknown, so the stub will have a v-table layout like:
       QueryInterface()
       AddRef()
       Release()
       OnPosLength()
       OnPresentationOpened()
       ...2. On the C++ side, we let IHikClientAdviseSink derive from IUnknown so they will be binary compatible.
    3. Use PreserveSig to prevent CLR from striping/adding HRESULT as error code.
    4. COM call convention is stdcall.
    5. Here is an example:
    using System;
    using System.Runtime.InteropServices;
    using System.Runtime.CompilerServices;namespace TestMyDll
    {
        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]        //<----1
        interface IHikClientAdviseSink
        {
            [PreserveSig]                                            //<----3
            int OnPosLength( uint nLength );        [PreserveSig]
            int OnPresentationOpened(int success);        [PreserveSig]
            int OnPresentationClosed();
        }    class MyImplementation : IHikClientAdviseSink
        {
            public int OnPosLength(uint nLength)
            {
                Console.WriteLine("Managed OnPosLength:" + nLength);
                return 11;
            }        public int OnPresentationOpened(int success)
            {
                Console.WriteLine("Managed OnPresentationOpened:" + success);
                return 22;
            }        public int OnPresentationClosed()
            {
                Console.WriteLine("Managed OnPresentationClosed");
                return 33;
            }
        }    class Program
        {
            static MyImplementation myImplementation = new MyImplementation();
            static void Main()
            {
                int i = HIKS_CreatePlayer(myImplementation);
                Console.ReadLine();
            }
            [DllImport("MyDll.dll")]
            extern static int HIKS_CreatePlayer(IHikClientAdviseSink pSink);
        }
    }// MyDll.cpp 
    //
    #include <windows.h>
    #include <atlbase.h>class IHikClientAdviseSink : IUnknown                                //<----2
    {
    public:
        virtual int __stdcall OnPosLength( unsigned long nLength ) = 0;  //<----4
        virtual int __stdcall OnPresentationOpened(int success) = 0;
        virtual int __stdcall OnPresentationClosed() = 0;
        //....
    };extern "C"
    {
        __declspec(dllexport) int __stdcall HIKS_CreatePlayer(IHikClientAdviseSink* pSink)
        {
            pSink->OnPosLength( 3 );
            pSink->OnPresentationOpened( 6 );
            pSink->OnPresentationClosed();
            return 1234;
        }
    }
      

  3.   

    IHikClientAdviseSink,定义这个接口还不够,还要设置GUID匹配才行(定义接口时用GuidAttribute修饰)。