diff --git a/meson.build b/meson.build
index 92c6ff0c..11e67368 100644
--- a/meson.build
+++ b/meson.build
@@ -122,6 +122,7 @@ vst3_plugin_sources = [
'src/common/serialization/vst3/component-handler-proxy.cpp',
'src/common/serialization/vst3/connection-point-proxy.cpp',
'src/common/serialization/vst3/context-menu-proxy.cpp',
+ 'src/common/serialization/vst3/context-menu-target.cpp',
'src/common/serialization/vst3/event-list.cpp',
'src/common/serialization/vst3/host-context-proxy.cpp',
'src/common/serialization/vst3/message.cpp',
diff --git a/src/common/serialization/vst3/README.md b/src/common/serialization/vst3/README.md
index 20f32934..6e421951 100644
--- a/src/common/serialization/vst3/README.md
+++ b/src/common/serialization/vst3/README.md
@@ -52,15 +52,16 @@ VST3 host interfaces are implemented as follows:
The following host interfaces are passed as function arguments and are thus also
implemented for serialization purposes:
-| yabridge class | Interfaces | Notes |
-| -------------------- | ------------------- | ---------------------------------------------------------------------- |
-| `YaAttributeList` | `IAttributeList` | |
-| `YaEventList` | `IEventList` | Comes with a lot of serialization wrappers around the related structs. |
-| `YaMessage` | `IMessage` | |
-| `YaMessagePtr` | `IMessage` | Should be used in inter process communication to exchange messages |
-| `YaParameterChanges` | `IParameterChanges` | |
-| `YaParamValueQueue` | `IParamValueQueue` | |
-| `VectorStream` | `IBStream` | Used for serializing data streams. |
+| yabridge class | Interfaces | Notes |
+| --------------------- | -------------------- | --------------------------------------------------------------------- |
+| `YaAttributeList` | `IAttributeList` | |
+| `YaContextMenuTarget` | `IContextMenuTarget` | Used in `YaContextMenu` to proxy specific menu items |
+| `YaEventList` | `IEventList` | Comes with a lot of serialization wrappers around the related structs |
+| `YaMessage` | `IMessage` | |
+| `YaMessagePtr` | `IMessage` | Should be used in inter process communication to exchange messages |
+| `YaParameterChanges` | `IParameterChanges` | |
+| `YaParamValueQueue` | `IParamValueQueue` | |
+| `VectorStream` | `IBStream` | Used for serializing data streams |
And finally `YaProcessData` uses the above along with `YaAudioBusBuffers` to
wrap around `ProcessData`.
diff --git a/src/common/serialization/vst3/context-menu-target.cpp b/src/common/serialization/vst3/context-menu-target.cpp
new file mode 100644
index 00000000..bc7bea5f
--- /dev/null
+++ b/src/common/serialization/vst3/context-menu-target.cpp
@@ -0,0 +1,35 @@
+// yabridge: a Wine VST bridge
+// Copyright (C) 2020-2021 Robbert van der Helm
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#include "context-menu-target.h"
+
+YaContextMenuTarget::YaContextMenuTarget(native_size_t owner_instance_id,
+ native_size_t context_menu_id,
+ int32 tag)
+ : owner_instance_id(owner_instance_id),
+ context_menu_id(context_menu_id),
+ tag(tag){FUNKNOWN_CTOR}
+
+ YaContextMenuTarget::~YaContextMenuTarget() {
+ FUNKNOWN_DTOR
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
+IMPLEMENT_FUNKNOWN_METHODS(YaContextMenuTarget,
+ Steinberg::Vst::IContextMenuTarget,
+ Steinberg::Vst::IContextMenuTarget::iid)
+#pragma GCC diagnostic pop
diff --git a/src/common/serialization/vst3/context-menu-target.h b/src/common/serialization/vst3/context-menu-target.h
new file mode 100644
index 00000000..baec5d89
--- /dev/null
+++ b/src/common/serialization/vst3/context-menu-target.h
@@ -0,0 +1,61 @@
+// yabridge: a Wine VST bridge
+// Copyright (C) 2020-2021 Robbert van der Helm
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+#pragma once
+
+#include
+
+#include "../common.h"
+#include "base.h"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+
+/**
+ * Wraps around `IContextMenuTarget` for proxying calls to specific
+ * `IContextMenu` items. These are created on the plugin side, and when
+ * `executeMenuItem()` gets called we execute the corresponding menu item's
+ * target _from the GUI thread_.
+ */
+class YaContextMenuTarget : public Steinberg::Vst::IContextMenuTarget {
+ public:
+ /**
+ * Create context menu target that when called, calls the corresponding
+ * context menu target provided by the object.
+ *
+ * @param owner_instance_id The object instance that this target's context
+ * menu belongs to.
+ * @param context_menu_id The unique ID of the context menu requested by
+ * `owwner_instance_id`.
+ * @param tag The tag of the menu item this target belongs to.
+ */
+ YaContextMenuTarget(native_size_t owner_instance_id,
+ native_size_t context_menu_id,
+ int32 tag);
+
+ ~YaContextMenuTarget();
+
+ DECLARE_FUNKNOWN_METHODS
+
+ virtual tresult PLUGIN_API executeMenuItem(int32 tag) override = 0;
+
+ protected:
+ native_size_t owner_instance_id;
+ native_size_t context_menu_id;
+ int32 tag;
+};
+
+#pragma GCC diagnostic pop