use super::{ModuleLoader, VstModule};
use crate::error::{Error, Result};
use std::path::Path;
use vst3::Steinberg::IPluginFactory;
#[cfg(target_os = "windows")]
use libloading::{Library, Symbol};
type InitDllFunc = unsafe extern "C" fn() -> bool;
type ExitDllFunc = unsafe extern "C" fn() -> bool;
type GetPluginFactoryFunc = unsafe extern "C" fn() -> *mut IPluginFactory;
pub struct WindowsModule {
#[allow(dead_code)]
library: Library,
path: std::path::PathBuf,
exit_dll: Option<Symbol<'static, ExitDllFunc>>,
get_factory_fn: Symbol<'static, GetPluginFactoryFunc>,
}
fn arch_mismatch_detail(binary: &Path) -> Option<String> {
use super::arch;
let data = std::fs::read(binary).ok()?;
let name = arch::pe_machine_name(arch::detect_pe_machine(&data)?);
arch::mismatch_detail("DLL", name)
}
impl WindowsModule {
fn load_internal(path: &Path) -> Result<Self> {
unsafe {
log::info!("=== Windows VST3 MODULE LOADING START ===");
log::info!("Loading VST3 DLL: {}", path.display());
let binary =
crate::discovery::get_vst3_binary_path(path).unwrap_or_else(|_| path.to_path_buf());
log::debug!("Step 1: Loading DLL: {}", binary.display());
let library = Library::new(&binary).map_err(|e| {
let detail = arch_mismatch_detail(&binary)
.unwrap_or_else(|| format!("Failed to load DLL: {}", e));
Error::PluginLoadFailed(detail)
})?;
log::debug!("DLL loaded successfully");
log::debug!("Step 2: Looking for InitDll function...");
let init_dll_result = library.get::<InitDllFunc>(b"InitDll");
match init_dll_result {
Ok(init_dll) => {
log::debug!("InitDll function found, calling it...");
let init_result = init_dll();
if init_result {
log::debug!("InitDll called successfully");
} else {
log::warn!("InitDll returned false");
return Err(Error::PluginLoadFailed(
"InitDll function returned false".to_string(),
));
}
}
Err(_) => {
log::debug!(
"InitDll function not found (this is OK, it's optional on Windows)"
);
}
}
log::debug!("Step 3: Looking for ExitDll function...");
let exit_dll = match library.get::<ExitDllFunc>(b"ExitDll") {
Ok(func) => {
log::debug!("ExitDll function found (will be called on cleanup)");
Some(std::mem::transmute(func))
}
Err(_) => {
log::debug!(
"ExitDll function not found (this is OK, it's optional on Windows)"
);
None
}
};
log::debug!("Step 4: Getting GetPluginFactory function...");
let get_factory_fn = library
.get::<GetPluginFactoryFunc>(b"GetPluginFactory")
.map_err(|e| {
Error::PluginLoadFailed(format!("Failed to find GetPluginFactory: {}", e))
})?;
log::debug!("GetPluginFactory function found");
let get_factory_fn: Symbol<'static, GetPluginFactoryFunc> =
std::mem::transmute(get_factory_fn);
log::info!("=== Windows VST3 MODULE LOADING COMPLETE ===");
log::info!("DLL loaded successfully: {}", path.display());
Ok(WindowsModule {
library,
path: path.to_path_buf(),
exit_dll,
get_factory_fn,
})
}
}
}
impl VstModule for WindowsModule {
fn get_factory(&self) -> Result<*mut IPluginFactory> {
let factory = unsafe { (self.get_factory_fn)() };
if factory.is_null() {
Err(Error::PluginLoadFailed(
"GetPluginFactory returned null".to_string(),
))
} else {
Ok(factory)
}
}
fn path(&self) -> &Path {
&self.path
}
}
impl Drop for WindowsModule {
fn drop(&mut self) {
unsafe {
log::debug!("=== Windows VST3 MODULE CLEANUP START ===");
if let Some(exit_dll) = self.exit_dll.take() {
log::debug!("Calling ExitDll...");
let exit_result = exit_dll();
if exit_result {
log::debug!("ExitDll called successfully");
} else {
log::warn!("ExitDll returned false");
}
}
log::debug!("Unloading DLL...");
log::debug!("DLL unloaded");
log::debug!("=== Windows VST3 MODULE CLEANUP COMPLETE ===");
}
}
}
pub struct WindowsModuleLoader;
impl ModuleLoader for WindowsModuleLoader {
fn load(path: &Path) -> Result<Box<dyn VstModule>> {
let module = WindowsModule::load_internal(path)?;
Ok(Box::new(module))
}
}