【问题标题】:How to subscribe to events raised within a Windows Runtime Component in C++/CX?如何订阅 C++/CX 中 Windows 运行时组件中引发的事件?
【发布时间】:2013-01-18 00:55:50
【问题描述】:

我在引发事件的 Windows 运行时组件(用 C# 编写)中有一个类。
我无法弄清楚如何在引用该组件的 C++/CX 应用程序中订阅这些事件。

C# 代码(在 Windows 运行时组件中):

public sealed class Messenger {

    private EventRegistrationTokenTable<EventHandler<MessageReceivedEventArgs>> messageReceivedTokenTable;


public event EventHandler<MessageReceivedEventArgs> MessageReceived
{
    add
    {
        return EventRegistrationTokenTable<EventHandler<MessageReceivedEventArgs>>
            .GetOrCreateEventRegistrationTokenTable(ref this.messageReceivedTokenTable)
            .AddEventHandler(value);
    }

    remove
    {
        EventRegistrationTokenTable<EventHandler<MessageReceivedEventArgs>>
            .GetOrCreateEventRegistrationTokenTable(ref this.messageReceivedTokenTable)
            .RemoveEventHandler(value);
    }
}

internal void OnMessageReceived(string message, string location)
{
    EventHandler<MessageReceivedEventArgs> temp =
        EventRegistrationTokenTable<EventHandler<MessageReceivedEventArgs>>
        .GetOrCreateEventRegistrationTokenTable(ref this.messageReceivedTokenTable)
        .InvocationList;

    temp(this, new MessageReceivedEventArgs(message, location));
}

}

MessageReceivedEventArgs 是:

public sealed class MessageReceivedEventArgs : object
{
    public MessageReceivedEventArgs(string message, string location)
    {
        this.Message = message;
        this.SenderLocation = location;
    }

    public string Message { get; set; }


    public string SenderLocation { get; set; }
}

请注意,根据MSDN,它来自 object 而不是 EventArgs。

然后在 C++ 中:

msngr = ref new Messenger();

msngr->MessageReceived += ?????????

+= 和相关方法(以及其他任何地方 - 在 C# 和/或 C++ 中)之后应该做什么,以便我可以在 C++ 应用程序中接收消息?

我尝试了各种方法,但遇到的各种编译器警告都无法为我指明解决方案。

我发现使用 C# 编写但在 C++ 应用程序中使用的 Windows 运行时组件的所有示例都是微不足道的,仅显示使用属性和调用方法。这两件事我都可以毫无问题地完成。我正在寻找一个订阅 C# 中引发的 C++ 事件的示例。

【问题讨论】:

    标签: c++ windows-8 windows-runtime windows-store-apps


    【解决方案1】:

    有必要创建一个代理来使用这些类型。

    这确实是您的问题,需要一个 COM 代理/存根将您的 MessageReceivedEventArgs 类从 C# 编组到 C++/CX。是的,记录很差。我会尝试解释这个过程。开始使用此WinRT sample,它演示了设置解决方案以获取您需要的代理并执行您想要做的事情的方法。

    起点是 ProxyStubForWinRTComponents_server 项目,这是一个声明共享类的 C# 项目。该项目的重要部分是 Post-Build 事件,它看起来像这样:

    call "$(DevEnvDir)..\..\VC\vcvarsall.bat" x86
    winmdidl /outdir:"$(ProjectDir)\" "$(TargetPath)"
    

    第一条语句设置运行 SDK 工具的环境。第二步运行 winmdidl.exe,这是一个完全未记录的构建工具,它将项目生成的 .winmd 文件反编译为 IDL 文件,然后对其进行编译。此构建步骤的输出是:

    • Microsoft.SDKSamples.Kitchen.idl - IDL 格式的反编译 .winmd 文件,用于生成其余文件
    • Microsoft.SDKSamples.Kitchen.h - 包含 C++ 格式的 C# 类型声明,适合 #include 到您的 C++/CX 项目中
    • Microsoft.SDKSamples.Kitchen_i.c - 包含 C# 类型的 GUID,用于构建代理
    • Microsoft.SDKSamples.Kitchen_p.c - 包含从中生成代理和存根的 goo
    • dlldata.c - 用于构建代理。

    接下来看看 ProxyStubsForWinRTComponentsPS 项目,它是构建代理/存根 DLL 的项目。它使用由 winmdidl.exe 生成的文件,唯一添加的是声明从 DLL 导出的 .def 文件。 COM 调用那些使用代理,您可以按原样使用文件。最好按原样使用这个项目,只更改文件的名称,这样您就可以正确设置所有编译器和链接器。

    毫无疑问,令人不快并且有很多方法可以弄错。希望对您有所帮助。

    【讨论】:

    • 是的,我最终使用了示例项目并在那里修改了文件。我找不到有关适当编译器和链接器设置的最新详细信息。
    【解决方案2】:

    假设您在 C++ 引用类中编写此代码,假设是 CPPClass,您的代码将如下所示:

    CPPClass::MyEventHandler(Platform::Object^ obj, MessageReceivedEventArgs^ args)
    {
        // handler code
    }
    
    
    CPPClass::SomeMethod()
    {
        msngr = ref new Messenger(this->SpecifedServer->Text);
        msngr->MessageReceived += ref new EventHandler<MessageReceivedEventArgs^>(this, &CPPClass::MyEventHandler);
    }
    

    ===================

    顺便说一下,下面是一个对我来说很好用的类似示例代码:

    在 C# 中定义类和事件:

    namespace WindowsRuntimeComponent3
    {
        public sealed class MyEventsArgs
        {
        }
    
        public sealed class Class1
        {
            public Class1()
            {
            }
    
            public event EventHandler<MyEventsArgs> MyEvent;
        }
    }
    

    在 C++ 中使用事件:

    App::App()
    {
        InitializeComponent();
        Suspending += ref new SuspendingEventHandler(this, &App::OnSuspending);
    
        auto obj = ref new WindowsRuntimeComponent3::Class1();
        obj->MyEvent += ref new EventHandler<WindowsRuntimeComponent3::MyEventsArgs^>(this, &App::MyEventHandler);
    }
    

    ===================

    【讨论】:

    • 您在哪里/如何定义 MessageReceivedEventHandler?
    • 这个门槛不起作用。正如我现在发现的那样,问题是因为MessageReceivedEventArgs 不是 Windows 运行时知道的类型,所以有必要创建一个代理来使用这些类型。根据我目前发现的所有内容,代理创建过程非常复杂且记录不充分。
    • @MattLacey 我已经编辑了答案并添加了一些适合我的示例代码。
    【解决方案3】:

    可以在此处的 MSDN 上找到此方案的官方文档:Raising Events in Windows Runtime Components

    【讨论】:

    • 由于此答案没有详细说明,因此最好将其发布为评论。
    猜你喜欢
    • 2015-06-15
    • 1970-01-01
    • 2013-04-01
    • 2020-06-05
    • 2015-04-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多