从C ++ COM DLL回调到C#应用程序 [英] Callback from a C++ COM DLL to a C# application

查看:620
本文介绍了从C ++ COM DLL回调到C#应用程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这将是一个长的职位,因为我想暴露你所有的步骤,我试图使这项工作:)



我有C + + COM dll包含使用Media Foundation API显示视频的VideoPlayer类。



VideoPlayer类使用IDL文件定义:

  [
object,
uuid(74FDBBB1-BFFB-4F7E-ACA3-ADB0C7232790),
dual,
不可扩展,
pointer_default(unique)
]
interface IVideoPlayer:IDispatch {

[id(1)] HRESULT初始化([in] HWND * video_hwnd,[in] HWND * event_hwnd);
[id(2)] HRESULT OpenUrl([in] BSTR url_path);
[id(3)] HRESULT Play();
[id(4)] HRESULT HandleEvent([in] INT pEventPtr);
[id(5)] HRESULT重绘(void);
[id(6)] HRESULT调整大小([in] LONG宽度,[in] LONG高度);
};

这个类在内部使用自定义的Presenter(基于 WPFMediaKit 项目),它输出IDirect3DSurface9对象内的视频帧。



需要一个IEVRPresenterCallback类型的回调,定义如下:

  MIDL_INTERFACE(B92D8991-6C42-4e51-B942-E61CB8696FCB )
IEVRPresenterCallback:public IUnknown
{
public:
virtual HRESULT STDMETHODCALLTYPE PresentSurfaceCB(IDirect3DSurface9 * pSurface)= 0;
};

正如你所看到的,它没有在IDL文件中定义, 。



我需要向VideoPlayer类添加一个新函数,它允许调用C#代码传递从IEVRPresenterCallback继承的类的实例,该类将被设置为



我已尝试将此行添加到VideoPlayer的IDL文件:

  [id(7)] HRESULT RegisterCallback2([in] IEVRPresenterCallback * p_PresenterCallback); 

但我收到一个错误:


错误MIDL2025:语法错误:期望接近
的类型规范IEVRPresenterCallback


这是正常的,因为我没有在IDL中导入任何东西。这是正常的,因为IEVRPresenterCallback在头文件中定义。



我试图导入头文件,但IEVRPresenterCallback定义的MIDL_INTERFACE宏生成错误: p>

/ b 错误MIDL2025:语法错误:期望接口名称或DispatchInterfaceName或CoclassName或ModuleName或LibraryName或ContractName或类型规范MIDL_INTERFACE p>

然后我尝试转发声明接口,但我收到此错误:


错误MIDL2011:未解析的类型声明:IEVRPresenterCallback [Procedure'RegisterCallback2'(Interface'IVideoPlayer')的参数'p_PresenterCallback']


我最后一次尝试是改变RegisterCallback的定义,有一个指向IUnknown而不是IEVRPresenterCallback的指针,在函数的声明中,我将指针转换到正确的接口。



这使得C ++ dll编译正确。



在C#应用程序中,我设置回调如下:

  [ComVisible(true),ComImport,SuppressUnmanagedCodeSecurity,Guid(B92D8991-6C42-4e51-B942-E61CB8696FCB),InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 
内部接口IEVRPresenterCallback
{
[ PreserveSig]
int PresentSurfaceCB(IntPtr pSurface);
}

内部类EVRPresenterCallback:IEVRPresenterCallback
{
public int PresentSurfaceCB(IntPtr pSurface)
{
return 0;
}
}

public partial class MainWindow:Window
{
private EmideeMediaFoundationLib.IVideoPlayer videoPlayer = new EmideeMediaFoundationLib.VideoPlayer();
private EVRPresenterCallback callback = new EVRPresenterCallback();

public MainWindow()
{
InitializeComponent();
}

private void Button_Click(object sender,RoutedEventArgs e)
{
videoHost.VideoPlayer.RegisterCallback(callback);
videoHost.VideoPlayer.OpenUrl(@C:\Users\Public\Videos\Sample Videos\wildlife.wmv);
}
}

我得到的问题是尽管自定义演示者调用回调,我从来没有回到C#PresentSurfaceCB函数。



我现在完全陷入困境,我不知道问题在哪里,也不知道如何解决



提前感谢



我已经在IDL文件中移动了接口,而改为在回调中返回一个ID3D9Surface指针,我返回一个DOWRD_PTR:

  [
uuid(B92D8991-6C42-4e51 B742-E61CB8696FCB),
]
接口IEVRPresenterCallback:IUnknown {
[id(1)] HRESULT PresentSurfaceCB(DWORD_PTR pSurface);
}

[
object,
uuid(74FDBBB1-BFFB-4F7E-ACA3-ADB0C7232790),
dual,
nonextensible,
pointer_default(unique)
]
interface IVideoPlayer:IDispatch {

[id(1)] HRESULT初始化([in] HWND * video_hwnd,[in] HWND * event_hwnd);
[id(2)] HRESULT OpenUrl([in] BSTR url_path);
[id(3)] HRESULT Play();
[id(4)] HRESULT HandleEvent([in] INT pEventPtr);
[id(5)] HRESULT重绘(void);
[id(6)] HRESULT调整大小([in] LONG宽度,[in] LONG高度);
[id(7)] HRESULT RegisterCallback([in] IEVRPresenterCallback * p_PresenterCallback);
};



在我的WPF应用程序中,我创建一个从IEVRCallback派生的类:

 内部类EVRPresenterCallback:EmideeMediaFoundationLib.IEVRPresenterCallback 
{
public void PresentSurfaceCB(uint pSurface)
{
}
}

我将此实例赋予VideoPlayer对象。


This is going to be a long post, as I want to expose you all the steps I tried to make this work :)

