37#include "public.sdk/source/vst/utility/optional.h"
38#include "public.sdk/source/vst/utility/stringconvert.h"
39#include "public.sdk/source/vst/hosting/module.h"
47#if _HAS_CXX17 && defined(_MSC_VER)
48#if __has_include(<filesystem>)
49#define USE_FILESYSTEM 1
50#elif __has_include(<experimental/filesystem>)
51#define USE_FILESYSTEM 0
54#define USE_FILESYSTEM 0
57#if USE_FILESYSTEM == 1
59namespace filesystem = std::filesystem;
64#define _SILENCE_EXPERIMENTAL_FILESYSTEM_DEPRECATION_WARNING
65#include <experimental/filesystem>
66namespace filesystem = std::experimental::filesystem;
69#pragma comment(lib, "Shell32")
80 static_assert(
sizeof(T) ==
sizeof(Steinberg::Vst::TChar));
81 return VST3::StringConvert::convert(
82 static_cast<const Steinberg::Vst::TChar*
>(
static_cast<const void*
>(
str)));
92#if SMTG_OS_WINDOWS_ARM
100#define USE_OLE !USE_FILESYSTEM
114 static Ole gInstance;
119 Ole () { OleInitialize (
nullptr); }
120 ~Ole () { OleUninitialize (); }
128 template <
typename T>
131 return reinterpret_cast<T
> (GetProcAddress (mModule,
name));
136 factory = PluginFactory (
nullptr);
141 if (
auto dllExit = getFunctionPointer<ExitModuleFunc> (
"ExitDll"))
144 FreeLibrary ((HMODULE)mModule);
148 bool load (
const std::string& inPath, std::string& errorDescription)
override
150 auto wideStr = StringConvert::convert (inPath);
151 mModule = LoadLibraryW (
reinterpret_cast<LPCWSTR
> (wideStr.data ()));
154 filesystem::path p (inPath);
155 auto filename = p.filename ();
159 wideStr = StringConvert::convert (p.string ());
160 mModule = LoadLibraryW (
reinterpret_cast<LPCWSTR
> (wideStr.data ()));
163 auto lastError = GetLastError ();
164 LPVOID lpMessageBuffer;
165 FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
166 nullptr, lastError, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
167 (LPSTR)&lpMessageBuffer, 0,
nullptr);
168 errorDescription =
"LoadLibray failed: " + std::string ((
char*)lpMessageBuffer);
169 LocalFree (lpMessageBuffer);
174 auto factoryProc = getFunctionPointer<GetFactoryProc> (
"GetPluginFactory");
177 errorDescription =
"The dll does not export the required 'GetPluginFactory' function";
181 auto dllEntry = getFunctionPointer<InitModuleFunc> (
"InitDll");
182 if (dllEntry && !dllEntry ())
184 errorDescription =
"Calling 'InitDll' failed";
187 auto f = Steinberg::FUnknownPtr<Steinberg::IPluginFactory> (owned (factoryProc ()));
190 errorDescription =
"Calling 'GetPluginFactory' returned nullptr";
197 HINSTANCE mModule {
nullptr};
203 auto filename = p.filename ();
207 auto hFile = CreateFileW (
reinterpret_cast<LPCWSTR
> (p.c_str ()), GENERIC_READ, FILE_SHARE_READ,
208 nullptr, OPEN_EXISTING, 0,
nullptr);
209 if (hFile != INVALID_HANDLE_VALUE)
221 if ( filesystem::is_symlink (p))
224 std::wstring wString = p.generic_wstring ();
225 auto attrib = GetFileAttributesW (
reinterpret_cast<LPCWSTR
> (wString.c_str ()));
226 if (attrib & FILE_ATTRIBUTE_REPARSE_POINT)
228 auto hFile = CreateFileW (
reinterpret_cast<LPCWSTR
> (wString.c_str ()), GENERIC_READ,
229 FILE_SHARE_READ,
nullptr, OPEN_EXISTING, 0,
nullptr);
230 if (hFile == INVALID_HANDLE_VALUE)
243 if (FAILED (SHGetKnownFolderPath (folderID, 0,
nullptr, &wideStr)))
252 return {filesystem::read_symlink (p)};
257 IShellLink* shellLink =
nullptr;
258 if (!SUCCEEDED (CoCreateInstance (CLSID_ShellLink,
nullptr, CLSCTX_INPROC_SERVER,
259 IID_IShellLink,
reinterpret_cast<LPVOID*
> (&shellLink))))
262 IPersistFile* persistFile =
nullptr;
264 shellLink->QueryInterface (IID_IPersistFile,
reinterpret_cast<void**
> (&persistFile))))
267 if (!SUCCEEDED (persistFile->Load (p.wstring ().data (), STGM_READ)))
270 if (!SUCCEEDED (shellLink->Resolve (
nullptr, MAKELONG (SLR_NO_UI, 500))))
273 WCHAR resolvedPath[MAX_PATH];
274 if (!SUCCEEDED (shellLink->GetPath (resolvedPath, MAX_PATH,
nullptr, SLGP_SHORTPATH)))
277 std::wstring longPath;
278 longPath.resize (MAX_PATH);
280 GetLongPathNameW (resolvedPath,
const_cast<wchar_t*
> (longPath.data ()), MAX_PATH);
283 longPath.resize (numChars);
285 persistFile->Release ();
286 shellLink->Release ();
288 return {filesystem::path (longPath)};
298 Module::PathList& pathList,
bool recursive =
true)
300 for (
auto& p : filesystem::directory_iterator (path))
303 filesystem::path finalPath (p);
309 if (!filesystem::exists (finalPath))
315 const auto& cpExt = finalPath.extension ();
318 filesystem::path vstPath (finalPath);
321 pathList.push_back (vstPath.generic_string ());
326 if (filesystem::is_directory (finalPath))
331 else if (cpExt == ext)
332 pathList.push_back (finalPath.generic_string ());
334 const auto& cp = p.path ();
335 const auto& cpExt = cp.extension ();
338 if ((p.status ().type () == filesystem::file_type::directory) ||
341 filesystem::path finalPath (p);
344 pathList.push_back (finalPath.generic_u8string ());
350 pathList.push_back (cp.generic_u8string ());
354 if (p.status ().type () == filesystem::file_type::directory)
358 else if (cpExt ==
".lnk")
362 if (resolvedLink->extension () == ext)
364 if (filesystem::is_directory (*resolvedLink) ||
367 filesystem::path finalPath (*resolvedLink);
370 pathList.push_back (finalPath.generic_u8string ());
376 pathList.push_back (resolvedLink->generic_u8string ());
378 else if (filesystem::is_directory (*resolvedLink))
380 const auto&
str = resolvedLink->generic_u8string ();
381 if (cp.generic_u8string ().compare (0,
str.size (),
str.data (),
393void findModules (
const filesystem::path& path, Module::PathList& pathList)
395 if (filesystem::exists (path))
401 const std::string& modulePath)
403 filesystem::path path (modulePath);
405 path = path.parent_path ();
408 path = path.parent_path ();
409 if (path.filename () !=
"Contents")
412 return Optional<filesystem::path> {std::move (path)};
419Module::Ptr Module::create (
const std::string& path, std::string& errorDescription)
421 auto _module = std::make_shared<Win32Module> ();
422 if (_module->load (path, errorDescription))
424 _module->path = path;
425 auto it = std::find_if (path.rbegin (), path.rend (),
426 [] (
const std::string::value_type& c) { return c ==
'/'; });
427 if (it != path.rend ())
428 _module->name = {it.base (), path.end ()};
435Module::PathList Module::getModulePaths ()
439 if (
auto knownFolder =
getKnownFolder (FOLDERID_ProgramFilesCommon))
441 filesystem::path p (*knownFolder);
447 WCHAR modulePath[MAX_PATH + 1];
448 GetModuleFileNameW (
nullptr, modulePath, MAX_PATH);
450 filesystem::path path (appPath);
451 path = path.parent_path ();
452 path = path.append (
"VST3");
459Module::SnapshotList Module::getSnapshots (
const std::string& modulePath)
466 *path /=
"Resources";
467 *path /=
"Snapshots";
469 if (filesystem::exists (*path) ==
false)
474 for (
auto& png : pngList)
476 filesystem::path p (png);
477 auto filename = p.filename ().generic_string ();
478 auto uid = Snapshot::decodeUID (filename);
481 auto scaleFactor = 1.;
482 if (
auto decodedScaleFactor = Snapshot::decodeScaleFactor (filename))
483 scaleFactor = *decodedScaleFactor;
485 Module::Snapshot::ImageDesc
desc;
486 desc.scaleFactor = scaleFactor;
487 desc.path = std::move (png);
489 for (
auto&
entry : result)
491 if (
entry.uid != *uid)
494 entry.images.emplace_back (std::move (
desc));
499 Module::Snapshot snapshot;
501 snapshot.images.emplace_back (std::move (
desc));
502 result.emplace_back (std::move (snapshot));
static ProjectFileIORegistry::AttributeWriterEntry entry
T getFunctionPointer(const char *name)
bool load(const std::string &inPath, std::string &errorDescription) override
bool(PLUGIN_API *)() InitModuleFunc
bool(PLUGIN_API *)() ExitModuleFunc
std::string ConvertToUTF8(const T *str)
VST3::Optional< filesystem::path > resolveShellLink(const filesystem::path &p)
Optional< std::string > getKnownFolder(REFKNOWNFOLDERID folderID)
void findFilesWithExt(const filesystem::path &path, const std::string &ext, Module::PathList &pathList, bool recursive=true)
void findModules(const filesystem::path &path, Module::PathList &pathList)
Optional< filesystem::path > getContentsDirectoryFromModuleExecutablePath(const std::string &modulePath)
bool isFolderSymbolicLink(const filesystem::path &p)
constexpr auto architectureString
bool checkVST3Package(filesystem::path &p)
const TranslatableString desc