Initial release

This commit is contained in:
civ
2026-08-16 18:24:52 +07:00
commit 876886a39a
13244 changed files with 2353959 additions and 0 deletions
@@ -0,0 +1,96 @@
//-----------------------------------------------------------------------------
// Project : SDK Core
// Version : 1.0
//
// Category : Common Base Classes
// Filename : public.sdk/source/main/dllmain.cpp
// Created by : Steinberg, 01/2004
// Description : Windows DLL Entry
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#include "pluginterfaces/base/ftypes.h"
#include "pluginterfaces/base/fstrdefs.h"
#include <windows.h>
#if defined(_MSC_VER) && defined(DEVELOPMENT)
#include <crtdbg.h>
#endif
//------------------------------------------------------------------------
HINSTANCE ghInst = nullptr;
void* moduleHandle = nullptr;
#define VST_MAX_PATH 2048
Steinberg::tchar gPath[VST_MAX_PATH] = {0};
//------------------------------------------------------------------------
extern bool InitModule (); ///< must be provided by plug-in: called when the library is loaded
extern bool DeinitModule (); ///< must be provided by plug-in: called when the library is unloaded
//------------------------------------------------------------------------
#ifdef __cplusplus
extern "C" {
#endif
static int moduleCounter {0}; // counting for InitDll/ExitDll pairs
//------------------------------------------------------------------------
/** must be called from host right after loading dll,
must be provided by the plug-in!
Note: this could be called more than one time! */
SMTG_EXPORT_SYMBOL bool InitDll ()
{
if (++moduleCounter == 1)
return InitModule ();
return true;
}
//------------------------------------------------------------------------
/** must be called from host right before unloading dll
must be provided by the plug-in!
Note: this could be called more than one time! */
SMTG_EXPORT_SYMBOL bool ExitDll ()
{
if (--moduleCounter == 0)
return DeinitModule ();
if (moduleCounter < 0)
return false;
return true;
}
#ifdef __cplusplus
} // extern "C"
#endif
//------------------------------------------------------------------------
BOOL WINAPI DllMain (HINSTANCE hInst, DWORD dwReason, LPVOID /*lpvReserved*/)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
#if defined(_MSC_VER) && defined(DEVELOPMENT)
_CrtSetReportMode (_CRT_WARN, _CRTDBG_MODE_DEBUG);
_CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_DEBUG);
_CrtSetReportMode (_CRT_ASSERT, _CRTDBG_MODE_DEBUG);
int flag = _CrtSetDbgFlag (_CRTDBG_REPORT_FLAG);
_CrtSetDbgFlag (flag | _CRTDBG_LEAK_CHECK_DF);
#endif
moduleHandle = ghInst = hInst;
// gets the path of the component
if (GetModuleFileName (ghInst, Steinberg::wscast (gPath), MAX_PATH) > 0)
{
Steinberg::tchar* bkslash = Steinberg::wscast (wcsrchr (Steinberg::wscast (gPath), L'\\'));
if (bkslash)
gPath[bkslash - gPath + 1] = 0;
}
}
return TRUE;
}
@@ -0,0 +1,62 @@
//-----------------------------------------------------------------------------
// Project : SDK Core
// Version : 1.0
//
// Category : Common Base Classes
// Filename : public.sdk/source/main/linuxmain.cpp
// Created by : Steinberg, 03/2017
// Description : Linux Component Entry
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#include "pluginterfaces/base/fplatform.h"
void* moduleHandle = nullptr;
//------------------------------------------------------------------------
bool InitModule (); ///< must be provided by plug-in: called when the library is loaded
bool DeinitModule (); ///< must be provided by plug-in: called when the library is unloaded
//------------------------------------------------------------------------
extern "C"
{
/** must be provided by the plug-in! */
SMTG_EXPORT_SYMBOL bool ModuleEntry (void*);
SMTG_EXPORT_SYMBOL bool ModuleExit (void);
}
static int moduleCounter {0}; // counting for ModuleEntry/ModuleExit pairs
//------------------------------------------------------------------------
/** must be called from host right after loading dll
Note: this could be called more than one time! */
bool ModuleEntry (void* sharedLibraryHandle)
{
if (++moduleCounter == 1)
{
moduleHandle = sharedLibraryHandle;
return InitModule ();
}
return true;
}
//------------------------------------------------------------------------
/** must be called from host right before unloading dll
Note: this could be called more than one time! */
bool ModuleExit (void)
{
if (--moduleCounter == 0)
{
moduleHandle = nullptr;
return DeinitModule ();
}
else if (moduleCounter < 0)
return false;
return true;
}
@@ -0,0 +1,96 @@
//-----------------------------------------------------------------------------
// Project : SDK Core
// Version : 1.0
//
// Category : Common Base Classes
// Filename : public.sdk/source/main/macmain.cpp
// Created by : Steinberg, 01/2004
// Description : Mac OS X Bundle Entry
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#include "pluginterfaces/base/fplatform.h"
#ifndef __CF_USE_FRAMEWORK_INCLUDES__
#define __CF_USE_FRAMEWORK_INCLUDES__ 1
#endif
#include <CoreFoundation/CoreFoundation.h>
//------------------------------------------------------------------------
CFBundleRef ghInst = nullptr;
int bundleRefCounter = 0; // counting for bundleEntry/bundleExit pairs
void* moduleHandle = nullptr;
#define VST_MAX_PATH 2048
char gPath[VST_MAX_PATH] = {0};
//------------------------------------------------------------------------
bool InitModule (); ///< must be provided by plug-in: called when the library is loaded
bool DeinitModule (); ///< must be provided by plug-in: called when the library is unloaded
//------------------------------------------------------------------------
extern "C" {
/** bundleEntry and bundleExit must be provided by the plug-in! */
SMTG_EXPORT_SYMBOL bool bundleEntry (CFBundleRef);
SMTG_EXPORT_SYMBOL bool bundleExit (void);
}
#include <vector>
std::vector<CFBundleRef> gBundleRefs;
//------------------------------------------------------------------------
/** must be called from host right after loading bundle
Note: this could be called more than one time! */
bool bundleEntry (CFBundleRef ref)
{
if (ref)
{
bundleRefCounter++;
CFRetain (ref);
// hold all bundle refs until plug-in is fully uninitialized
gBundleRefs.push_back (ref);
if (!moduleHandle)
{
ghInst = ref;
moduleHandle = ref;
// obtain the bundle path
CFURLRef tempURL = CFBundleCopyBundleURL (ref);
CFURLGetFileSystemRepresentation (tempURL, true, reinterpret_cast<UInt8*> (gPath), VST_MAX_PATH);
CFRelease (tempURL);
}
if (bundleRefCounter == 1)
return InitModule ();
}
return true;
}
//------------------------------------------------------------------------
/** must be called from host right before unloading bundle
Note: this could be called more than one time! */
bool bundleExit (void)
{
if (--bundleRefCounter == 0)
{
DeinitModule ();
// release the CFBundleRef's once all bundleExit clients called in
// there is no way to identify the proper CFBundleRef of the bundleExit call
for (size_t i = 0; i < gBundleRefs.size (); i++)
CFRelease (gBundleRefs[i]);
gBundleRefs.clear ();
}
else if (bundleRefCounter < 0)
return false;
return true;
}
@@ -0,0 +1,103 @@
//-----------------------------------------------------------------------------
// Project : SDK Core
//
// Category : Common Base Classes
// Filename : public.sdk/source/main/moduleinit.cpp
// Created by : Steinberg, 11/2020
// Description : Module Initializers/Terminators
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#include "moduleinit.h"
#include <atomic>
#include <vector>
extern void* moduleHandle; // from dllmain.cpp, linuxmain.cpp or macmain.cpp
//------------------------------------------------------------------------
namespace Steinberg {
namespace {
//------------------------------------------------------------------------
using FunctionVector = std::vector<std::pair<ModuleInitPriority, ModuleInitFunction>>;
//------------------------------------------------------------------------
FunctionVector& getInitFunctions ()
{
static FunctionVector gInitVector;
return gInitVector;
}
//------------------------------------------------------------------------
FunctionVector& getTermFunctions ()
{
static FunctionVector gTermVector;
return gTermVector;
}
//------------------------------------------------------------------------
void addInitFunction (ModuleInitFunction&& func, ModuleInitPriority prio)
{
getInitFunctions ().emplace_back (prio, std::move (func));
}
//------------------------------------------------------------------------
void addTerminateFunction (ModuleInitFunction&& func, ModuleInitPriority prio)
{
getTermFunctions ().emplace_back (prio, std::move (func));
}
//------------------------------------------------------------------------
void sortAndRunFunctions (FunctionVector& array)
{
std::sort (array.begin (), array.end (),
[] (const FunctionVector::value_type& v1, const FunctionVector::value_type& v2) {
return v1.first < v2.first;
});
for (auto& entry : array)
entry.second ();
}
//------------------------------------------------------------------------
} // anonymous
//------------------------------------------------------------------------
ModuleInitializer::ModuleInitializer (ModuleInitFunction&& func, ModuleInitPriority prio)
{
addInitFunction (std::move (func), prio);
}
//------------------------------------------------------------------------
ModuleTerminator::ModuleTerminator (ModuleInitFunction&& func, ModuleInitPriority prio)
{
addTerminateFunction (std::move (func), prio);
}
//------------------------------------------------------------------------
PlatformModuleHandle getPlatformModuleHandle ()
{
return reinterpret_cast<PlatformModuleHandle> (moduleHandle);
}
//------------------------------------------------------------------------
} // Steinberg
//------------------------------------------------------------------------
bool InitModule ()
{
Steinberg::sortAndRunFunctions (Steinberg::getInitFunctions ());
return true;
}
//------------------------------------------------------------------------
bool DeinitModule ()
{
Steinberg::sortAndRunFunctions (Steinberg::getTermFunctions ());
return true;
}
@@ -0,0 +1,93 @@
//-----------------------------------------------------------------------------
// Project : SDK Core
//
// Category : Common Base Classes
// Filename : public.sdk/source/main/moduleinit.h
// Created by : Steinberg, 11/2020
// Description : Module Initializers/Terminators
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#pragma once
#include "pluginterfaces/base/ftypes.h"
#include <algorithm>
#include <functional>
#include <limits>
#include <numeric>
//------------------------------------------------------------------------
/** A replacement for InitModule and DeinitModule
*
* If you link this file the InitModule and DeinitModule functions are
* implemented and you can use this to register functions that will be
* called when the module is loaded and before the module is unloaded.
*
* Use this for one time initializers or cleanup functions.
* For example: if you depend on a 3rd party library that needs
* initialization before you can use it you can write an initializer like this:
*
* static ModuleInitializer InitMyExternalLib ([] () { MyExternalLib::init (); });
*
* Or you have a lazy create wavetable you need to free the allocated memory later:
*
* static ModuleTerminator FreeWaveTableMemory ([] () { MyWaveTable::free (); });
*/
//------------------------------------------------------------------------
#if SMTG_OS_WINDOWS
using HINSTANCE = struct HINSTANCE__*;
namespace Steinberg { using PlatformModuleHandle = HINSTANCE; }
//------------------------------------------------------------------------
#elif SMTG_OS_OSX || SMTG_OS_IOS
typedef struct __CFBundle* CFBundleRef;
namespace Steinberg { using PlatformModuleHandle = CFBundleRef; }
//------------------------------------------------------------------------
#elif SMTG_OS_LINUX
namespace Steinberg { using PlatformModuleHandle = void*; }
#endif
//------------------------------------------------------------------------
namespace Steinberg {
using ModuleInitFunction = std::function<void ()>;
using ModuleInitPriority = uint32;
static constexpr ModuleInitPriority DefaultModulePriority =
std::numeric_limits<ModuleInitPriority>::max () / 2;
//------------------------------------------------------------------------
struct ModuleInitializer
{
/**
* Register a function which is called when the module is loaded
* @param func function to call
* @param prio priority
*/
ModuleInitializer (ModuleInitFunction&& func,
ModuleInitPriority prio = DefaultModulePriority);
};
//------------------------------------------------------------------------
struct ModuleTerminator
{
/**
* Register a function which is called when the module is unloaded
* @param func function to call
* @param prio priority
*/
ModuleTerminator (ModuleInitFunction&& func,
ModuleInitPriority prio = DefaultModulePriority);
};
//------------------------------------------------------------------------
PlatformModuleHandle getPlatformModuleHandle ();
//------------------------------------------------------------------------
} // Steinberg
@@ -0,0 +1,340 @@
//-----------------------------------------------------------------------------
// Project : SDK Core
//
// Category : Common Base Classes
// Filename : public.sdk/source/main/pluginfactory.cpp
// Created by : Steinberg, 01/2004
// Description : Standard Plug-In Factory
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#include "pluginfactory.h"
#if SMTG_OS_LINUX
#include "pluginterfaces/base/funknownimpl.h"
#include "pluginterfaces/gui/iplugview.h"
#include "base/source/timer.h"
#endif
#include <algorithm>
#include <cstdlib>
namespace Steinberg {
DEF_CLASS_IID (IPluginFactoryInternal);
CPluginFactory* gPluginFactory = nullptr;
//------------------------------------------------------------------------
// CPluginFactory implementation
//------------------------------------------------------------------------
CPluginFactory::CPluginFactory (const PFactoryInfo& info)
: classes (nullptr), classCount (0), maxClassCount (0)
{
FUNKNOWN_CTOR
factoryInfo = info;
}
//------------------------------------------------------------------------
CPluginFactory::~CPluginFactory ()
{
if (gPluginFactory == this)
gPluginFactory = nullptr;
if (classes)
free (classes);
FUNKNOWN_DTOR
}
//------------------------------------------------------------------------
IMPLEMENT_REFCOUNT (CPluginFactory)
//------------------------------------------------------------------------
tresult PLUGIN_API CPluginFactory::queryInterface (FIDString _iid, void** obj)
{
QUERY_INTERFACE (_iid, obj, IPluginFactory::iid, IPluginFactory)
QUERY_INTERFACE (_iid, obj, IPluginFactory2::iid, IPluginFactory2)
QUERY_INTERFACE (_iid, obj, IPluginFactory3::iid, IPluginFactory3)
QUERY_INTERFACE (_iid, obj, IPluginFactoryInternal::iid, IPluginFactoryInternal)
QUERY_INTERFACE (_iid, obj, FUnknown::iid, IPluginFactory)
*obj = nullptr;
return kNoInterface;
}
//------------------------------------------------------------------------
bool CPluginFactory::registerClass (const PClassInfo* info, FUnknown* (*createFunc) (void*),
void* context)
{
if (!info || !createFunc)
return false;
PClassInfo2 info2;
memcpy (&info2, info, sizeof (PClassInfo));
return registerClass (&info2, createFunc, context);
}
//------------------------------------------------------------------------
bool CPluginFactory::registerClass (const PClassInfo2* info, FUnknown* (*createFunc) (void*),
void* context)
{
if (!info || !createFunc)
return false;
if (classCount >= maxClassCount)
{
if (!growClasses ())
return false;
}
PClassEntry& entry = classes[classCount];
entry.info8 = *info;
entry.info16.fromAscii (*info);
entry.createFunc = createFunc;
entry.context = context;
entry.isUnicode = false;
classCount++;
return true;
}
//------------------------------------------------------------------------
bool CPluginFactory::registerClass (const PClassInfoW* info, FUnknown* (*createFunc) (void*),
void* context)
{
if (!info || !createFunc)
return false;
if (classCount >= maxClassCount)
{
if (!growClasses ())
return false;
}
PClassEntry& entry = classes[classCount];
entry.info16 = *info;
entry.createFunc = createFunc;
entry.context = context;
entry.isUnicode = true;
classCount++;
return true;
}
//------------------------------------------------------------------------
bool CPluginFactory::growClasses ()
{
static const int32 delta = 10;
size_t size = (maxClassCount + delta) * sizeof (PClassEntry);
void* memory = classes;
if (!memory)
memory = malloc (size);
else
memory = realloc (memory, size);
if (!memory)
return false;
classes = static_cast<PClassEntry*> (memory);
maxClassCount += delta;
return true;
}
//------------------------------------------------------------------------
bool CPluginFactory::isClassRegistered (const FUID& cid)
{
for (int32 i = 0; i < classCount; i++)
{
if (FUnknownPrivate::iidEqual (cid, classes[i].info16.cid))
return true;
}
return false;
}
//------------------------------------------------------------------------
void CPluginFactory::removeAllClasses ()
{
classCount = 0;
}
//------------------------------------------------------------------------
tresult PLUGIN_API CPluginFactory::getFactoryInfo (PFactoryInfo* info)
{
if (info)
memcpy (info, &factoryInfo, sizeof (PFactoryInfo));
return kResultOk;
}
//------------------------------------------------------------------------
int32 PLUGIN_API CPluginFactory::countClasses ()
{
return classCount;
}
//------------------------------------------------------------------------
tresult PLUGIN_API CPluginFactory::getClassInfo (int32 index, PClassInfo* info)
{
if (info && (index >= 0 && index < classCount))
{
if (classes[index].isUnicode)
{
memset (info, 0, sizeof (PClassInfo));
return kResultFalse;
}
memcpy (info, &classes[index].info8, sizeof (PClassInfo));
return kResultOk;
}
return kInvalidArgument;
}
//------------------------------------------------------------------------
tresult PLUGIN_API CPluginFactory::getClassInfo2 (int32 index, PClassInfo2* info)
{
if (info && (index >= 0 && index < classCount))
{
if (classes[index].isUnicode)
{
memset (info, 0, sizeof (PClassInfo2));
return kResultFalse;
}
memcpy (info, &classes[index].info8, sizeof (PClassInfo2));
return kResultOk;
}
return kInvalidArgument;
}
//------------------------------------------------------------------------
tresult PLUGIN_API CPluginFactory::getClassInfoUnicode (int32 index, PClassInfoW* info)
{
if (info && (index >= 0 && index < classCount))
{
memcpy (info, &classes[index].info16, sizeof (PClassInfoW));
return kResultOk;
}
return kInvalidArgument;
}
//------------------------------------------------------------------------
tresult PLUGIN_API CPluginFactory::createInstance (FIDString cid, FIDString _iid, void** obj)
{
for (int32 i = 0; i < classCount; i++)
{
if (memcmp (classes[i].info16.cid, cid, sizeof (TUID)) == 0)
{
FUnknown* instance = classes[i].createFunc (classes[i].context);
if (instance)
{
if (instance->queryInterface (_iid, obj) == kResultOk)
{
instance->release ();
return kResultOk;
}
instance->release ();
}
break;
}
}
*obj = nullptr;
return kNoInterface;
}
#if SMTG_OS_LINUX
//------------------------------------------------------------------------
namespace /*anonymous*/ {
//------------------------------------------------------------------------
class LinuxPlatformTimer : public U::Extends<Timer, U::Directly<Linux::ITimerHandler>>
{
public:
~LinuxPlatformTimer () noexcept override { stop (); }
tresult init (ITimerCallback* cb, uint32 timeout)
{
if (!runLoop || cb == nullptr || timeout == 0)
return kResultFalse;
auto result = runLoop->registerTimer (this, timeout);
if (result == kResultTrue)
{
callback = cb;
timerRegistered = true;
}
return result;
}
void PLUGIN_API onTimer () override { callback->onTimer (this); }
void stop () override
{
if (timerRegistered)
{
if (runLoop)
runLoop->unregisterTimer (this);
timerRegistered = false;
}
}
bool timerRegistered {false};
ITimerCallback* callback;
static IPtr<Linux::IRunLoop> runLoop;
};
IPtr<Linux::IRunLoop> LinuxPlatformTimer::runLoop;
//------------------------------------------------------------------------
Timer* createLinuxTimer (ITimerCallback* cb, uint32 milliseconds)
{
if (!LinuxPlatformTimer::runLoop)
return nullptr;
auto timer = NEW LinuxPlatformTimer;
if (timer->init (cb, milliseconds) == kResultTrue)
return timer;
timer->release ();
return nullptr;
}
} // anonymous
#endif // SMTG_OS_LINUX
//------------------------------------------------------------------------
tresult PLUGIN_API CPluginFactory::setHostContext (FUnknown* context)
{
std::for_each (hostContextCallbacks.begin (), hostContextCallbacks.end (),
[context] (const auto& cb) { cb (context); });
#if SMTG_OS_LINUX
if (auto runLoop = U::cast<Linux::IRunLoop> (context))
{
LinuxPlatformTimer::runLoop = runLoop;
InjectCreateTimerFunction (createLinuxTimer);
}
else
{
LinuxPlatformTimer::runLoop.reset ();
InjectCreateTimerFunction (nullptr);
}
return kResultTrue;
#else
(void) context;
return kNotImplemented;
#endif
}
//------------------------------------------------------------------------
void PLUGIN_API CPluginFactory::addHostContextCallback (HostContextCallbackFunc func)
{
hostContextCallbacks.push_back (func);
}
//------------------------------------------------------------------------
} // namespace Steinberg
@@ -0,0 +1,191 @@
//------------------------------------------------------------------------
// Project : SDK Core
//
// Category : Common Base Classes
// Filename : public.sdk/source/main/pluginfactory.h
// Created by : Steinberg, 01/2004
// Description : Standard Plug-In Factory
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#pragma once
#include "pluginterfaces/base/ipluginbase.h"
#include <vector>
namespace Steinberg {
//------------------------------------------------------------------------
class IPluginFactoryInternal : public FUnknown
{
public:
using HostContextCallbackFunc = void (*) (FUnknown*);
virtual void PLUGIN_API addHostContextCallback (HostContextCallbackFunc func) = 0;
//------------------------------------------------------------------------
static const FUID iid;
};
DECLARE_CLASS_IID (IPluginFactoryInternal, 0x5A6AD11A, 0x22AF40F3, 0xBCA1C147, 0x506C88D9)
//------------------------------------------------------------------------
/** Default Class Factory implementation.
\ingroup sdkBase
\see classFactoryMacros
*/
class CPluginFactory : public IPluginFactory3, public IPluginFactoryInternal
{
public:
//------------------------------------------------------------------------
CPluginFactory (const PFactoryInfo& info);
virtual ~CPluginFactory ();
//--- ---------------------------------------------------------------------
/** Registers a plug-in class with classInfo version 1, returns true for success. */
bool registerClass (const PClassInfo* info, FUnknown* (*createFunc) (void*),
void* context = nullptr);
/** Registers a plug-in class with classInfo version 2, returns true for success. */
bool registerClass (const PClassInfo2* info, FUnknown* (*createFunc) (void*),
void* context = nullptr);
/** Registers a plug-in class with classInfo Unicode version, returns true for success. */
bool registerClass (const PClassInfoW* info, FUnknown* (*createFunc) (void*),
void* context = nullptr);
/** Check if a class for a given classId is already registered. */
bool isClassRegistered (const FUID& cid);
/** Remove all classes (no class exported) */
void removeAllClasses ();
//------------------------------------------------------------------------
DECLARE_FUNKNOWN_METHODS
//---from IPluginFactory------
tresult PLUGIN_API getFactoryInfo (PFactoryInfo* info) SMTG_OVERRIDE;
int32 PLUGIN_API countClasses () SMTG_OVERRIDE;
tresult PLUGIN_API getClassInfo (int32 index, PClassInfo* info) SMTG_OVERRIDE;
tresult PLUGIN_API createInstance (FIDString cid, FIDString _iid, void** obj) SMTG_OVERRIDE;
//---from IPluginFactory2-----
tresult PLUGIN_API getClassInfo2 (int32 index, PClassInfo2* info) SMTG_OVERRIDE;
//---from IPluginFactory3-----
tresult PLUGIN_API getClassInfoUnicode (int32 index, PClassInfoW* info) SMTG_OVERRIDE;
tresult PLUGIN_API setHostContext (FUnknown* context) SMTG_OVERRIDE;
//---from IPluginFactoryInternal
void PLUGIN_API addHostContextCallback (HostContextCallbackFunc func) SMTG_OVERRIDE;
//------------------------------------------------------------------------
protected:
/// @cond
struct PClassEntry
{
//-----------------------------------
PClassInfo2 info8;
PClassInfoW info16;
FUnknown* (*createFunc) (void*);
void* context;
bool isUnicode;
//-----------------------------------
};
/// @endcond
PFactoryInfo factoryInfo;
PClassEntry* classes;
int32 classCount;
int32 maxClassCount;
std::vector<HostContextCallbackFunc> hostContextCallbacks;
bool growClasses ();
};
extern CPluginFactory* gPluginFactory;
//------------------------------------------------------------------------
} // namespace Steinberg
//------------------------------------------------------------------------
/** \defgroup classFactoryMacros Macros for defining the class factory
\ingroup sdkBase
\b Example - How to use the class factory macros:
\code
BEGIN_FACTORY ("Steinberg Technologies",
"http://www.steinberg.de",
"mailto:info@steinberg.de",
PFactoryInfo::kNoFlags)
DEF_CLASS (INLINE_UID (0x00000000, 0x00000000, 0x00000000, 0x00000000),
PClassInfo::kManyInstances,
"Service",
"Test Service",
TestService::newInstance)
END_FACTORY
\endcode
@{*/
#define BEGIN_FACTORY_CLASS(FactoryClass,vendor,url,email,flags) using namespace Steinberg; \
SMTG_EXPORT_SYMBOL IPluginFactory* PLUGIN_API GetPluginFactory () { \
if (!gPluginFactory) \
{ static PFactoryInfo factoryInfo (vendor,url,email,flags); \
gPluginFactory = new FactoryClass (factoryInfo); \
#define BEGIN_FACTORY(vendor,url,email,flags) using namespace Steinberg; \
SMTG_EXPORT_SYMBOL IPluginFactory* PLUGIN_API GetPluginFactory () { \
if (!gPluginFactory) \
{ static PFactoryInfo factoryInfo (vendor,url,email,flags); \
gPluginFactory = new CPluginFactory (factoryInfo); \
#define DEF_CLASS(cid,cardinality,category,name,createMethod) \
{ TUID lcid = cid; static PClassInfo componentClass (lcid,cardinality,category,name); \
gPluginFactory->registerClass (&componentClass,createMethod); }
#define DEF_CLASS1(cid,cardinality,category,name,createMethod) \
{ static PClassInfo componentClass (cid,cardinality,category,name); \
gPluginFactory->registerClass (&componentClass,createMethod); }
#define DEF_CLASS2(cid,cardinality,category,name,classFlags,subCategories,version,sdkVersion,createMethod) \
{ TUID lcid = cid; static PClassInfo2 componentClass (lcid,cardinality,category,name,classFlags,subCategories,nullptr,version,sdkVersion);\
gPluginFactory->registerClass (&componentClass,createMethod); }
#define DEF_CLASS_W(cid,cardinality,category,name,classFlags,subCategories,version,sdkVersion,createMethod) \
{ TUID lcid = cid; static PClassInfoW componentClass (lcid,cardinality,category,name,classFlags,subCategories,nullptr,version,sdkVersion);\
gPluginFactory->registerClass (&componentClass,createMethod); }
#define DEF_CLASS_W2(cid,cardinality,category,name,classFlags,subCategories,vendor,version,sdkVersion,createMethod) \
{ TUID lcid = cid; static PClassInfoW componentClass (lcid,cardinality,category,name,classFlags,subCategories,vendor,version,sdkVersion);\
gPluginFactory->registerClass (&componentClass,createMethod); }
#define END_FACTORY } else gPluginFactory->addRef (); \
return gPluginFactory; }
#define DEF_VST3_CLASS(pluginName, pluginVst3Categories, classFlags, pluginVersion, processorCID, \
processorCreateFunc, controllerCID, controllerCreateFunc) \
{ \
{ \
const Steinberg::TUID lcid = processorCID; \
static Steinberg::PClassInfo2 processorClass ( \
lcid, Steinberg::PClassInfo::kManyInstances, kVstAudioEffectClass, pluginName, \
classFlags, pluginVst3Categories, 0, pluginVersion, kVstVersionString); \
gPluginFactory->registerClass (&processorClass, processorCreateFunc); \
} \
{ \
const Steinberg::TUID lcid = controllerCID; \
static Steinberg::PClassInfo2 controllerClass ( \
lcid, Steinberg::PClassInfo::kManyInstances, kVstComponentControllerClass, \
pluginName, 0, "", 0, pluginVersion, kVstVersionString); \
gPluginFactory->registerClass (&controllerClass, controllerCreateFunc); \
} \
}
/** @} */
@@ -0,0 +1,201 @@
//------------------------------------------------------------------------
// Flags : clang-format SMTGSequencer
// Project : SDK Core
//
// Category : Common Base Classes
// Filename : public.sdk/source/main/pluginfactory_constexpr.h
// Created by : Steinberg, 10/2021
// Description : Standard Plug-In Factory (constexpr variant)
//
//-----------------------------------------------------------------------------
// This file is part of a Steinberg SDK. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this distribution
// and at www.steinberg.net/sdklicenses.
// No part of the SDK, including this file, may be copied, modified, propagated,
// or distributed except according to the terms contained in the LICENSE file.
//-----------------------------------------------------------------------------
#pragma once
#include "pluginterfaces/base/funknownimpl.h"
#include "pluginterfaces/base/ipluginbase.h"
#if !SMTG_CPP17
#error "C++17 is required for this header"
#endif
#include <array>
namespace Steinberg {
//------------------------------------------------------------------------
/** IPluginFactory implementation with compile time provided factory and class infos.
\ingroup sdkBase
\see \ref constexprClassFactoryMacros
You can use this factory when your number of classes are known during compile time. The
advantage here is that during runtime no unnecessary setup is needed.
Please note that this only supports ASCII names and thus if you need to support Unicode names
you must use another implementation.
This only works when compiling with c++17 or newer.
*/
template <typename T>
class PluginFactory
: public U::ImplementsNonDestroyable<U::Directly<IPluginFactory2>, U::Indirectly<IPluginFactory>>
{
public:
//------------------------------------------------------------------------
tresult PLUGIN_API getFactoryInfo (PFactoryInfo* info) override
{
if (info == nullptr)
return kInvalidArgument;
*info = T::factoryInfo;
return kResultTrue;
}
int32 PLUGIN_API countClasses () override { return static_cast<int32> (T::classInfos.size ()); }
tresult PLUGIN_API getClassInfo (int32 index, PClassInfo* info) override
{
if (index < 0 || index >= static_cast<int32> (T::classInfos.size ()) || info == nullptr)
return kInvalidArgument;
*info = {};
const auto& ci = T::classInfos[index];
copyTUID (info->cid, ci.cid);
info->cardinality = ci.cardinality;
if (ci.category)
strncpy (info->category, ci.category, PClassInfo::kCategorySize);
if (ci.name)
strncpy (info->name, ci.name, PClassInfo::kNameSize);
return kResultTrue;
}
tresult PLUGIN_API createInstance (FIDString cid, FIDString iid, void** obj) override
{
for (const auto& e : T::classInfos)
{
if (FUnknownPrivate::iidEqual (e.cid, cid))
{
if (auto instance = e.create (e.context))
{
if (instance->queryInterface (iid, obj) == kResultOk)
{
instance->release ();
return kResultOk;
}
else
instance->release ();
}
}
}
*obj = nullptr;
return kNoInterface;
}
tresult PLUGIN_API getClassInfo2 (int32 index, PClassInfo2* info) override
{
if (index < 0 || index >= static_cast<int32> (T::classInfos.size ()) || info == nullptr)
return kInvalidArgument;
*info = T::classInfos[index];
return kResultTrue;
}
};
//------------------------------------------------------------------------
namespace PluginFactoryDetail {
//------------------------------------------------------------------------
struct ClassInfo2WithCreateFunc : PClassInfo2
{
using CreateInstanceFunc = FUnknown* (*)(void*);
CreateInstanceFunc create {nullptr};
void* context {nullptr};
};
//------------------------------------------------------------------------
inline constexpr ClassInfo2WithCreateFunc makeClassInfo2 (
const TUID cid, int32 cardinality, const char8* category, const char8* name, int32 classFlags,
const char8* subCategories, const char8* vendor, const char8* version, const char8* sdkVersion,
ClassInfo2WithCreateFunc::CreateInstanceFunc func, void* context = nullptr)
{
ClassInfo2WithCreateFunc classInfo {};
copyTUID (classInfo.cid, cid);
classInfo.cardinality = cardinality;
strncpy8 (classInfo.category, category, PClassInfo::kCategorySize);
strncpy8 (classInfo.name, name, PClassInfo::kNameSize);
classInfo.classFlags = classFlags;
if (subCategories)
strncpy8 (classInfo.subCategories, subCategories, PClassInfo2::kSubCategoriesSize);
if (vendor)
strncpy8 (classInfo.vendor, vendor, PClassInfo2::kVendorSize);
if (version)
strncpy8 (classInfo.version, version, PClassInfo2::kVersionSize);
if (sdkVersion)
strncpy8 (classInfo.sdkVersion, sdkVersion, PClassInfo2::kVersionSize);
classInfo.create = func;
classInfo.context = context;
return classInfo;
}
//------------------------------------------------------------------------
} // namespace PluginFactoryDetail
} // namespace Steinberg
#ifdef BEGIN_FACTORY_DEF
#undef BEGIN_FACTORY_DEF
#endif
/** \defgroup constexprClassFactoryMacros Macros for defining the compile time class factory
\ingroup sdkBase
\b Example:
\code
static constexpr size_t numberOfClasses = 1;
static DECLARE_UID (TestPluginUID, 0x00000001, 0x00000002, 0x00000003, 0x00000004);
BEGIN_FACTORY_DEF ("MyCompany", "mycompany.com", "info@mycompany.com", numberOfClasses)
DEF_CLASS (TestPluginUID,
PClassInfo::kManyInstances,
"PlugIn",
"Test PlugIn",
0,
"SubCategory",
"1.0.0",
stringSDKVersion,
TestPlugin::newInstance,
nullptr)
END_FACTORY
\endcode
@{*/
// clang-format off
#define BEGIN_FACTORY_DEF(company, url, email, noClasses) \
struct SMTG_HIDDEN_SYMBOL FactoryData \
{ \
static constexpr Steinberg::PFactoryInfo factoryInfo = { \
company, url, email, Steinberg::PFactoryInfo::kUnicode}; \
\
static constexpr std::array<Steinberg::PluginFactoryDetail::ClassInfo2WithCreateFunc, \
noClasses> \
classInfos = {
#define DEF_CLASS(cid, cardinality, category, name, classFlags, subCategories, version, \
sdkVersion, createMethod, createContext) \
Steinberg::PluginFactoryDetail::makeClassInfo2 (cid, cardinality, category, name, classFlags, \
subCategories, nullptr, version, sdkVersion, \
createMethod, createContext),
#define END_FACTORY \
};}; \
SMTG_EXPORT_SYMBOL Steinberg::IPluginFactory* PLUGIN_API GetPluginFactory () \
{ \
static Steinberg::PluginFactory<FactoryData> factory; \
return &factory; \
}
// clang-format on
/** @} */