I have C++ COM dll which contains a VideoPlayer class which uses the Media Foundation API to display a video.

The VideoPlayer class is defined using an IDL file:

[
    object,
    uuid(74FDBBB1-BFFB-4F7E-ACA3-ADB0C7232790),
    dual,
    nonextensible,
    pointer_default(unique)
]
interface IVideoPlayer : IDispatch {

    [id(1)] HRESULT Initialize([in] HWND* video_hwnd, [in] HWND* event_hwnd);
    [id(2)] HRESULT OpenUrl([in] BSTR url_path);
    [id(3)] HRESULT Play();
    [id(4)] HRESULT HandleEvent([in] INT pEventPtr);
    [id(5)] HRESULT Repaint(void);
    [id(6)] HRESULT Resize([in] LONG width, [in] LONG height);
};

This class internally uses a custom presenter (which is based on the WPFMediaKit project), which outputs the video frames inside a IDirect3DSurface9 object.

The custom presenter needs a callback of type IEVRPresenterCallback, which is defined as follow:

MIDL_INTERFACE("B92D8991-6C42-4e51-B942-E61CB8696FCB")
IEVRPresenterCallback : public IUnknown
{
public:
    virtual HRESULT STDMETHODCALLTYPE PresentSurfaceCB(IDirect3DSurface9 *pSurface) = 0;
};

As you can see, it is not defined in a IDL file, but is declared in a header file.

I need to add a new function to the VideoPlayer class, which allows the calling C# code to pass an instance of a class inheriting from IEVRPresenterCallback, which will be set to the custom presenter.

I've tried to add this line to the IDL file of the VideoPlayer:

[id(7)] HRESULT RegisterCallback2([in] IEVRPresenterCallback * p_PresenterCallback);

But I get an error:

error MIDL2025: syntax error : expecting a type specification near "IEVRPresenterCallback"

I guess it is normal, because I didn't import anything in the IDL. Which is normal, as IEVRPresenterCallback is defined in a header file.

I tried to import the header file, but the MIDL_INTERFACE macro of the IEVRPresenterCallback definition generates an error:

error MIDL2025: syntax error : expecting an interface name or DispatchInterfaceName or CoclassName or ModuleName or LibraryName or ContractName or a type specification near "MIDL_INTERFACE"

I then tried to forward declare the interface, but I got this error:

error MIDL2011: unresolved type declaration : IEVRPresenterCallback [ Parameter 'p_PresenterCallback' of Procedure 'RegisterCallback2' ( Interface 'IVideoPlayer' ) ]

My last attempt was to change the definition of RegisterCallback, to have a pointer to IUnknown instead of IEVRPresenterCallback, and in the declaration of the function, I cast the pointer to the correct interface.

This makes the C++ dll compile correctly.

In the C# application, I set the callback as follow:

[ComVisible(true), ComImport, SuppressUnmanagedCodeSecurity, Guid("B92D8991-6C42-4e51-B942-E61CB8696FCB"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IEVRPresenterCallback
{
    [PreserveSig]
    int PresentSurfaceCB(IntPtr pSurface);
}

internal class EVRPresenterCallback : IEVRPresenterCallback
{
    public int PresentSurfaceCB(IntPtr pSurface)
    {
        return 0;
    }
}

public partial class MainWindow : Window
{
    private EmideeMediaFoundationLib.IVideoPlayer videoPlayer = new EmideeMediaFoundationLib.VideoPlayer();
    private EVRPresenterCallback callback = new EVRPresenterCallback();

    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        videoHost.VideoPlayer.RegisterCallback(callback);
        videoHost.VideoPlayer.OpenUrl(@"C:\Users\Public\Videos\Sample Videos\wildlife.wmv");
    }
}

The problem I get is despite the custom presenter calling the callback, I never get back in the C# PresentSurfaceCB function.

I'm completely stuck right now, and I don't know where the problem is, nor how to solve it :(

Any ideas?

Thanks in advance

解决方案

Thanks to Hans, I could make it work.

I moved the interface in the IDL file, and instead of returning a ID3D9Surface pointer in the callback, I return a DOWRD_PTR:

[
    uuid(B92D8991-6C42-4e51-B942-E61CB8696FCB),
]
interface IEVRPresenterCallback : IUnknown {
    [id(1)] HRESULT PresentSurfaceCB( DWORD_PTR pSurface);
}

[
    object,
    uuid(74FDBBB1-BFFB-4F7E-ACA3-ADB0C7232790),
    dual,
    nonextensible,
    pointer_default(unique)
]
interface IVideoPlayer : IDispatch {

    [id(1)] HRESULT Initialize([in] HWND* video_hwnd, [in] HWND* event_hwnd);
    [id(2)] HRESULT OpenUrl([in] BSTR url_path);
    [id(3)] HRESULT Play();
    [id(4)] HRESULT HandleEvent([in] INT pEventPtr);
    [id(5)] HRESULT Repaint(void);
    [id(6)] HRESULT Resize([in] LONG width, [in] LONG height);
    [id(7)] HRESULT RegisterCallback([in] IEVRPresenterCallback * p_PresenterCallback);
};

In my WPF application, I create a class deriving from IEVRCallback:

internal class EVRPresenterCallback : EmideeMediaFoundationLib.IEVRPresenterCallback
{
    public void PresentSurfaceCB(uint pSurface)
    {
    }
}

and I give this instance to the VideoPlayer object.

这篇关于从C ++ COM DLL回调到C#应用程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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