2011-11-09 38 views
2

這將是一個很長的帖子,因爲我要揭露你的所有步驟我努力使這項工作:)回調到C#應用程序

我有C++ COM DLL包含一個使用Media Foundation API顯示視頻的VideoPlayer類。

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); 

但我得到一個錯誤:

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

我想這是正常的,因爲我沒有」不要在IDL中導入任何東西。這是正常的,因爲IEVRPresenterCallback是在頭文件中定義的。

我試圖導入的頭文件,但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"

然後我試圖轉發申報界面,但我得到這個錯誤:

error MIDL2011: unresolved type declaration : IEVRPresenterCallback [ Parameter 'p_PresenterCallback' of Procedure 'RegisterCallback2' (Interface '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功能。

我完全現在卡住了,我不知道問題出在哪裏,也不知道怎樣去解決它:(

任何想法?

在此先感謝

+1

不要試圖避免將接口放入IDL中,這沒有意義。你不能強制轉換COM指針,你必須使用QueryInterface()。 –

+0

我試圖在IDL中聲明接口,但是我的ID3D9Surface接口有問題...除非我更改IEVRCallback的聲明以使用LONG指針而不是ID3D9Surface?我會試一試。 – Mike

回答

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對象。

+0

'public void PresentSurfaceCB(uint pSurface)' - 既然PresentSurfaceCB返回HRESULT,它應該不是'public int PresentSurfaceCB(uint pSurface)'嗎?我遇到的問題是,如果我將回調返回類型聲明爲int而不是void,則我在x86模式下訪問衝突,但在x64中正常工作! –