#![allow(clippy::redundant_pub_crate)]
use std::{
ffi::{CStr, CString, OsString, c_char},
os::windows::ffi::OsStringExt as _,
path::PathBuf,
ptr,
};
use winapi::{
shared::{
minwindef::{DWORD, HMODULE, MAX_PATH},
winerror::ERROR_INSUFFICIENT_BUFFER,
},
um::{
errhandlingapi::GetLastError,
libloaderapi::{
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
GetModuleFileNameW, GetModuleHandleExW,
},
},
};
pub(crate) unsafe fn cstr<'a>(ptr: *const c_char) -> &'a str {
if ptr.is_null() {
return "";
}
unsafe { CStr::from_ptr(ptr) }.to_str().unwrap_or("")
}
pub(crate) fn cstr_lossy(s: &str) -> CString {
CString::new(s)
.unwrap_or_else(|_| CString::new(s.replace('\0', "")).expect("no interior NUL after strip"))
}
fn current_module() -> Option<HMODULE> {
static ANCHOR: u16 = 0;
let mut handle: HMODULE = ptr::null_mut();
let ok = unsafe {
GetModuleHandleExW(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
&raw const ANCHOR,
&raw mut handle,
)
};
if ok == 0 { None } else { Some(handle) }
}
pub fn get_plugin_path() -> Option<PathBuf> {
fn get_plugin_path(module: HMODULE, len: usize) -> Option<PathBuf> {
let mut buf = Vec::with_capacity(len);
#[expect(clippy::as_conversions, reason = "We should never get that far")]
#[expect(
clippy::cast_possible_truncation,
reason = "We should never get that far"
)]
let ret = unsafe { GetModuleFileNameW(module, buf.as_mut_ptr(), len as DWORD) } as usize;
if ret == 0 {
None
} else if ret < len {
unsafe {
buf.set_len(ret);
}
let s = OsString::from_wide(&buf);
Some(s.into())
} else {
let errno = unsafe { GetLastError() };
if errno == ERROR_INSUFFICIENT_BUFFER {
get_plugin_path(module, len * 2)
} else {
None
}
}
}
let module = current_module()?;
get_plugin_path(module, MAX_PATH)
}