У меня есть класс в Windows Runtime Component (написан на 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 это происходит от объекта, а не EventArgs.
Затем в C ++:
msngr = ref new Messenger();
msngr->MessageReceived += ?????????
Что должно идти после +=
и в соответствующем методе (и в любом другом месте — в C # и / или C ++), чтобы я мог получать сообщения в приложении C ++?
Я пробовал разные вещи, и различные предупреждения компилятора, с которыми я сталкивался, не могли указать мне на решение.
Все примеры использования Windows Runtime Component, написанные на C #, но используемые в приложении C ++, были тривиальны и показаны только с использованием свойств и вызывающих методов. Оба из которых я могу сделать без проблем. Я приведу пример подписки на событие в C ++, которое возникает в C #.
необходимо создать прокси для использования таких типов.
Это действительно ваша проблема, 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, а затем компилирует его. Выходные данные этого шага сборки:
Далее рассмотрим проект ProxyStubsForWinRTComponentsPS, который создает библиотеку DLL прокси / заглушки. Он использует файлы, сгенерированные winmdidl.exe, единственный добавленный файл .def, который объявляет об экспорте из DLL. COM вызывает тех, кто использует прокси, вы можете использовать файл как есть. Лучше всего использовать этот проект как есть, изменяя только имена файлов, чтобы все параметры компилятора и компоновщика были правильными.
Неприятно и много способов ошибиться, без сомнения. Надеюсь, поможет.
Предполагая, что вы пишете этот код в классе C ++ ref, скажем, 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);
}
=================
Официальную документацию по этому сценарию можно найти на MSDN здесь: Создание событий в компонентах среды выполнения Windows