diff --git a/src/common/serialization/clap.h b/src/common/serialization/clap.h
index f46db77d..6a2a9dbf 100644
--- a/src/common/serialization/clap.h
+++ b/src/common/serialization/clap.h
@@ -22,6 +22,7 @@
#include "../bitsery/ext/message-reference.h"
#include "../utils.h"
+#include "clap/plugin-factory.h"
#include "common.h"
// The CLAP communication strategy is identical to what we do for VST3.
diff --git a/src/common/serialization/clap/plugin-factory.h b/src/common/serialization/clap/plugin-factory.h
new file mode 100644
index 00000000..5bde4ec1
--- /dev/null
+++ b/src/common/serialization/clap/plugin-factory.h
@@ -0,0 +1,290 @@
+// yabridge: a Wine plugin bridge
+// Copyright (C) 2020-2022 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 "plugin.h"
+
+// Serialization messages for `clap/plugin-factory.h`
+
+namespace clap {
+namespace plugin_factory {
+
+/**
+ * The response to the `clap::plugin_factory::list` message defined below.
+ */
+struct list_response {
+ std::vector descriptors;
+
+ template
+ void serialize(S& s) {
+ s.container(descriptors, 8192);
+ }
+};
+
+/**
+ * Message combining `clap_plugin_factory::count()` with
+ * `clap_plugin_factory::get()` to get all plugin descriptors in one go.
+ */
+struct list {
+ using Response = list_response;
+
+ // Since we send this to a specific CLAP plugin library, there are no
+ // parameters here
+ template
+ void serialize(S&) {}
+};
+
+} // namespace plugin_factory
+} // namespace clap
+
+// #include
+// #include
+
+// #include "../../../bitsery/ext/in-place-optional.h"
+// #include "../base.h"
+// #include "../host-context-proxy.h"
+
+// #pragma GCC diagnostic push
+// #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+
+// /**
+// * Wraps around `IPluginFactory{1,2,3}` for serialization purposes. This is
+// * instantiated as part of `Vst3PluginFactoryProxy`.
+// */
+// class YaPluginFactory3 : public Steinberg::IPluginFactory3 {
+// public:
+// /**
+// * These are the arguments for creating a `YaPluginFactory3`. All class
+// * infos in all available formats are read from the plugin so the host
+// can
+// * query them.
+// */
+// struct ConstructArgs {
+// ConstructArgs() noexcept;
+
+// /**
+// * Check whether an existing implementation implements
+// * `IPluginFactory1`, `IPluginFactory2`, and ``IPluginFactory3`` and
+// * read arguments from it.
+// */
+// ConstructArgs(Steinberg::IPtr object);
+
+// /**
+// * Whether the object supported `IPluginFactory`.
+// */
+// bool supports_plugin_factory = false;
+
+// /**
+// * Whether the object supported `IPluginFactory2`.
+// */
+// bool supports_plugin_factory_2 = false;
+
+// /**
+// * Whether the object supported `IPluginFactory3`.
+// */
+// bool supports_plugin_factory_3 = false;
+
+// /**
+// * For `IPluginFactory::getFactoryInfo`.
+// */
+// std::optional factory_info;
+
+// /**
+// * For `IPluginFactory::countClasses`.
+// */
+// int num_classes;
+
+// /**
+// * For `IPluginFactory::getClassInfo`. We need to store all four
+// class
+// * info versions if the plugin can provide them since we don't know
+// * which version of the interface the host will use. Will be
+// * `std::nullopt` if the plugin doesn't return a class info.
+// *
+// * NOTE: We'll have already converted all returned class IDs to
+// native
+// * class IDs using `WineUID::to_native_uid()` for
+// cross-platform
+// * compatibility. This applies to all `class_info_*` fields
+// here.
+// */
+// std::vector> class_infos_1;
+
+// /**
+// * For `IPluginFactory2::getClassInfo2`, works the same way as the
+// * above.
+// */
+// std::vector> class_infos_2;
+
+// /**
+// * For `IPluginFactory3::getClassInfoUnicode`, works the same way as
+// the
+// * above.
+// */
+// std::vector>
+// class_infos_unicode;
+
+// template
+// void serialize(S& s) {
+// s.value1b(supports_plugin_factory);
+// s.value1b(supports_plugin_factory_2);
+// s.value1b(supports_plugin_factory_3);
+// s.ext(factory_info, bitsery::ext::InPlaceOptional{});
+// s.value4b(num_classes);
+// s.container(class_infos_1, 2048,
+// [](S& s, std::optional& info)
+// {
+// s.ext(info, bitsery::ext::InPlaceOptional{});
+// });
+// s.container(class_infos_2, 2048,
+// [](S& s, std::optional& info)
+// {
+// s.ext(info, bitsery::ext::InPlaceOptional{});
+// });
+// s.container(class_infos_unicode, 2048,
+// [](S& s, std::optional& info)
+// {
+// s.ext(info, bitsery::ext::InPlaceOptional{});
+// });
+// }
+// };
+
+// /**
+// * Instantiate this instance with arguments read from the Windows VST3
+// * plugin's plugin factory.
+// */
+// YaPluginFactory3(ConstructArgs&& args) noexcept;
+
+// virtual ~YaPluginFactory3() noexcept = default;
+
+// inline bool supports_plugin_factory() const noexcept {
+// return arguments_.supports_plugin_factory;
+// }
+
+// inline bool supports_plugin_factory_2() const noexcept {
+// return arguments_.supports_plugin_factory_2;
+// }
+
+// inline bool supports_plugin_factory_3() const noexcept {
+// return arguments_.supports_plugin_factory_3;
+// }
+
+// // All of these functiosn returning class information are fetched once on
+// // the Wine side since they'll be static so we can just copy over the
+// // responses
+
+// // From `IPluginFactory`
+// tresult PLUGIN_API getFactoryInfo(Steinberg::PFactoryInfo* info)
+// override; int32 PLUGIN_API countClasses() override; tresult PLUGIN_API
+// getClassInfo(Steinberg::int32 index,
+// Steinberg::PClassInfo* info) override;
+// /**
+// * See the implementation in `Vst3PluginFactoryProxyImpl` for how this is
+// * handled. We'll create new managed `Vst3PluginProxy` objects from here.
+// */
+// virtual tresult PLUGIN_API createInstance(Steinberg::FIDString cid,
+// Steinberg::FIDString _iid,
+// void** obj) override = 0;
+
+// // From `IPluginFactory2`
+// tresult PLUGIN_API getClassInfo2(int32 index,
+// Steinberg::PClassInfo2* info) override;
+
+// // From `IPluginFactory3`
+// tresult PLUGIN_API
+// getClassInfoUnicode(int32 index, Steinberg::PClassInfoW* info) override;
+
+// /**
+// * Message to pass through a call to `IPluginFactory3::setHostContext()`
+// to
+// * the Wine plugin host. A `Vst3HostContextProxy` should be created on
+// the
+// * Wine plugin host and then passed as an argument to
+// * `IPluginFactory3::setHostContext()`.
+// */
+// struct SetHostContext {
+// using Response = UniversalTResult;
+
+// Vst3HostContextProxy::ConstructArgs host_context_args;
+
+// template
+// void serialize(S& s) {
+// s.object(host_context_args);
+// }
+// };
+
+// virtual tresult PLUGIN_API
+// setHostContext(Steinberg::FUnknown* context) override = 0;
+
+// protected:
+// ConstructArgs arguments_;
+// };
+
+// #pragma GCC diagnostic pop
+
+// // Serialization functions have to live in the same namespace as the objects
+// // they're serializing
+// namespace Steinberg {
+// template
+// void serialize(S& s, PClassInfo& class_info) {
+// s.container1b(class_info.cid);
+// s.value4b(class_info.cardinality);
+// s.text1b(class_info.category);
+// s.text1b(class_info.name);
+// }
+
+// template
+// void serialize(S& s, PClassInfo2& class_info) {
+// s.container1b(class_info.cid);
+// s.value4b(class_info.cardinality);
+// s.text1b(class_info.category);
+// s.text1b(class_info.name);
+// s.value4b(class_info.classFlags);
+// s.text1b(class_info.subCategories);
+// s.text1b(class_info.vendor);
+// s.text1b(class_info.version);
+// s.text1b(class_info.sdkVersion);
+// }
+
+// template
+// void serialize(S& s, PClassInfoW& class_info) {
+// s.container1b(class_info.cid);
+// s.value4b(class_info.cardinality);
+// s.text1b(class_info.category);
+// // FIXME: Bitsery uses `std::char_traits::length()` under the hood
+// // for `text2b()` on the Wine side, and under winegcc this function
+// // this length is incorrect. As a workaround we're just serializing
+// // the entire container. This applies to every place where we use
+// // `container2b()` to serialize a `String128`, so if we end up fixing
+// // this we should replace all of the instances of `container2b()`
+// // that serialize a `String128`.
+// s.container2b(class_info.name);
+// s.value4b(class_info.classFlags);
+// s.text1b(class_info.subCategories);
+// s.container2b(class_info.vendor);
+// s.container2b(class_info.version);
+// s.container2b(class_info.sdkVersion);
+// }
+
+// template
+// void serialize(S& s, PFactoryInfo& factory_info) {
+// s.text1b(factory_info.vendor);
+// s.text1b(factory_info.url);
+// s.text1b(factory_info.email);
+// s.value4b(factory_info.flags);
+// }
+// } // namespace Steinberg