2

I have an class in a Windows Runtime Component (written in C#) that raises events.
I cannot work out how to subscribe to these events in a C++/CX app that references the component.

The C# code (in the Windows Runtime Component):

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 is:

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

Note that as per MSDN this descends from object and not EventArgs.

Then in C++:

msngr = ref new Messenger();

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

What should go after the += and in the relevant method (and anywhere else - in C# and/or C++) so that I can receive the messages in the C++ app?

I've tried various things and the various compiler warnings I've encountered have been unable to point me to a solution.

All examples I've found of using a Windows Runtime Component written in C# but consumed in a C++ app have been trivial and only show using properties and calling methods. Both of which I can do without problem. I'm after an example of subscribing to an event in C++ that is raised in C#.

4

3 回答 3

5

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

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

起点是 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# 类型的声明,适合在您的 C++/CX 项目中#included
  • Microsoft.SDKSamples.Kitchen_i.c - 包含 C# 类型的 GUID,用于构建代理
  • Microsoft.SDKSamples.Kitchen_p.c - 包含从中生成代理和存根的 goo
  • dlldata.c - 用于构建代理。

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

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

于 2013-02-10T21:30:45.720 回答
1

假设您在 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);
}

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

于 2013-02-06T12:33:39.880 回答
0

可以在此处的 MSDN 上找到此方案的官方文档:在 Windows 运行时组件中引发事件

于 2013-10-28T17:47:01.250 回答