这将是一个很长的帖子,因为我想向您揭示我尝试使其工作的所有步骤:)
我有C ++ COM dll,其中包含一个VideoPlayer类,它使用Media Foundation API显示视频。
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);
};
此类在内部使用自定义演示者(基于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宏会生成错误:
错误MIDL2025:语法错误:需要接口名称或DispatchInterfaceName或CoclassName或ModuleName或LibraryName或ContractName或“MIDL_INTERFACE”附近的类型规范
然后我尝试转发声明接口,但是我收到了这个错误:
错误MIDL2011:未解析的类型声明:IEVRPresenterCallback [过程'RegisterCallback2'的参数'p_PresenterCallback'(接口'IVideoPlayer')]
我的最后一次尝试是更改RegisterCallback的定义,以指向IUnknown而不是IEVRPresenterCallback,并在函数的声明中,我将指针转换为正确的接口。
这使得C ++ DLL能够正确编译。
在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");
}
}
我得到的问题是尽管自定义主持人调用了回调,但我从未回到C#PresentSurfaceCB函数。
我现在完全陷入困境,我不知道问题出在哪里,也不知道如何解决问题:(
有什么想法吗?
提前致谢
答案 0 :(得分:0)
感谢汉斯,我能让它发挥作用。
我在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);
};
在我的WPF应用程序中,我创建了一个派生自IEVRCallback的类:
internal class EVRPresenterCallback : EmideeMediaFoundationLib.IEVRPresenterCallback
{
public void PresentSurfaceCB(uint pSurface)
{
}
}
我将此实例提供给VideoPlayer对象。