从wrlcom组件获取托管回调

Getting a managed callback from a WRL COM component

本文关键字:回调 获取 wrlcom 组件      更新时间:2023-10-16

背景(或者,看看我自己走了多远!)

我从Windows 8媒体扩展示例开始。我使用灰度示例作为起点,学习如何将值从托管代码传递到COM对象,以及如何将值从COM对象传递回托管代码。在我的IDL文件中,我有一个GrayscaleEffect类(完全取自示例)和一个自定义接口,应该让我在c#世界中查询字符串。

IDL文件:

namespace GrayscaleTransform
{
    [version(NTDDI_WIN8), uuid(553B5684-4C22-4D21-8638-1E7D86D84F10)]
    interface MyInterface : IInspectable {
        HRESULT GetMsg([out] HSTRING *message);
    }
    [version(NTDDI_WIN8)]
    runtimeclass GrayscaleEffect {
        interface Windows.Media.IMediaExtension;
        interface MyInterface;
    }
}

我的GrayscaleEffect类实现实现GetMsg返回字符串"Woozle"

相关c#:

cap = new MediaCapture();
await cap.InitializeAsync();
previewElement1.Source = cap;
await cap.StartPreviewAsync();
PropertySet props = new PropertySet();
await cap.AddEffectAsync(
    Windows.Media.Capture.MediaStreamType.VideoPreview,
    "GrayscaleTransform.GrayscaleEffect",
    props);
if (this.props.ContainsKey("ref"))
{
    var augGui = (GrayscaleTransform.MyInterface)this.props["ref"];
    string message;
    augGui.GetMsg(out message);
}

调用GetMsg之后,我可以看到消息包含字符串"Woozle",就像我期望的那样-太棒了!

现在我想做一些更有趣的事情。我想实现一个方法,让我从c#向COM传递一个委托,而不是一个让我从COM向c#传递字符串的方法。我想让MFT类每隔10个视频帧调用这个方法-这部分不重要。我希望我的接口有一个叫做SubscribeEvent的方法它把委托作为参数。现在,它可以是一个不带参数的void委托。

这个页面让我相信我应该能够在COM世界中声明一个WinRT委托,并且能够从c#中传递一个相同类型的委托(参见最后的第三项)。酷——看起来很容易。到目前为止,我最好的尝试是在idl中这样做:

delegate void CallbackMethod();
[version(NTDDI_WIN8), uuid(553B5684-4C22-4D21-8638-1E7D86D84F10)]
interface MyInterface : IInspectable {
    HRESULT Subscribe(CallbackMethod cb);
}

不幸的是,这会导致一个错误-似乎与委托CallbackMethod的声明有关:

错误MIDL9008:内部编译器问题-有关如何找到解决方案的建议,请参阅文档。

编辑这一点很明显。这种语法是c++/cx的东西。经过仔细检查,我没有打开c++/CX扩展。这是一个WRL项目,这意味着它是具有模板魔力的常规风格的c++。

我还试图通过实现IConnectionPoint接口来连接事件,但是当我包括OCIdl.h时,我得到一个编译错误,桌面组件无法为ARM编译。

我说错话了吗?我应该让我的GrayscaleEffect类是使用c++/CX的WinRT运行时类吗?也许我们在这里冒险进入"新问题"领域,但是当我试图在c++/CX中使用WinRT类实现IMFTransform时,我得到

错误C2811: 'GrayscaleRT::Class1':不能从'IMFTransform'继承,一个ref类只能从ref类或接口类继承

一个更好的问题:我能在这里传递一个委托吗?我觉得我应该能够做到,只要我知道WRL模板的神奇组合就可以了。

看起来这就是答案。在WRL中,您可以像这样在idl中声明一个事件:

[uuid(3FBED04F-EFA7-4D92-B04D-59BD8B1B055E), version(NTDDI_WIN8)]
delegate HRESULT WhateverEvent();

请参阅添加一个在计算素数时触发的事件部分

我的问题是,我最初不明白我不是使用c++/cx。我使用常规c++和WRL, WRL是一个类似于ATL的模板库,使WinRT编程更容易,并且不使用非标准语言扩展。

一旦我理解了这一点,找到一个使用WRL的事件处理程序示例就相对容易了