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")
84#if SMTG_OS_WINDOWS_ARM
92#define USE_OLE !USE_FILESYSTEM
106 static Ole gInstance;
111 Ole () { OleInitialize (
nullptr); }
112 ~Ole () { OleUninitialize (); }
120 template <
typename T>
123 return reinterpret_cast<T
> (GetProcAddress (mModule,
name));
128 factory = PluginFactory (
nullptr);
133 if (
auto dllExit = getFunctionPointer<ExitModuleFunc> (
"ExitDll"))
136 FreeLibrary ((HMODULE)mModule);
140 bool load (
const std::string& inPath, std::string& errorDescription)
override
142 auto wideStr = StringConvert::convert (inPath);
143 mModule = LoadLibraryW (
reinterpret_cast<LPCWSTR
> (wideStr.data ()));
146 filesystem::path p (inPath);
147 auto filename = p.filename ();
151 wideStr = StringConvert::convert (p.string ());
152 mModule = LoadLibraryW (
reinterpret_cast<LPCWSTR
> (wideStr.data ()));
155 auto lastError = GetLastError ();
156 LPVOID lpMessageBuffer;
157 FormatMessageA (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
158 nullptr, lastError, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
159 (LPSTR)&lpMessageBuffer, 0,
nullptr);
160 errorDescription =
"LoadLibray failed: " + std::string ((
char*)lpMessageBuffer);
161 LocalFree (lpMessageBuffer);
166 auto factoryProc = getFunctionPointer<GetFactoryProc> (
"GetPluginFactory");
169 errorDescription =
"The dll does not export the required 'GetPluginFactory' function";
173 auto dllEntry = getFunctionPointer<InitModuleFunc> (
"InitDll");
174 if (dllEntry && !dllEntry ())
176 errorDescription =
"Calling 'InitDll' failed";
179 auto f = Steinberg::FUnknownPtr<Steinberg::IPluginFactory> (owned (factoryProc ()));
182 errorDescription =
"Calling 'GetPluginFactory' returned nullptr";
189 HINSTANCE mModule {
nullptr};
195 auto filename = p.filename ();
199 auto hFile = CreateFileW (
reinterpret_cast<LPCWSTR
> (p.c_str ()), GENERIC_READ, FILE_SHARE_READ,
200 nullptr, OPEN_EXISTING, 0,
nullptr);
201 if (hFile != INVALID_HANDLE_VALUE)
213 if ( filesystem::is_symlink (p))
216 std::wstring wString = p.generic_wstring ();
217 auto attrib = GetFileAttributesW (
reinterpret_cast<LPCWSTR
> (wString.c_str ()));
218 if (attrib & FILE_ATTRIBUTE_REPARSE_POINT)
220 auto hFile = CreateFileW (
reinterpret_cast<LPCWSTR
> (wString.c_str ()), GENERIC_READ,
221 FILE_SHARE_READ,
nullptr, OPEN_EXISTING, 0,
nullptr);
222 if (hFile == INVALID_HANDLE_VALUE)
235 if (FAILED (SHGetKnownFolderPath (folderID, 0,
nullptr, &wideStr)))
237 return StringConvert::convert (wideStr);
244 return {filesystem::read_symlink (p)};
249 IShellLink* shellLink =
nullptr;
250 if (!SUCCEEDED (CoCreateInstance (CLSID_ShellLink,
nullptr, CLSCTX_INPROC_SERVER,
251 IID_IShellLink,
reinterpret_cast<LPVOID*
> (&shellLink))))
254 IPersistFile* persistFile =
nullptr;
256 shellLink->QueryInterface (IID_IPersistFile,
reinterpret_cast<void**
> (&persistFile))))
259 if (!SUCCEEDED (persistFile->Load (p.wstring ().data (), STGM_READ)))
262 if (!SUCCEEDED (shellLink->Resolve (
nullptr, MAKELONG (SLR_NO_UI, 500))))
265 WCHAR resolvedPath[MAX_PATH];
266 if (!SUCCEEDED (shellLink->GetPath (resolvedPath, MAX_PATH,
nullptr, SLGP_SHORTPATH)))
269 std::wstring longPath;
270 longPath.resize (MAX_PATH);
272 GetLongPathNameW (resolvedPath,
const_cast<wchar_t*
> (longPath.data ()), MAX_PATH);
275 longPath.resize (numChars);
277 persistFile->Release ();
278 shellLink->Release ();
280 return {filesystem::path (longPath)};
290 Module::PathList& pathList,
bool recursive =
true)
292 for (
auto& p : filesystem::directory_iterator (path))
295 filesystem::path finalPath (p);
301 if (!filesystem::exists (finalPath))
307 const auto& cpExt = finalPath.extension ();
310 filesystem::path vstPath (finalPath);
313 pathList.push_back (vstPath.generic_string ());
318 if (filesystem::is_directory (finalPath))
323 else if (cpExt == ext)
324 pathList.push_back (finalPath.generic_string ());
326 const auto& cp = p.path ();
327 const auto& cpExt = cp.extension ();
330 if ((p.status ().type () == filesystem::file_type::directory) ||
333 filesystem::path finalPath (p);
336 pathList.push_back (finalPath.generic_u8string ());
342 pathList.push_back (cp.generic_u8string ());
346 if (p.status ().type () == filesystem::file_type::directory)
350 else if (cpExt ==
".lnk")
354 if (resolvedLink->extension () == ext)
356 if (filesystem::is_directory (*resolvedLink) ||
359 filesystem::path finalPath (*resolvedLink);
362 pathList.push_back (finalPath.generic_u8string ());
368 pathList.push_back (resolvedLink->generic_u8string ());
370 else if (filesystem::is_directory (*resolvedLink))
372 const auto&
str = resolvedLink->generic_u8string ();
373 if (cp.generic_u8string ().compare (0,
str.size (),
str.data (),
385void findModules (
const filesystem::path& path, Module::PathList& pathList)
387 if (filesystem::exists (path))
393 const std::string& modulePath)
395 filesystem::path path (modulePath);
397 path = path.parent_path ();
400 path = path.parent_path ();
401 if (path.filename () !=
"Contents")
404 return Optional<filesystem::path> {std::move (path)};
411Module::Ptr Module::create (
const std::string& path, std::string& errorDescription)
413 auto _module = std::make_shared<Win32Module> ();
414 if (_module->load (path, errorDescription))
416 _module->path = path;
417 auto it = std::find_if (path.rbegin (), path.rend (),
418 [] (
const std::string::value_type& c) { return c ==
'/'; });
419 if (it != path.rend ())
420 _module->name = {it.base (), path.end ()};
427Module::PathList Module::getModulePaths ()
431 if (
auto knownFolder =
getKnownFolder (FOLDERID_ProgramFilesCommon))
433 filesystem::path p (*knownFolder);
439 WCHAR modulePath[MAX_PATH + 1];
440 GetModuleFileNameW (
nullptr, modulePath, MAX_PATH);
441 auto appPath = StringConvert::convert (modulePath);
442 filesystem::path path (appPath);
443 path = path.parent_path ();
444 path = path.append (
"VST3");
451Module::SnapshotList Module::getSnapshots (
const std::string& modulePath)
458 *path /=
"Resources";
459 *path /=
"Snapshots";
461 if (filesystem::exists (*path) ==
false)
466 for (
auto& png : pngList)
468 filesystem::path p (png);
469 auto filename = p.filename ().generic_string ();
470 auto uid = Snapshot::decodeUID (filename);
473 auto scaleFactor = 1.;
474 if (
auto decodedScaleFactor = Snapshot::decodeScaleFactor (filename))
475 scaleFactor = *decodedScaleFactor;
477 Module::Snapshot::ImageDesc
desc;
478 desc.scaleFactor = scaleFactor;
479 desc.path = std::move (png);
481 for (
auto&
entry : result)
483 if (
entry.uid != *uid)
486 entry.images.emplace_back (std::move (
desc));
491 Module::Snapshot snapshot;
493 snapshot.images.emplace_back (std::move (
desc));
494 result.emplace_back (std::move (snapshot));
const TranslatableString name
const TranslatableString desc
T getFunctionPointer(const char *name)
bool load(const std::string &inPath, std::string &errorDescription) override
bool(PLUGIN_API *)() InitModuleFunc
bool(PLUGIN_API *)() ExitModuleFunc
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)
static RegisteredToolbarFactory factory