[英]Callback from a C++ COM DLL to a C# application
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. 我有C ++ COM dll,其中包含一个VideoPlayer类,该类使用Media Foundation API来显示视频。
The VideoPlayer class is defined using an IDL file: VideoPlayer类是使用IDL文件定义的:
[
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. 此类在内部使用自定义演示器(基于WPFMediaKit项目),该演示器在IDirect3DSurface9对象中输出视频帧。
The custom presenter needs a callback of type IEVRPresenterCallback, which is defined as follow: 定制演示者需要一个IEVRPresenterCallback类型的回调,其定义如下:
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. 如您所见,它不是在IDL文件中定义的,而是在头文件中声明的。
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. 我需要向VideoPlayer类添加一个新函数,该函数允许调用C#代码传递从IEVRPresenterCallback继承的类的实例,该实例将设置为自定义演示者。
I've tried to add this line to the IDL file of the VideoPlayer: 我尝试将这一行添加到VideoPlayer的IDL文件中:
[id(7)] HRESULT RegisterCallback2([in] IEVRPresenterCallback * p_PresenterCallback);
But I get an error: 但是我得到一个错误:
error MIDL2025: syntax error : expecting a type specification near "IEVRPresenterCallback" 错误MIDL2025:语法错误:期望在“ IEVRPresenterCallback”附近输入类型规范
I guess it is normal, because I didn't import anything in the IDL. 我想这很正常,因为我没有在IDL中导入任何内容。 Which is normal, as IEVRPresenterCallback is defined in a header file. 这很正常,因为IEVRPresenterCallback是在头文件中定义的。
I tried to import the header file, but the MIDL_INTERFACE macro of the IEVRPresenterCallback definition generates an error: 我尝试导入头文件,但是IEVRPresenterCallback定义的MIDL_INTERFACE宏会生成错误:
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" 错误MIDL2025:语法错误:期望接口名称或DispatchInterfaceName或CoclassName或ModuleName或LibraryName或ContractName或“ 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' ) ] 错误MIDL2011:未解决的类型声明:IEVRPresenterCallback [过程'RegisterCallback2'(接口'IVideoPlayer')的参数'p_PresenterCallback']
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. 我的最后一次尝试是更改RegisterCallback的定义,以指向IUnknown的指针而不是IEVRPresenterCallback,在函数的声明中,我将该指针转换为正确的接口。
This makes the C++ dll compile correctly. 这使C ++ dll正确编译。
In the C# application, I set the callback as follow: 在C#应用程序中,我将回调设置如下:
[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. 我遇到的问题是尽管自定义演示者调用了回调,但我再也没有回到C#PresentSurfaceCB函数中。
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: 我将接口移到IDL文件中,而不是在回调中返回ID3D9Surface指针,而是返回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: 在我的WPF应用程序中,我创建了一个从IEVRCallback派生的类:
internal class EVRPresenterCallback : EmideeMediaFoundationLib.IEVRPresenterCallback
{
public void PresentSurfaceCB(uint pSurface)
{
}
}
and I give this instance to the VideoPlayer object. 然后将此实例提供给VideoPlayer对象。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.