diff --git a/README.md b/README.md
index 6e2e4005..75fbfbed 100644
--- a/README.md
+++ b/README.md
@@ -16,8 +16,8 @@ This branch is still very far removed from being in a usable state. Below is an
imcomplete list of things that still have to be done before this can be used:
- Left to implement:
- - `IHostApplication` for both `IPluginBase::initialize()` as well as for
- `IPluginFactory3::setHostContext()`.
+ - `IHostApplication` implementations for both `IPluginBase::initialize()` as
+ well as for `IPluginFactory3::setHostContext()`.
- The rest of `IComponent`'s functions after implementing `intialize()`
- `IPluginFactory3::setHostContext()`
- All other mandatory interfaces
diff --git a/meson.build b/meson.build
index 5d12b3d5..b6b09d2a 100644
--- a/meson.build
+++ b/meson.build
@@ -79,6 +79,7 @@ vst3_plugin_sources = [
'src/common/logging/vst3.cpp',
'src/common/serialization/vst3/base.cpp',
'src/common/serialization/vst3/component.cpp',
+ 'src/common/serialization/vst3/host-application.cpp',
'src/common/serialization/vst3/plugin-factory.cpp',
'src/common/configuration.cpp',
'src/common/plugins.cpp',
@@ -113,6 +114,7 @@ if with_vst3
'src/common/logging/vst3.cpp',
'src/common/serialization/vst3/base.cpp',
'src/common/serialization/vst3/component.cpp',
+ 'src/common/serialization/vst3/host-application.cpp',
'src/common/serialization/vst3/plugin-factory.cpp',
'src/wine-host/bridges/vst3.cpp',
]
diff --git a/src/common/serialization/vst3/host-application.cpp b/src/common/serialization/vst3/host-application.cpp
new file mode 100644
index 00000000..d270e277
--- /dev/null
+++ b/src/common/serialization/vst3/host-application.cpp
@@ -0,0 +1,69 @@
+// yabridge: a Wine VST bridge
+// Copyright (C) 2020 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 "host-application.h"
+
+YaHostApplication::ConstructArgs::ConstructArgs() {}
+
+YaHostApplication::ConstructArgs::ConstructArgs(
+ Steinberg::IPtr context,
+ size_t component_instance_id)
+ : component_instance_id(component_instance_id) {
+ Steinberg::Vst::String128 name_array;
+ if (context->getName(name_array) == Steinberg::kResultOk) {
+#ifdef __WINE__
+ // Who even invented UTF-16
+ static_assert(sizeof(wchar_t) == sizeof(char16_t));
+#endif
+ name = std::u16string(reinterpret_cast(name_array));
+ }
+}
+
+YaHostApplication::YaHostApplication(const ConstructArgs&& args)
+ : arguments(std::move(args)){FUNKNOWN_CTOR}
+
+ YaHostApplication::~YaHostApplication() {
+ FUNKNOWN_DTOR
+}
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
+IMPLEMENT_REFCOUNT(YaHostApplication)
+#pragma GCC diagnostic pop
+
+tresult PLUGIN_API YaHostApplication::queryInterface(Steinberg::FIDString _iid,
+ void** obj) {
+ QUERY_INTERFACE(_iid, obj, Steinberg::FUnknown::iid,
+ Steinberg::Vst::IHostApplication);
+ QUERY_INTERFACE(_iid, obj, Steinberg::Vst::IHostApplication::iid,
+ Steinberg::Vst::IHostApplication)
+
+ *obj = nullptr;
+ return Steinberg::kNoInterface;
+}
+
+tresult PLUGIN_API YaHostApplication::getName(Steinberg::Vst::String128 name) {
+ if (arguments.name) {
+ // Terminate with a null byte. There are no nice functions for copying
+ // UTF-16 strings (because who would use those?).
+ std::copy(arguments.name->begin(), arguments.name->end(), name);
+ name[arguments.name->size()] = 0;
+
+ return Steinberg::kResultOk;
+ } else {
+ return Steinberg::kNotImplemented;
+ }
+}
diff --git a/src/common/serialization/vst3/host-application.h b/src/common/serialization/vst3/host-application.h
new file mode 100644
index 00000000..0589feee
--- /dev/null
+++ b/src/common/serialization/vst3/host-application.h
@@ -0,0 +1,111 @@
+// yabridge: a Wine VST bridge
+// Copyright (C) 2020 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
+#include
+#include
+
+#include "../common.h"
+#include "base.h"
+
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+
+/**
+ * Wraps around `IHostApplication` for serialization purposes. See `README.md`
+ * for more information on how this works. This is used both to proxy the host
+ * application context passed during `IPluginBase::intialize()` as well as for
+ * `IPluginFactory3::setHostContext()`. This interface is thus implemented on
+ * both the native plugin side as well as the Wine plugin host side.
+ */
+class YaHostApplication : public Steinberg::Vst::IHostApplication {
+ public:
+ /**
+ * These are the arguments for creating a
+ * `YaYaHostApplication{Plugin,Host}Impl`.
+ */
+ struct ConstructArgs {
+ ConstructArgs();
+
+ /**
+ * Read arguments from an existing implementation.
+ */
+ ConstructArgs(Steinberg::IPtr context,
+ size_t component_isntance_id);
+
+ /**
+ * The unique instance identifier of the component this host context has
+ * been passed to and thus belongs to.
+ *
+ * TODO: When we implement `IPluginFactory3::setHostContext()` this
+ * should be made optional.
+ */
+ native_size_t component_instance_id;
+
+ /**
+ * For `IHostApplication::getName`.
+ */
+ std::optional name;
+
+ template
+ void serialize(S& s) {
+ s.value8b(component_instance_id);
+ s.ext(name, bitsery::ext::StdOptional{},
+ [](S& s, std::string& name) {
+ s.text2b(name, std::extent_v);
+ });
+ }
+ };
+
+ /**
+ * Instantiate this instance with arguments read from an actual host
+ * context.
+ *
+ * @note Since this is passed as part of ``IPluginBase::intialize()` and
+ * `IPluginFactory3::setHostContext()``, there are no direct `Construct`
+ * or `Destruct` messages. This object's lifetime is bound to that of the
+ * objects they are passed to. If those objects get dropped, then the host
+ * contexts should also be dropped.
+ *
+ * TODO: Check if this ends up working out this way
+ */
+ YaHostApplication(const ConstructArgs&& args);
+
+ /**
+ * The lifetime of this object should be bound to the object we created it
+ * for. When for instance the `IComponent` instance with id `x` gets dropped
+ * and we also track a `YaHostApplicationHostImpl` for the component with
+ * instance id `x`, then that should also be dropped.
+ */
+ ~YaHostApplication();
+
+ DECLARE_FUNKNOWN_METHODS
+
+ // From `IHostApplication`
+ tresult PLUGIN_API getName(Steinberg::Vst::String128 name) override;
+ virtual tresult PLUGIN_API createInstance(Steinberg::TUID cid,
+ Steinberg::TUID _iid,
+ void** obj) override = 0;
+
+ protected:
+ ConstructArgs arguments;
+};
+
+#pragma GCC diagnostic pop
diff --git a/src/common/serialization/vst3/plugin-factory.h b/src/common/serialization/vst3/plugin-factory.h
index 118eb305..979038ce 100644
--- a/src/common/serialization/vst3/plugin-factory.h
+++ b/src/common/serialization/vst3/plugin-factory.h
@@ -127,9 +127,9 @@ class YaPluginFactory : public Steinberg::IPluginFactory3 {
YaPluginFactory(const ConstructArgs&& args);
/**
- * We do not need to implement the destructor, since when the sockets are
- * closed, RAII will clean up the Windows VST3 module we loaded along with
- * its factory for us.
+ * We do not need to implement the destructor in
+ * `YaPluginFactoryPluginImpl`, since when the sockets are closed, RAII will
+ * clean up the Windows VST3 module we loaded along with its factory for us.
*/
virtual ~YaPluginFactory();