use alloc::ffi::CString;
use core::{ffi::c_void, ops::Deref};
use windows_core::{GUID, Interface, PCSTR, PCWSTR, PWSTR};
use windows_sys::{
Win32::Foundation::{BOOL, HANDLE, HMODULE},
core::HRESULT,
};
use crate::error::{ClrError, Result};
#[repr(C)]
#[derive(Clone, Debug)]
pub struct ICLRRuntimeInfo(windows_core::IUnknown);
impl ICLRRuntimeInfo {
#[inline]
pub fn is_started(&self) -> bool {
let mut started = 0;
let mut startup_flags = 0;
self.IsStarted(&mut started, &mut startup_flags).is_ok() && started != 0
}
#[inline]
pub fn IsLoadable(&self) -> Result<BOOL> {
unsafe {
let mut result = 0;
let hr = (Interface::vtable(self).IsLoadable)(Interface::as_raw(self), &mut result);
if hr == 0 {
Ok(result)
} else {
Err(ClrError::ApiError("IsLoadable", hr))
}
}
}
#[inline]
pub fn GetInterface<T>(&self, rclsid: *const GUID) -> Result<T>
where
T: Interface,
{
unsafe {
let mut result = core::ptr::null_mut();
let hr = (Interface::vtable(self).GetInterface)(
Interface::as_raw(self),
rclsid,
&T::IID,
&mut result,
);
if hr == 0 {
Ok(core::mem::transmute_copy(&result))
} else {
Err(ClrError::ApiError("GetInterface", hr))
}
}
}
#[inline]
pub fn GetVersionString(&self, pwzbuffer: PWSTR, pcchbuffer: *mut u32) -> Result<()> {
unsafe {
let hr = (Interface::vtable(self).GetVersionString)(
Interface::as_raw(self),
pwzbuffer,
pcchbuffer,
);
if hr == 0 {
Ok(())
} else {
Err(ClrError::ApiError("GetVersionString", hr))
}
}
}
#[inline]
pub fn GetRuntimeDirectory(&self, pwzbuffer: PWSTR, pcchbuffer: *mut u32) -> Result<()> {
unsafe {
let hr = (Interface::vtable(self).GetRuntimeDirectory)(
Interface::as_raw(self),
pwzbuffer,
pcchbuffer,
);
if hr == 0 {
Ok(())
} else {
Err(ClrError::ApiError("GetRuntimeDirectory", hr))
}
}
}
#[inline]
pub fn IsLoaded(&self, hndProcess: HANDLE) -> Result<BOOL> {
unsafe {
let mut pbLoaded = 0;
let hr = (Interface::vtable(self).IsLoaded)(
Interface::as_raw(self),
hndProcess,
&mut pbLoaded,
);
if hr == 0 {
Ok(pbLoaded)
} else {
Err(ClrError::ApiError("IsLoaded", hr))
}
}
}
#[inline]
pub fn LoadErrorString(
&self,
iResourceID: u32,
pwzBuffer: PWSTR,
pcchBuffer: *mut u32,
iLocaleID: i32,
) -> Result<()> {
unsafe {
let hr = (Interface::vtable(self).LoadErrorString)(
Interface::as_raw(self),
iResourceID,
pwzBuffer,
pcchBuffer,
iLocaleID,
);
if hr == 0 {
Ok(())
} else {
Err(ClrError::ApiError("LoadErrorString", hr))
}
}
}
#[inline]
pub fn LoadLibraryA(&self, pwzDllName: PCWSTR) -> Result<HMODULE> {
unsafe {
let mut result = core::mem::zeroed();
let hr = (Interface::vtable(self).LoadLibraryA)(
Interface::as_raw(self),
pwzDllName,
&mut result,
);
if hr == 0 {
Ok(result)
} else {
Err(ClrError::ApiError("LoadLibraryA", hr))
}
}
}
#[inline]
pub fn GetProcAddress(&self, pszProcName: &str) -> Result<*mut c_void> {
unsafe {
let mut result = core::mem::zeroed();
let cstr =
CString::new(pszProcName).map_err(|_| ClrError::Msg("invalid String"))?;
let hr = (Interface::vtable(self).GetProcAddress)(
Interface::as_raw(self),
PCSTR(cstr.as_ptr().cast()),
&mut result,
);
if hr == 0 {
Ok(result)
} else {
Err(ClrError::ApiError("GetProcAddress", hr))
}
}
}
#[inline]
pub fn SetDefaultStartupFlags(
&self,
dwstartupflags: u32,
pwzhostconfigfile: PCWSTR,
) -> Result<()> {
unsafe {
let hr = (Interface::vtable(self).SetDefaultStartupFlags)(
Interface::as_raw(self),
dwstartupflags,
pwzhostconfigfile,
);
if hr == 0 {
Ok(())
} else {
Err(ClrError::ApiError("SetDefaultStartupFlags", hr))
}
}
}
#[inline]
pub fn GetDefaultStartupFlags(
&self,
pdwstartupflags: *mut u32,
pwzhostconfigfile: PWSTR,
pcchhostconfigfile: *mut u32,
) -> Result<()> {
unsafe {
let hr = (Interface::vtable(self).GetDefaultStartupFlags)(
Interface::as_raw(self),
pdwstartupflags,
core::mem::transmute(pwzhostconfigfile),
pcchhostconfigfile,
);
if hr == 0 {
Ok(())
} else {
Err(ClrError::ApiError("GetDefaultStartupFlags", hr))
}
}
}
#[inline]
pub fn BindAsLegacyV2Runtime(&self) -> Result<()> {
unsafe {
let hr = (Interface::vtable(self).BindAsLegacyV2Runtime)(Interface::as_raw(self));
if hr == 0 {
Ok(())
} else {
Err(ClrError::ApiError("BindAsLegacyV2Runtime", hr))
}
}
}
#[inline]
pub fn IsStarted(&self, pbstarted: *mut BOOL, pdwstartupflags: *mut u32) -> Result<()> {
unsafe {
let hr = (Interface::vtable(self).IsStarted)(
Interface::as_raw(self),
pbstarted,
pdwstartupflags,
);
if hr == 0 {
Ok(())
} else {
Err(ClrError::ApiError("IsStarted", hr))
}
}
}
}
unsafe impl Interface for ICLRRuntimeInfo {
type Vtable = ICLRRuntimeInfo_Vtbl;
const IID: GUID = GUID::from_u128(0xbd39d1d2_ba2f_486a_89b0_b4b0cb466891);
}
impl Deref for ICLRRuntimeInfo {
type Target = windows_core::IUnknown;
fn deref(&self) -> &Self::Target {
unsafe { core::mem::transmute(self) }
}
}
#[repr(C)]
pub struct ICLRRuntimeInfo_Vtbl {
pub base__: windows_core::IUnknown_Vtbl,
pub GetVersionString: unsafe extern "system" fn(
this: *mut c_void,
pwzBuffer: PWSTR,
pcchBuffer: *mut u32,
) -> HRESULT,
pub GetRuntimeDirectory: unsafe extern "system" fn(
this: *mut c_void,
pwzBuffer: PWSTR,
pcchBuffer: *mut u32,
) -> HRESULT,
pub IsLoaded: unsafe extern "system" fn(
this: *mut c_void,
hndProcess: HANDLE,
pbLoaded: *mut BOOL,
) -> HRESULT,
pub LoadErrorString: unsafe extern "system" fn(
this: *mut c_void,
iResourceID: u32,
pwzBuffer: PWSTR,
pcchBuffer: *mut u32,
iLocaleID: i32,
) -> HRESULT,
pub LoadLibraryA: unsafe extern "system" fn(
this: *mut c_void,
pwzDllName: PCWSTR,
phndModule: *mut HMODULE,
) -> HRESULT,
pub GetProcAddress: unsafe extern "system" fn(
this: *mut c_void,
pszProcName: PCSTR,
ppProc: *mut *mut c_void,
) -> HRESULT,
pub GetInterface: unsafe extern "system" fn(
this: *mut c_void,
rclsid: *const windows_core::GUID,
riid: *const windows_core::GUID,
ppUnk: *mut *mut c_void,
) -> HRESULT,
pub IsLoadable: unsafe extern "system" fn(this: *mut c_void, pbLoadable: *mut BOOL) -> HRESULT,
pub SetDefaultStartupFlags: unsafe extern "system" fn(
this: *mut c_void,
dwStartupFlags: u32,
pwzHostConfigFile: PCWSTR,
) -> HRESULT,
pub GetDefaultStartupFlags: unsafe extern "system" fn(
this: *mut c_void,
dwStartupFlags: *mut u32,
pwzHostConfigFile: windows_core::PCWSTR,
pcchHostConfigFile: *mut u32,
) -> HRESULT,
pub BindAsLegacyV2Runtime: unsafe extern "system" fn(this: *mut c_void) -> HRESULT,
pub IsStarted: unsafe extern "system" fn(
this: *mut c_void,
pbStarted: *mut BOOL,
pdwStartupFlags: *mut u32,
) -> HRESULT,
}