mirror of
https://github.com/yamakadi/clroxide
synced 2026-06-08 18:28:14 +00:00
Move everything to its own repo
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
/target
|
||||
/Cargo.lock
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
[package]
|
||||
name = "clroxide"
|
||||
authors = ["KY <me@yamakadi.com>"]
|
||||
description = "A library that allows you to host the CLR and execute dotnet binaries."
|
||||
edition = "2021"
|
||||
homepage = "https://github.com/yamakadi/clroxide"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/yamakadi/clroxide"
|
||||
version = "1.0.0"
|
||||
|
||||
[lib]
|
||||
crate-type = ["lib", "staticlib"]
|
||||
|
||||
[features]
|
||||
default = ["default-loader"]
|
||||
default-loader = ["windows/Win32_System_LibraryLoader"]
|
||||
debug = []
|
||||
|
||||
[dependencies]
|
||||
windows = { version = "0.44.0", features = ["Win32_System_Com", "Win32_Foundation", "Win32_System_Ole"] }
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
all-features = false
|
||||
default-target = "x86_64-pc-windows-gnu"
|
||||
targets = ["x86_64-pc-windows-gnu", "x86_64-pc-windows-msvc"]
|
||||
@@ -0,0 +1,67 @@
|
||||
# ClrOxide
|
||||
`ClrOxide` is a rust library that allows you to host the CLR and dynamically execute dotnet binaries.
|
||||
|
||||
I wanted to call it `Kepler` for no particular reason, but there's already a package named `kepler` in cargo. :(
|
||||
|
||||
I have been working on hosting CLR with rust on and off for 2 years now, and finally something clicked two weeks ago!
|
||||
|
||||
This library wouldn't be possible without the following projects:
|
||||
|
||||
- [NimPlant](https://github.com/chvancooten/NimPlant) and its [execute assembly](https://github.com/chvancooten/NimPlant/tree/main/client/commands/risky/executeAssembly.nim) implementation
|
||||
- The elegance with which `winim/clr` allows overwriting the output buffer for `Console.Write` and gets the output! Striving for the same elegance is the only reason this library took two years.
|
||||
How can I convince Cas to dabble with rust if he can't replicate this!? My work for a rust implant for `NimPlant` is also how I got into this rabbit hole in the first place.
|
||||
- [go-clr](https://github.com/ropnop/go-clr) by [ropnop](https://github.com/ropnop)
|
||||
- A very special thank you to ropnop here! This whole library is the result of 3 days of work thanks to something in `go-clr` that just made everything click for me!
|
||||
- [dinvoke_rs](https://github.com/Kudaes/DInvoke_rs) by [Kudaes](https://github.com/Kudaes)
|
||||
- Similar to `go-clr`, Kurosh's `dinvoke_rs` project also made some rust/win32 intricacies clearer and allowed the project to move forward.
|
||||
- Various CLR-related rust libraries
|
||||
- https://github.com/ZerothLaw/mscorlib-rs-sys
|
||||
- https://github.com/ZerothLaw/mscoree-rs
|
||||
- and likely a few more...
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
`ClrOxide` will load the CLR in the current process, resolve `mscorlib` and redirect the output for `System.Console`, finally loading and running your executable and returning its output as a string.
|
||||
|
||||
Streaming the output is not currently supported, although I'm sure the CLR wrangling magic used for redirecting the output could be a good guide for anyone willing to implement it.
|
||||
|
||||
```rust
|
||||
use clroxide::clr::Clr;
|
||||
use std::{env, fs, process::exit};
|
||||
|
||||
fn main() -> Result<(), String> {
|
||||
let (path, args) = prepare_args();
|
||||
|
||||
let contents = fs::read(path).expect("Unable to read file");
|
||||
let mut context = Clr::new(contents, args)?;
|
||||
|
||||
let results = context.run()?;
|
||||
|
||||
println!("[*] Results:\n\n{}", results);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn prepare_args() -> (String, Vec<String>) {
|
||||
let mut args: Vec<String> = env::args().collect();
|
||||
|
||||
if args.len() < 2 {
|
||||
println!("Please provide a path to a dotnet executable");
|
||||
|
||||
exit(1)
|
||||
}
|
||||
|
||||
let mut command_args: Vec<String> = vec![];
|
||||
|
||||
if args.len() > 2 {
|
||||
command_args = args.split_off(2)
|
||||
}
|
||||
|
||||
let path = args[1].clone();
|
||||
|
||||
println!("[+] Running `{}` with given args: {:?}", path, command_args);
|
||||
|
||||
return (path, command_args);
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,37 @@
|
||||
use clroxide::clr::Clr;
|
||||
use std::{env, fs, process::exit};
|
||||
|
||||
fn main() -> Result<(), String> {
|
||||
let (path, args) = prepare_args();
|
||||
|
||||
let contents = fs::read(path).expect("Unable to read file");
|
||||
let mut context = Clr::new(contents, args)?;
|
||||
|
||||
let results = context.run()?;
|
||||
|
||||
println!("[*] Results:\n\n{}", results);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn prepare_args() -> (String, Vec<String>) {
|
||||
let mut args: Vec<String> = env::args().collect();
|
||||
|
||||
if args.len() < 2 {
|
||||
println!("Please provide a path to a dotnet executable");
|
||||
|
||||
exit(1)
|
||||
}
|
||||
|
||||
let mut command_args: Vec<String> = vec![];
|
||||
|
||||
if args.len() > 2 {
|
||||
command_args = args.split_off(2)
|
||||
}
|
||||
|
||||
let path = args[1].clone();
|
||||
|
||||
println!("[+] Running `{}` with given args: {:?}", path, command_args);
|
||||
|
||||
return (path, command_args);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
imports_granularity = "Crate"
|
||||
indent_style = "Block"
|
||||
match_block_trailing_comma = true
|
||||
reorder_impl_items = true
|
||||
use_field_init_shorthand = true
|
||||
use_try_shorthand = true
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
use crate::primitives::{
|
||||
ICLRMetaHost, ICLRRuntimeInfo, ICorRuntimeHost, IUnknown, Interface, _AppDomain, _MethodInfo,
|
||||
_StringWriter, wrap_method_arguments, GUID, HRESULT,
|
||||
};
|
||||
use std::{ffi::c_void, ptr};
|
||||
use windows::Win32::System::Com::VARIANT;
|
||||
#[cfg(feature = "default-loader")]
|
||||
use windows::Win32::System::LibraryLoader::{GetProcAddress, LoadLibraryA};
|
||||
|
||||
pub struct Clr {
|
||||
contents: Vec<u8>,
|
||||
arguments: Vec<String>,
|
||||
create_interface: isize,
|
||||
context: Option<ClrContext>,
|
||||
output_context: Option<OutputContext>,
|
||||
}
|
||||
|
||||
pub struct ClrContext {
|
||||
pub has_started: bool,
|
||||
pub host: *mut ICLRMetaHost,
|
||||
pub runtime_info: *mut ICLRRuntimeInfo,
|
||||
pub runtime_host: *mut ICorRuntimeHost,
|
||||
pub app_domain: *mut _AppDomain,
|
||||
}
|
||||
|
||||
pub struct OutputContext {
|
||||
pub set_out: *mut _MethodInfo,
|
||||
pub original_stdout: VARIANT,
|
||||
pub redirected_stdout: VARIANT,
|
||||
}
|
||||
|
||||
impl Clr {
|
||||
#[cfg(feature = "default-loader")]
|
||||
pub fn new(contents: Vec<u8>, arguments: Vec<String>) -> Result<Clr, String> {
|
||||
let create_interface = load_function("mscoree.dll", "CreateInterface")?;
|
||||
|
||||
Ok(Clr {
|
||||
contents,
|
||||
arguments,
|
||||
create_interface,
|
||||
context: None,
|
||||
output_context: None,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "default-loader"))]
|
||||
pub fn new(
|
||||
contents: Vec<u8>,
|
||||
arguments: Vec<String>,
|
||||
load_function: fn(&str, &str) -> Result<isize, String>,
|
||||
) -> Result<Clr, String> {
|
||||
let create_interface = load_function("mscoree.dll", "CreateInterface")?;
|
||||
|
||||
Ok(Clr {
|
||||
contents,
|
||||
arguments,
|
||||
create_interface,
|
||||
context: None,
|
||||
output_context: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> Result<String, String> {
|
||||
self.redirect_output()?;
|
||||
|
||||
let context = self.get_context()?;
|
||||
let assembly = unsafe { (*(&context).app_domain).load_assembly(&self.contents)? };
|
||||
|
||||
unsafe { (*assembly).run_entrypoint(&self.arguments)? };
|
||||
|
||||
self.restore_output()?;
|
||||
|
||||
self.get_redirected_output()
|
||||
}
|
||||
|
||||
pub fn redirect_output(&mut self) -> Result<(), String> {
|
||||
let context = self.get_context()?;
|
||||
|
||||
let assembly = unsafe { (*(&context).app_domain).load_library("mscorlib")? };
|
||||
|
||||
let console = unsafe { (*assembly).get_type("System.Console")? };
|
||||
|
||||
let get_out = unsafe { (*console).get_method("get_Out")? };
|
||||
|
||||
let set_out = unsafe { (*console).get_method("SetOut")? };
|
||||
|
||||
let old_console = unsafe { (*get_out).invoke_without_args()? };
|
||||
|
||||
let string_writer_instance =
|
||||
unsafe { (*assembly).create_instance("System.IO.StringWriter")? };
|
||||
|
||||
let method_args = wrap_method_arguments(vec![string_writer_instance.clone()])?;
|
||||
|
||||
unsafe { (*set_out).invoke(method_args)? };
|
||||
|
||||
self.output_context = Some(OutputContext {
|
||||
set_out,
|
||||
original_stdout: old_console,
|
||||
redirected_stdout: string_writer_instance,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn restore_output(&mut self) -> Result<(), String> {
|
||||
if self.output_context.is_none() {
|
||||
return Err("Output context has not been initialized".into());
|
||||
}
|
||||
|
||||
let context = self.output_context.as_ref().unwrap();
|
||||
|
||||
let method_args = wrap_method_arguments(vec![context.original_stdout.clone()])?;
|
||||
|
||||
unsafe { (*(&context).set_out).invoke(method_args)? };
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_redirected_output(&mut self) -> Result<String, String> {
|
||||
if self.output_context.is_none() {
|
||||
return Err("Output context has not been initialized".into());
|
||||
}
|
||||
|
||||
let context = self.output_context.as_ref().unwrap();
|
||||
|
||||
let mut dispatchable: &*mut IUnknown = unsafe {
|
||||
std::mem::transmute(
|
||||
context
|
||||
.redirected_stdout
|
||||
.Anonymous
|
||||
.Anonymous
|
||||
.Anonymous
|
||||
.pdispVal
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
)
|
||||
};
|
||||
let mut string_writer_ptr: *mut _StringWriter = ptr::null_mut();
|
||||
|
||||
if dispatchable.is_null() {
|
||||
return Err("Could not retrieve StringWriter".into());
|
||||
}
|
||||
|
||||
let hr = unsafe {
|
||||
(**dispatchable).QueryInterface(
|
||||
&_StringWriter::IID,
|
||||
&mut string_writer_ptr as *mut *mut _ as *mut *mut c_void,
|
||||
)
|
||||
};
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Error while retrieving StringWriter: 0x{:x}", hr.0));
|
||||
}
|
||||
|
||||
if string_writer_ptr.is_null() {
|
||||
return Err("Could not retrieve StringWriter".into());
|
||||
}
|
||||
|
||||
Ok(unsafe { (*string_writer_ptr).to_string()? })
|
||||
}
|
||||
|
||||
pub fn get_context(&mut self) -> Result<&ClrContext, String> {
|
||||
if self.context.is_some() {
|
||||
return Ok(self.context.as_ref().unwrap());
|
||||
}
|
||||
|
||||
let host = self.get_clr_host()?;
|
||||
let runtime_info = unsafe { (*host).get_first_available_runtime()? };
|
||||
let runtime_host = unsafe { (*runtime_info).get_runtime_host()? };
|
||||
|
||||
unsafe { (*runtime_host).start()? };
|
||||
|
||||
let app_domain = unsafe { (*runtime_host).get_default_domain()? };
|
||||
|
||||
self.context = Some(ClrContext {
|
||||
has_started: true,
|
||||
host,
|
||||
runtime_info,
|
||||
runtime_host,
|
||||
app_domain,
|
||||
});
|
||||
|
||||
Ok(self.context.as_ref().unwrap())
|
||||
}
|
||||
|
||||
fn get_clr_host(&self) -> Result<*mut ICLRMetaHost, String> {
|
||||
pub type CreateInterface = fn(
|
||||
class_id: *const GUID,
|
||||
interface_id: *const GUID,
|
||||
interface: *mut *mut c_void,
|
||||
) -> HRESULT;
|
||||
|
||||
let create_interface: CreateInterface =
|
||||
unsafe { std::mem::transmute(self.create_interface) };
|
||||
|
||||
let mut host: *mut ICLRMetaHost = ICLRMetaHost::new(create_interface)?;
|
||||
|
||||
return Ok(host);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "default-loader")]
|
||||
fn load_function(library_name: &str, function_name: &str) -> Result<isize, String> {
|
||||
let library = match unsafe {
|
||||
LoadLibraryA(windows::core::PCSTR::from_raw(
|
||||
format!("{}\0", library_name).as_ptr(),
|
||||
))
|
||||
} {
|
||||
Ok(hinstance) => hinstance,
|
||||
Err(e) => return Err(format!("Error while loading `{}`: {}", library_name, e)),
|
||||
};
|
||||
|
||||
return match unsafe {
|
||||
GetProcAddress(
|
||||
library,
|
||||
windows::core::PCSTR::from_raw(format!("{}\0", function_name).as_ptr()),
|
||||
)
|
||||
} {
|
||||
None => Err(format!(
|
||||
"Could not locate `{}` in `{}`",
|
||||
function_name, library_name
|
||||
)),
|
||||
Some(f) => Ok(f as isize),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
pub mod clr;
|
||||
pub mod primitives;
|
||||
@@ -0,0 +1,116 @@
|
||||
use std::{ffi::c_void, mem::ManuallyDrop, ptr};
|
||||
use windows::{
|
||||
core::BSTR,
|
||||
Win32::System::{
|
||||
Com::{
|
||||
SAFEARRAY, SAFEARRAYBOUND, VARENUM, VARIANT, VARIANT_0, VARIANT_0_0, VARIANT_0_0_0,
|
||||
VT_ARRAY, VT_BSTR, VT_UI1, VT_VARIANT,
|
||||
},
|
||||
Ole::{
|
||||
SafeArrayAccessData, SafeArrayCreate, SafeArrayCreateVector, SafeArrayGetUBound,
|
||||
SafeArrayPutElement, SafeArrayUnaccessData,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
pub fn prepare_assembly(bytes: &[u8]) -> Result<*mut SAFEARRAY, String> {
|
||||
let mut bounds = SAFEARRAYBOUND {
|
||||
cElements: bytes.len() as _,
|
||||
lLbound: 0,
|
||||
};
|
||||
|
||||
let mut safe_array_ptr: *mut SAFEARRAY = unsafe { SafeArrayCreate(VT_UI1, 1, &mut bounds) };
|
||||
let mut pv_data: *mut c_void = ptr::null_mut();
|
||||
|
||||
match unsafe { SafeArrayAccessData(safe_array_ptr, &mut pv_data) } {
|
||||
Ok(_) => {},
|
||||
Err(e) => {
|
||||
return Err(format!(
|
||||
"Could not prepare assembly due to a safe array related error: {:?}",
|
||||
e.code()
|
||||
))
|
||||
},
|
||||
}
|
||||
|
||||
unsafe { ptr::copy_nonoverlapping(bytes.as_ptr(), pv_data.cast(), bytes.len()) };
|
||||
|
||||
match unsafe { SafeArrayUnaccessData(safe_array_ptr) } {
|
||||
Ok(_) => {},
|
||||
Err(e) => {
|
||||
return Err(format!(
|
||||
"Could not prepare assembly due to a safe array related error: {:?}",
|
||||
e.code()
|
||||
))
|
||||
},
|
||||
};
|
||||
|
||||
Ok(safe_array_ptr)
|
||||
}
|
||||
|
||||
pub fn get_array_length(array_ptr: *mut SAFEARRAY) -> i32 {
|
||||
unsafe { SafeArrayGetUBound(array_ptr, 1) }.unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn empty_array() -> *mut SAFEARRAY {
|
||||
unsafe { SafeArrayCreateVector(VT_VARIANT, 0, 0) }
|
||||
}
|
||||
|
||||
pub fn wrap_strings_in_array(strings: &[String]) -> Result<VARIANT, String> {
|
||||
let mut inner = vec![];
|
||||
|
||||
for string in strings.iter() {
|
||||
inner.push(BSTR::from(string).into_raw())
|
||||
}
|
||||
|
||||
let mut safe_array_ptr: *mut SAFEARRAY =
|
||||
unsafe { SafeArrayCreateVector(VT_BSTR, 0, inner.len() as u32) };
|
||||
|
||||
for i in 0..inner.len() {
|
||||
let indices: [i32; 1] = [i as _];
|
||||
let v_ref = &inner[i];
|
||||
match unsafe { SafeArrayPutElement(safe_array_ptr, indices.as_ptr(), *v_ref as *const _) } {
|
||||
Ok(_) => {},
|
||||
Err(e) => {
|
||||
return Err(format!(
|
||||
"Could not create an array of strings: {:?}",
|
||||
e.code()
|
||||
))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(VARIANT {
|
||||
Anonymous: VARIANT_0 {
|
||||
Anonymous: ManuallyDrop::new(VARIANT_0_0 {
|
||||
vt: VARENUM(VT_BSTR.0 | VT_ARRAY.0),
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: VARIANT_0_0_0 {
|
||||
parray: safe_array_ptr,
|
||||
},
|
||||
}),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
pub fn wrap_method_arguments(arguments: Vec<VARIANT>) -> Result<*mut SAFEARRAY, String> {
|
||||
let mut variant_array_ptr: *mut SAFEARRAY = unsafe { SafeArrayCreateVector(VT_VARIANT, 0, 1) };
|
||||
|
||||
for i in 0..arguments.len() {
|
||||
let indices: [i32; 1] = [i as _];
|
||||
let v_ref: *const _ = &arguments[i];
|
||||
match unsafe { SafeArrayPutElement(variant_array_ptr, indices.as_ptr(), v_ref as *const _) }
|
||||
{
|
||||
Ok(_) => {},
|
||||
Err(e) => {
|
||||
return Err(format!(
|
||||
"Could not create an array of arguments: {:?}",
|
||||
e.code()
|
||||
))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
Ok(variant_array_ptr)
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
use crate::primitives::{
|
||||
itype::_Type, IUnknown, IUnknownVtbl, Interface, _Assembly, prepare_assembly, GUID, HRESULT,
|
||||
};
|
||||
use std::{
|
||||
ffi::{c_long, c_void},
|
||||
ops::Deref,
|
||||
ptr,
|
||||
};
|
||||
use windows::{core::BSTR, Win32::System::Com::SAFEARRAY};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct _AppDomain {
|
||||
pub vtable: *const _AppDomainVtbl,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct _AppDomainVtbl {
|
||||
pub parent: IUnknownVtbl,
|
||||
pub GetTypeInfoCount: *const c_void,
|
||||
pub GetTypeInfo: *const c_void,
|
||||
pub GetIDsOfNames: *const c_void,
|
||||
pub Invoke: *const c_void,
|
||||
pub ToString: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
|
||||
pub Equals: *const c_void,
|
||||
pub GetHashCode: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut c_long) -> HRESULT,
|
||||
pub GetType: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut _Type) -> HRESULT,
|
||||
pub InitializeLifetimeService: *const c_void,
|
||||
pub GetLifetimeService: *const c_void,
|
||||
pub get_Evidence: *const c_void,
|
||||
pub set_Evidence: *const c_void,
|
||||
pub get_DomainUnload: *const c_void,
|
||||
pub set_DomainUnload: *const c_void,
|
||||
pub get_AssemblyLoad: *const c_void,
|
||||
pub set_AssemblyLoad: *const c_void,
|
||||
pub get_ProcessExit: *const c_void,
|
||||
pub set_ProcessExit: *const c_void,
|
||||
pub get_TypeResolve: *const c_void,
|
||||
pub set_TypeResolve: *const c_void,
|
||||
pub get_ResourceResolve: *const c_void,
|
||||
pub set_ResourceResolve: *const c_void,
|
||||
pub get_AssemblyResolve: *const c_void,
|
||||
pub get_UnhandledException: *const c_void,
|
||||
pub set_UnhandledException: *const c_void,
|
||||
pub DefineDynamicAssembly: *const c_void,
|
||||
pub DefineDynamicAssembly_2: *const c_void,
|
||||
pub DefineDynamicAssembly_3: *const c_void,
|
||||
pub DefineDynamicAssembly_4: *const c_void,
|
||||
pub DefineDynamicAssembly_5: *const c_void,
|
||||
pub DefineDynamicAssembly_6: *const c_void,
|
||||
pub DefineDynamicAssembly_7: *const c_void,
|
||||
pub DefineDynamicAssembly_8: *const c_void,
|
||||
pub DefineDynamicAssembly_9: *const c_void,
|
||||
pub CreateInstance: *const c_void,
|
||||
pub CreateInstanceFrom: *const c_void,
|
||||
pub CreateInstance_2: *const c_void,
|
||||
pub CreateInstanceFrom_2: *const c_void,
|
||||
pub CreateInstance_3: *const c_void,
|
||||
pub CreateInstanceFrom_3: *const c_void,
|
||||
pub Load: *const c_void,
|
||||
pub Load_2: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
assemblyString: *mut u16,
|
||||
pRetVal: *mut *mut _Assembly,
|
||||
) -> HRESULT,
|
||||
pub Load_3: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
rawAssembly: *mut SAFEARRAY,
|
||||
pRetVal: *mut *mut _Assembly,
|
||||
) -> HRESULT,
|
||||
pub Load_4: *const c_void,
|
||||
pub Load_5: *const c_void,
|
||||
pub Load_6: *const c_void,
|
||||
pub Load_7: *const c_void,
|
||||
pub ExecuteAssembly: *const c_void,
|
||||
pub ExecuteAssembly_2: *const c_void,
|
||||
pub ExecuteAssembly_3: *const c_void,
|
||||
pub get_FriendlyName: *const c_void,
|
||||
pub get_BaseDirectory: *const c_void,
|
||||
pub get_RelativeSearchPath: *const c_void,
|
||||
pub get_ShadowCopyFiles: *const c_void,
|
||||
pub GetAssemblies: *const c_void,
|
||||
pub AppendPrivatePath: *const c_void,
|
||||
pub ClearPrivatePath: *const c_void,
|
||||
pub ClearShadowCopyPath: *const c_void,
|
||||
pub SetData: *const c_void,
|
||||
pub GetData: *const c_void,
|
||||
pub SetAppDomainPolicy: *const c_void,
|
||||
pub SetThreadPrincipal: *const c_void,
|
||||
pub SetPrincipalPolicy: *const c_void,
|
||||
pub DoCallBack: *const c_void,
|
||||
pub get_DynamicDirectory: *const c_void,
|
||||
}
|
||||
|
||||
impl _AppDomain {
|
||||
pub fn load_library(&self, library: &str) -> Result<*mut _Assembly, String> {
|
||||
let mut library_buffer = BSTR::from(library);
|
||||
|
||||
let mut library_ptr: *mut _Assembly = ptr::null_mut();
|
||||
|
||||
let hr = unsafe { (*self).Load_2(library_buffer.into_raw() as *mut _, &mut library_ptr) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Could not retrieve `{}`: {:?}", library, hr));
|
||||
}
|
||||
|
||||
if library_ptr.is_null() {
|
||||
return Err(format!("Could not retrieve `{}`", library));
|
||||
}
|
||||
|
||||
Ok(library_ptr)
|
||||
}
|
||||
|
||||
pub fn load_assembly(&self, bytes: &[u8]) -> Result<*mut _Assembly, String> {
|
||||
let assembly_bytes = prepare_assembly(bytes)?;
|
||||
|
||||
let mut assembly_ptr: *mut _Assembly = ptr::null_mut();
|
||||
|
||||
let hr = unsafe { (*self).Load_3(assembly_bytes, &mut assembly_ptr) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Could not retrieve assembly: {:?}", hr));
|
||||
}
|
||||
|
||||
if assembly_ptr.is_null() {
|
||||
return Err("Could not retrieve assembly".into());
|
||||
}
|
||||
|
||||
Ok(assembly_ptr)
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> Result<String, String> {
|
||||
let mut buffer = BSTR::new();
|
||||
|
||||
let hr = unsafe { (*self).ToString(&mut buffer as *mut _ as *mut *mut u16) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Failed while running `ToString`: {:?}", hr));
|
||||
}
|
||||
|
||||
Ok(buffer.to_string())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn ToString(&self, pRetVal: *mut *mut u16) -> HRESULT {
|
||||
((*self.vtable).ToString)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetHashCode(&self, pRetVal: *mut c_long) -> HRESULT {
|
||||
((*self.vtable).GetHashCode)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetType(&self, pRetVal: *mut *mut _Type) -> HRESULT {
|
||||
((*self.vtable).GetType)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn Load_2(&self, assemblyString: *mut u16, pRetVal: *mut *mut _Assembly) -> HRESULT {
|
||||
((*self.vtable).Load_2)(self as *const _ as *mut _, assemblyString, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn Load_3(
|
||||
&self,
|
||||
rawAssembly: *mut SAFEARRAY,
|
||||
pRetVal: *mut *mut _Assembly,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).Load_3)(self as *const _ as *mut _, rawAssembly, pRetVal)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interface for _AppDomain {
|
||||
const IID: GUID = GUID::from_values(
|
||||
0x05F696DC,
|
||||
0x2B29,
|
||||
0x3663,
|
||||
[0xAD, 0x8B, 0xC4, 0x38, 0x9C, 0xF2, 0xA7, 0x13],
|
||||
);
|
||||
|
||||
fn vtable(&self) -> *const c_void {
|
||||
self.vtable as *const _ as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for _AppDomain {
|
||||
type Target = IUnknown;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &IUnknown {
|
||||
unsafe { &*(self as *const _AppDomain as *const IUnknown) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,288 @@
|
||||
use crate::primitives::{
|
||||
itype::_Type, IUnknown, IUnknownVtbl, Interface, _MethodInfo, empty_array,
|
||||
wrap_method_arguments, wrap_strings_in_array, GUID, HRESULT,
|
||||
};
|
||||
use std::{
|
||||
ffi::{c_long, c_void},
|
||||
ops::Deref,
|
||||
ptr,
|
||||
};
|
||||
use windows::{
|
||||
core::BSTR,
|
||||
Win32::System::{
|
||||
Com::{SAFEARRAY, VARIANT, VT_UNKNOWN},
|
||||
Ole::{SafeArrayCreateVector, SafeArrayGetElement, SafeArrayGetLBound, SafeArrayGetUBound},
|
||||
},
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct _Assembly {
|
||||
pub vtable: *const _AssemblyVtbl,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct _AssemblyVtbl {
|
||||
pub parent: IUnknownVtbl,
|
||||
pub GetTypeInfoCount: *const c_void,
|
||||
pub GetTypeInfo: *const c_void,
|
||||
pub GetIDsOfNames: *const c_void,
|
||||
pub Invoke: *const c_void,
|
||||
pub ToString: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
|
||||
pub Equals: *const c_void,
|
||||
pub GetHashCode: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut c_long) -> HRESULT,
|
||||
pub GetType: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut _Type) -> HRESULT,
|
||||
pub get_CodeBase:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
|
||||
pub get_EscapedCodeBase:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
|
||||
pub GetName: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut c_void) -> HRESULT,
|
||||
pub GetName_2: *const c_void,
|
||||
pub get_FullName:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
|
||||
pub get_EntryPoint:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut _MethodInfo) -> HRESULT,
|
||||
pub GetType_2: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
name: *mut u16,
|
||||
pRetVal: *mut *mut _Type,
|
||||
) -> HRESULT,
|
||||
pub GetType_3: *const c_void,
|
||||
pub GetExportedTypes: *const c_void,
|
||||
pub GetTypes:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut SAFEARRAY) -> HRESULT,
|
||||
pub GetManifestResourceStream: *const c_void,
|
||||
pub GetManifestResourceStream_2: *const c_void,
|
||||
pub GetFile: *const c_void,
|
||||
pub GetFiles: *const c_void,
|
||||
pub GetFiles_2: *const c_void,
|
||||
pub GetManifestResourceNames: *const c_void,
|
||||
pub GetManifestResourceInfo: *const c_void,
|
||||
pub get_Location:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
|
||||
pub get_Evidence: *const c_void,
|
||||
pub GetCustomAttributes: *const c_void,
|
||||
pub GetCustomAttributes_2: *const c_void,
|
||||
pub IsDefined: *const c_void,
|
||||
pub GetObjectData: *const c_void,
|
||||
pub add_ModuleResolve: *const c_void,
|
||||
pub remove_ModuleResolve: *const c_void,
|
||||
pub GetType_4: *const c_void,
|
||||
pub GetSatelliteAssembly: *const c_void,
|
||||
pub GetSatelliteAssembly_2: *const c_void,
|
||||
pub LoadModule: *const c_void,
|
||||
pub LoadModule_2: *const c_void,
|
||||
pub CreateInstance: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
typeName: *mut u16,
|
||||
pRetVal: *mut VARIANT,
|
||||
) -> HRESULT,
|
||||
pub CreateInstance_2: *const c_void,
|
||||
pub CreateInstance_3: *const c_void,
|
||||
pub GetLoadedModules: *const c_void,
|
||||
pub GetLoadedModules_2: *const c_void,
|
||||
pub GetModules: *const c_void,
|
||||
pub GetModules_2: *const c_void,
|
||||
pub GetModule: *const c_void,
|
||||
pub GetReferencedAssemblies: *const c_void,
|
||||
pub get_GlobalAssemblyCache: *const c_void,
|
||||
}
|
||||
|
||||
impl _Assembly {
|
||||
pub fn run_entrypoint(&self, args: &[String]) -> Result<VARIANT, String> {
|
||||
let entrypoint = unsafe { (*self).get_entrypoint()? };
|
||||
let signature = unsafe { (*entrypoint).to_string()? };
|
||||
|
||||
if signature.ends_with("Main()") {
|
||||
return unsafe { (*entrypoint).invoke_without_args() };
|
||||
}
|
||||
|
||||
if signature.ends_with("Main(System.String[])") {
|
||||
let args_variant = wrap_strings_in_array(args)?;
|
||||
let mut method_args = wrap_method_arguments(vec![args_variant])?;
|
||||
|
||||
return unsafe { (*entrypoint).invoke(method_args) };
|
||||
}
|
||||
|
||||
Err(format!(
|
||||
"Cannot handle an entrypoint with this method signature: {}",
|
||||
signature
|
||||
))
|
||||
}
|
||||
|
||||
pub fn get_entrypoint(&self) -> Result<*mut _MethodInfo, String> {
|
||||
let mut method_info_ptr: *mut _MethodInfo = ptr::null_mut();
|
||||
|
||||
let hr = unsafe { (*self).get_EntryPoint(&mut method_info_ptr) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Could not retrieve entrypoint: {:?}", hr));
|
||||
}
|
||||
|
||||
if method_info_ptr.is_null() {
|
||||
return Err("Could not retrieve entrypoint".into());
|
||||
}
|
||||
|
||||
Ok(method_info_ptr)
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> Result<String, String> {
|
||||
let mut buffer = BSTR::new();
|
||||
|
||||
let hr = unsafe { (*self).ToString(&mut buffer as *mut _ as *mut *mut u16) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Failed while running `ToString`: {:?}", hr));
|
||||
}
|
||||
|
||||
Ok(buffer.to_string())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn ToString(&self, pRetVal: *mut *mut u16) -> HRESULT {
|
||||
((*self.vtable).ToString)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetHashCode(&self, pRetVal: *mut c_long) -> HRESULT {
|
||||
((*self.vtable).GetHashCode)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetType(&self, pRetVal: *mut *mut _Type) -> HRESULT {
|
||||
((*self.vtable).GetType)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_CodeBase(&self, pRetVal: *mut *mut u16) -> HRESULT {
|
||||
((*self.vtable).get_CodeBase)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_EscapedCodeBase(&self, pRetVal: *mut *mut u16) -> HRESULT {
|
||||
((*self.vtable).get_EscapedCodeBase)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetName(&self, pRetVal: *mut *mut c_void) -> HRESULT {
|
||||
((*self.vtable).GetName)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_FullName(&self, pRetVal: *mut *mut u16) -> HRESULT {
|
||||
((*self.vtable).get_FullName)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_EntryPoint(&self, pRetVal: *mut *mut _MethodInfo) -> HRESULT {
|
||||
((*self.vtable).get_EntryPoint)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetType_2(&self, name: *mut u16, pRetVal: *mut *mut _Type) -> HRESULT {
|
||||
((*self.vtable).GetType_2)(self as *const _ as *mut _, name, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetTypes(&self, pRetVal: *mut *mut SAFEARRAY) -> HRESULT {
|
||||
((*self.vtable).GetTypes)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_Location(&self, pRetVal: *mut *mut u16) -> HRESULT {
|
||||
((*self.vtable).get_Location)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn CreateInstance(&self, typeName: *mut u16, pRetVal: *mut VARIANT) -> HRESULT {
|
||||
((*self.vtable).CreateInstance)(self as *const _ as *mut _, typeName, pRetVal)
|
||||
}
|
||||
|
||||
pub fn create_instance(&self, name: &str) -> Result<VARIANT, String> {
|
||||
let mut dw = BSTR::from(name);
|
||||
|
||||
let mut instance: VARIANT = VARIANT::default();
|
||||
let hr = unsafe { (*self).CreateInstance(dw.into_raw() as *mut _, &mut instance) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!(
|
||||
"Error while creating instance of `{}`: 0x{:x}",
|
||||
name, hr.0
|
||||
));
|
||||
}
|
||||
|
||||
Ok(instance)
|
||||
}
|
||||
|
||||
pub fn get_type(&self, name: &str) -> Result<*mut _Type, String> {
|
||||
let mut dw = BSTR::from(name);
|
||||
|
||||
let mut type_ptr: *mut _Type = ptr::null_mut();
|
||||
let hr = unsafe { (*self).GetType_2(dw.into_raw() as *mut _, &mut type_ptr) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!(
|
||||
"Error while retrieving type `{}`: 0x{:x}",
|
||||
name, hr.0
|
||||
));
|
||||
}
|
||||
|
||||
if type_ptr.is_null() {
|
||||
return Err(format!("Could not retrieve type `{}`", name));
|
||||
}
|
||||
|
||||
Ok(type_ptr)
|
||||
}
|
||||
|
||||
pub fn get_types(&self) -> Result<Vec<*mut _Type>, String> {
|
||||
let mut results: Vec<*mut _Type> = vec![];
|
||||
|
||||
let mut safe_array_ptr: *mut SAFEARRAY = unsafe { SafeArrayCreateVector(VT_UNKNOWN, 0, 0) };
|
||||
|
||||
let hr = unsafe { (*self).GetTypes(&mut safe_array_ptr) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Error while retrieving types: 0x{:x}", hr.0));
|
||||
}
|
||||
|
||||
let ubound = unsafe { SafeArrayGetUBound(safe_array_ptr, 1) }.unwrap_or(0);
|
||||
|
||||
for i in 0..ubound {
|
||||
let indices: [i32; 1] = [i as _];
|
||||
let mut variant: *mut _Type = ptr::null_mut();
|
||||
let pv = &mut variant as *mut _ as *mut c_void;
|
||||
|
||||
match unsafe { SafeArrayGetElement(safe_array_ptr, indices.as_ptr(), pv) } {
|
||||
Ok(_) => {},
|
||||
Err(e) => return Err(format!("Could not access safe array: {:?}", e.code())),
|
||||
}
|
||||
|
||||
if !pv.is_null() {
|
||||
results.push(variant)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interface for _Assembly {
|
||||
const IID: GUID = GUID::from_values(
|
||||
0x17156360,
|
||||
0x2f1a,
|
||||
0x384a,
|
||||
[0xbc, 0x52, 0xfd, 0xe9, 0x3c, 0x21, 0x5c, 0x5b],
|
||||
);
|
||||
|
||||
fn vtable(&self) -> *const c_void {
|
||||
self.vtable as *const _ as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for _Assembly {
|
||||
type Target = IUnknown;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &IUnknown {
|
||||
unsafe { &*(self as *const _Assembly as *const IUnknown) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
use crate::primitives::{
|
||||
Class, ICLRRuntimeInfo, IEnumUnknown, IUnknown, IUnknownVtbl, Interface, GUID, HRESULT,
|
||||
};
|
||||
use std::{ffi::c_void, ops::Deref, ptr};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ICLRMetaHostVtbl {
|
||||
pub parent: IUnknownVtbl,
|
||||
pub GetRuntime: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pwzVersion: *mut u16,
|
||||
riid: *const GUID,
|
||||
ppRuntime: *mut *mut c_void,
|
||||
) -> HRESULT,
|
||||
pub GetVersionFromFile: unsafe extern "system" fn(this: *mut c_void) -> HRESULT,
|
||||
pub EnumerateInstalledRuntimes: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
ppEnumerator: *mut *mut IEnumUnknown,
|
||||
) -> HRESULT,
|
||||
pub EnumerateLoadedRuntimes: unsafe extern "system" fn(this: *mut c_void) -> HRESULT,
|
||||
pub RequestRuntimeLoadedNotification: unsafe extern "system" fn(this: *mut c_void) -> HRESULT,
|
||||
pub QueryLegacyV2RuntimeBinding: unsafe extern "system" fn(this: *mut c_void) -> HRESULT,
|
||||
pub ExitProcess: unsafe extern "system" fn(this: *mut c_void) -> HRESULT,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[repr(C)]
|
||||
pub struct ICLRMetaHost {
|
||||
pub vtable: *const ICLRMetaHostVtbl,
|
||||
}
|
||||
|
||||
pub type CLRCreateInstance =
|
||||
fn(class_id: *const GUID, interface_id: *const GUID, interface: *mut *mut c_void) -> HRESULT;
|
||||
|
||||
impl ICLRMetaHost {
|
||||
pub fn new(clr_create_instance: CLRCreateInstance) -> Result<*mut ICLRMetaHost, String> {
|
||||
let mut ppv: *mut ICLRMetaHost = ptr::null_mut();
|
||||
|
||||
let hr = unsafe {
|
||||
clr_create_instance(
|
||||
&ICLRMetaHost::CLSID,
|
||||
&ICLRMetaHost::IID,
|
||||
&mut ppv as *mut *mut _ as *mut *mut c_void,
|
||||
)
|
||||
};
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("{:?}", hr));
|
||||
}
|
||||
|
||||
if ppv.is_null() {
|
||||
return Err("Could not retrieve ICLRMetaHost".into());
|
||||
}
|
||||
|
||||
return Ok(ppv);
|
||||
}
|
||||
|
||||
pub fn get_first_available_runtime(&self) -> Result<*mut ICLRRuntimeInfo, String> {
|
||||
let runtimes = self.get_installed_runtimes()?;
|
||||
|
||||
if runtimes.len() > 0 {
|
||||
Ok(runtimes[0])
|
||||
} else {
|
||||
Err("Could not find any runtimes".into())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_runtime(&self, version: *mut u16) -> Result<*mut ICLRRuntimeInfo, String> {
|
||||
let mut ppv: *mut ICLRRuntimeInfo = ptr::null_mut();
|
||||
|
||||
let hr = unsafe {
|
||||
(*self).GetRuntime(
|
||||
version,
|
||||
&ICLRRuntimeInfo::IID,
|
||||
&mut ppv as *mut *mut _ as *mut *mut c_void,
|
||||
)
|
||||
};
|
||||
|
||||
return match hr.is_ok() {
|
||||
true => Ok(ppv),
|
||||
false => Err(format!("{:?}", hr)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_installed_runtimes(&self) -> Result<Vec<*mut ICLRRuntimeInfo>, String> {
|
||||
let mut ieu_ptr: *mut IEnumUnknown = ptr::null_mut();
|
||||
|
||||
let hr = unsafe { (*self).EnumerateInstalledRuntimes(&mut ieu_ptr) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("{:?}", hr));
|
||||
}
|
||||
|
||||
if ieu_ptr.is_null() {
|
||||
return Err("Could not enumerate installed runtimes.".into());
|
||||
}
|
||||
|
||||
let mut hmri: Vec<*mut ICLRRuntimeInfo> = vec![];
|
||||
|
||||
loop {
|
||||
let mut iu_ptr: *mut IUnknown = ptr::null_mut();
|
||||
let mut cfetched: u32 = 0;
|
||||
|
||||
let next_hr = unsafe { (*ieu_ptr).Next(1, &mut iu_ptr, &mut cfetched) };
|
||||
|
||||
if next_hr.is_err() || iu_ptr.is_null() {
|
||||
break;
|
||||
}
|
||||
|
||||
let mut ri_ptr: *mut ICLRRuntimeInfo = ptr::null_mut();
|
||||
|
||||
let inner_hr = unsafe {
|
||||
(*iu_ptr).QueryInterface(
|
||||
&ICLRRuntimeInfo::IID,
|
||||
&mut ri_ptr as *mut _ as *mut *mut c_void,
|
||||
)
|
||||
};
|
||||
|
||||
if inner_hr.is_err() || ri_ptr.is_null() {
|
||||
break;
|
||||
}
|
||||
|
||||
hmri.push(ri_ptr);
|
||||
}
|
||||
|
||||
Ok(hmri)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetRuntime(
|
||||
&self,
|
||||
pwzVersion: *mut u16,
|
||||
riid: *const GUID,
|
||||
ppRuntime: *mut *mut c_void,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).GetRuntime)(self as *const _ as *mut _, pwzVersion, riid, ppRuntime)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn EnumerateInstalledRuntimes(
|
||||
&self,
|
||||
ppEnumerator: *mut *mut IEnumUnknown,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).EnumerateInstalledRuntimes)(self as *const _ as *mut _, ppEnumerator)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interface for ICLRMetaHost {
|
||||
const IID: GUID = GUID {
|
||||
data1: 0xD332DB9E,
|
||||
data2: 0xB9B3,
|
||||
data3: 0x4125,
|
||||
data4: [0x82, 0x07, 0xA1, 0x48, 0x84, 0xF5, 0x32, 0x16],
|
||||
};
|
||||
|
||||
fn vtable(&self) -> *const c_void {
|
||||
self.vtable as *const _ as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
impl Class for ICLRMetaHost {
|
||||
const CLSID: GUID = GUID {
|
||||
data1: 0x9280188d,
|
||||
data2: 0xe8e,
|
||||
data3: 0x4867,
|
||||
data4: [0xb3, 0xc, 0x7f, 0xa8, 0x38, 0x84, 0xe8, 0xde],
|
||||
};
|
||||
}
|
||||
|
||||
impl Deref for ICLRMetaHost {
|
||||
type Target = IUnknown;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &IUnknown {
|
||||
unsafe { &*(self as *const ICLRMetaHost as *const IUnknown) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
use crate::primitives::{
|
||||
Class, ICorRuntimeHost, IUnknown, IUnknownVtbl, Interface, BOOL, GUID, HANDLE, HRESULT,
|
||||
};
|
||||
use std::{ffi::c_void, ops::Deref, ptr};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ICLRRuntimeInfo {
|
||||
pub vtable: *const ICLRRuntimeInfoVtbl,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ICLRRuntimeInfoVtbl {
|
||||
pub parent: IUnknownVtbl,
|
||||
pub GetVersionString: unsafe extern "system" fn(
|
||||
This: *mut ICLRRuntimeInfo,
|
||||
pwzBuffer: *mut u16,
|
||||
pcchBuffer: *mut u32,
|
||||
) -> HRESULT,
|
||||
pub GetRuntimeDirectory: unsafe extern "system" fn(
|
||||
This: *mut ICLRRuntimeInfo,
|
||||
pwzBuffer: *mut u16,
|
||||
pcchBuffer: *mut u32,
|
||||
) -> HRESULT,
|
||||
pub IsLoaded: unsafe extern "system" fn(
|
||||
This: *mut ICLRRuntimeInfo,
|
||||
hndProcess: HANDLE,
|
||||
pbLoaded: *mut BOOL,
|
||||
) -> HRESULT,
|
||||
pub LoadErrorString: unsafe extern "system" fn(
|
||||
This: *mut ICLRRuntimeInfo,
|
||||
iResourceID: u32,
|
||||
pwzBuffer: *mut u16,
|
||||
pcchBuffer: *mut u32,
|
||||
iLocaleID: u32,
|
||||
) -> HRESULT,
|
||||
pub LoadLibrary: unsafe extern "system" fn(
|
||||
This: *mut ICLRRuntimeInfo,
|
||||
pwzDllName: *const u16,
|
||||
ppProc: *mut *mut c_void,
|
||||
) -> HRESULT,
|
||||
pub GetProcAddress: unsafe extern "system" fn(
|
||||
This: *mut ICLRRuntimeInfo,
|
||||
pszProcName: *const i8,
|
||||
ppProc: *mut *mut c_void,
|
||||
) -> HRESULT,
|
||||
pub GetInterface: unsafe extern "system" fn(
|
||||
This: *mut ICLRRuntimeInfo,
|
||||
rclsid: *const GUID,
|
||||
riid: *const GUID,
|
||||
ppUnk: *mut *mut c_void,
|
||||
) -> HRESULT,
|
||||
pub IsLoadable:
|
||||
unsafe extern "system" fn(This: *mut ICLRRuntimeInfo, pbLoadable: *mut BOOL) -> HRESULT,
|
||||
pub SetDefaultStartupFlags: unsafe extern "system" fn(
|
||||
This: *mut ICLRRuntimeInfo,
|
||||
dwStartupFlags: u32,
|
||||
pwzHostConfigFile: *const u16,
|
||||
) -> HRESULT,
|
||||
pub GetDefaultStartupFlags: unsafe extern "system" fn(
|
||||
This: *mut ICLRRuntimeInfo,
|
||||
pdwStartupFlags: *mut u32,
|
||||
pwzHostConfigFile: *mut u16,
|
||||
pcchHostConfigFile: *mut u32,
|
||||
) -> HRESULT,
|
||||
pub BindAsLegacyV2Runtime: unsafe extern "system" fn(This: *mut ICLRRuntimeInfo) -> HRESULT,
|
||||
pub IsStarted: unsafe extern "system" fn(
|
||||
This: *mut ICLRRuntimeInfo,
|
||||
pbStarted: *mut BOOL,
|
||||
pdwStartupFlags: *mut u32,
|
||||
) -> HRESULT,
|
||||
}
|
||||
|
||||
impl ICLRRuntimeInfo {
|
||||
pub fn get_runtime_host(&self) -> Result<*mut ICorRuntimeHost, String> {
|
||||
let mut ppv: *mut ICorRuntimeHost = ptr::null_mut();
|
||||
|
||||
let hr = unsafe {
|
||||
(*self).GetInterface(
|
||||
&ICorRuntimeHost::CLSID,
|
||||
&ICorRuntimeHost::IID,
|
||||
&mut ppv as *mut *mut _ as *mut *mut c_void,
|
||||
)
|
||||
};
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Could not retrieve ICorRuntimeHost: {:?}", hr));
|
||||
}
|
||||
|
||||
if ppv.is_null() {
|
||||
return Err("Could not retrieve ICorRuntimeHost".into());
|
||||
}
|
||||
|
||||
return Ok(ppv);
|
||||
}
|
||||
|
||||
pub fn has_started() -> Result<bool, String> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetVersionString(&self, pwzBuffer: *mut u16, pcchBuffer: *mut u32) -> HRESULT {
|
||||
((*self.vtable).GetVersionString)(self as *const _ as *mut _, pwzBuffer, pcchBuffer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetRuntimeDirectory(&self, pwzBuffer: *mut u16, pcchBuffer: *mut u32) -> HRESULT {
|
||||
((*self.vtable).GetRuntimeDirectory)(self as *const _ as *mut _, pwzBuffer, pcchBuffer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn IsLoaded(&self, hndProcess: HANDLE, pbLoaded: *mut BOOL) -> HRESULT {
|
||||
((*self.vtable).IsLoaded)(self as *const _ as *mut _, hndProcess, pbLoaded)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn LoadErrorString(
|
||||
&self,
|
||||
iResourceID: u32,
|
||||
pwzBuffer: *mut u16,
|
||||
pcchBuffer: *mut u32,
|
||||
iLocaleID: u32,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).LoadErrorString)(
|
||||
self as *const _ as *mut _,
|
||||
iResourceID,
|
||||
pwzBuffer,
|
||||
pcchBuffer,
|
||||
iLocaleID,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn LoadLibrary(&self, pwzDllName: *const u16, ppProc: *mut *mut c_void) -> HRESULT {
|
||||
((*self.vtable).LoadLibrary)(self as *const _ as *mut _, pwzDllName, ppProc)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetProcAddress(
|
||||
&self,
|
||||
pszProcName: *const i8,
|
||||
ppProc: *mut *mut c_void,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).GetProcAddress)(self as *const _ as *mut _, pszProcName, ppProc)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetInterface(
|
||||
&self,
|
||||
rclsid: *const GUID,
|
||||
riid: *const GUID,
|
||||
ppUnk: *mut *mut c_void,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).GetInterface)(self as *const _ as *mut _, rclsid, riid, ppUnk)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn IsLoadable(&self, pbLoadable: *mut BOOL) -> HRESULT {
|
||||
((*self.vtable).IsLoadable)(self as *const _ as *mut _, pbLoadable)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn SetDefaultStartupFlags(
|
||||
&self,
|
||||
dwStartupFlags: u32,
|
||||
pwzHostConfigFile: *const u16,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).SetDefaultStartupFlags)(
|
||||
self as *const _ as *mut _,
|
||||
dwStartupFlags,
|
||||
pwzHostConfigFile,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetDefaultStartupFlags(
|
||||
&self,
|
||||
pdwStartupFlags: *mut u32,
|
||||
pwzHostConfigFile: *mut u16,
|
||||
pcchHostConfigFile: *mut u32,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).GetDefaultStartupFlags)(
|
||||
self as *const _ as *mut _,
|
||||
pdwStartupFlags,
|
||||
pwzHostConfigFile,
|
||||
pcchHostConfigFile,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn BindAsLegacyV2Runtime(&self) -> HRESULT {
|
||||
((*self.vtable).BindAsLegacyV2Runtime)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn IsStarted(&self, pbStarted: *mut BOOL, pdwStartupFlags: *mut u32) -> HRESULT {
|
||||
((*self.vtable).IsStarted)(self as *const _ as *mut _, pbStarted, pdwStartupFlags)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interface for ICLRRuntimeInfo {
|
||||
const IID: GUID = GUID::from_values(
|
||||
0xBD39D1D2,
|
||||
0xBA2F,
|
||||
0x486a,
|
||||
[0x89, 0xB0, 0xB4, 0xB0, 0xCB, 0x46, 0x68, 0x91],
|
||||
);
|
||||
|
||||
fn vtable(&self) -> *const c_void {
|
||||
self.vtable as *const _ as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for ICLRRuntimeInfo {
|
||||
type Target = IUnknown;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &IUnknown {
|
||||
unsafe { &*(self as *const ICLRRuntimeInfo as *const IUnknown) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,266 @@
|
||||
use std::{ffi::c_void, ops::Deref, ptr};
|
||||
|
||||
use crate::primitives::{
|
||||
Class, IUnknown, IUnknownVtbl, Interface, _AppDomain, GUID, HANDLE, HINSTANCE, HRESULT,
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ICorRuntimeHost {
|
||||
pub vtable: *const ICorRuntimeHostVtbl,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ICorRuntimeHostVtbl {
|
||||
pub parent: IUnknownVtbl,
|
||||
pub CreateLogicalThreadState: unsafe extern "system" fn(This: *mut ICorRuntimeHost) -> HRESULT,
|
||||
pub DeleteLogicalThreadState: unsafe extern "system" fn(This: *mut ICorRuntimeHost) -> HRESULT,
|
||||
pub SwitchInLogicalThreadState:
|
||||
unsafe extern "system" fn(This: *mut ICorRuntimeHost, pFiberCookie: *mut u32) -> HRESULT,
|
||||
pub SwitchOutLogicalThreadState: unsafe extern "system" fn(
|
||||
This: *mut ICorRuntimeHost,
|
||||
pFiberCookie: *mut *mut u32,
|
||||
) -> HRESULT,
|
||||
pub LocksHeldByLogicalThread:
|
||||
unsafe extern "system" fn(This: *mut ICorRuntimeHost, pCount: *mut u32) -> HRESULT,
|
||||
pub MapFile: unsafe extern "system" fn(
|
||||
This: *mut ICorRuntimeHost,
|
||||
hFile: HANDLE,
|
||||
hMapAddress: *mut HINSTANCE,
|
||||
) -> HRESULT,
|
||||
pub GetConfiguration: unsafe extern "system" fn(
|
||||
This: *mut ICorRuntimeHost,
|
||||
pConfiguration: *mut *mut c_void,
|
||||
) -> HRESULT,
|
||||
pub Start: unsafe extern "system" fn(This: *mut ICorRuntimeHost) -> HRESULT,
|
||||
pub Stop: unsafe extern "system" fn(This: *mut ICorRuntimeHost) -> HRESULT,
|
||||
pub CreateDomain: unsafe extern "system" fn(
|
||||
This: *mut ICorRuntimeHost,
|
||||
pwzFriendlyName: *const u16,
|
||||
pIdentityArray: *mut IUnknown,
|
||||
pAppDomain: *mut *mut IUnknown,
|
||||
) -> HRESULT,
|
||||
pub GetDefaultDomain: unsafe extern "system" fn(
|
||||
This: *mut ICorRuntimeHost,
|
||||
pAppDomain: *mut *mut IUnknown,
|
||||
) -> HRESULT,
|
||||
pub EnumDomains:
|
||||
unsafe extern "system" fn(This: *mut ICorRuntimeHost, hEnum: *mut *mut c_void) -> HRESULT,
|
||||
pub NextDomain: unsafe extern "system" fn(
|
||||
This: *mut ICorRuntimeHost,
|
||||
hEnum: *mut c_void,
|
||||
pAppDomain: *mut *mut IUnknown,
|
||||
) -> HRESULT,
|
||||
pub CloseEnum:
|
||||
unsafe extern "system" fn(This: *mut ICorRuntimeHost, hEnum: *mut c_void) -> HRESULT,
|
||||
pub CreateDomainEx: unsafe extern "system" fn(
|
||||
This: *mut ICorRuntimeHost,
|
||||
pwzFriendlyName: *const u16,
|
||||
pSetup: *mut IUnknown,
|
||||
pEvidence: *mut IUnknown,
|
||||
pAppDomain: *mut *mut IUnknown,
|
||||
) -> HRESULT,
|
||||
pub CreateDomainSetup: unsafe extern "system" fn(
|
||||
This: *mut ICorRuntimeHost,
|
||||
pAppDomain: *mut *mut IUnknown,
|
||||
) -> HRESULT,
|
||||
pub CreateEvidence: unsafe extern "system" fn(
|
||||
This: *mut ICorRuntimeHost,
|
||||
pEvidence: *mut *mut IUnknown,
|
||||
) -> HRESULT,
|
||||
pub UnloadDomain:
|
||||
unsafe extern "system" fn(This: *mut ICorRuntimeHost, pAppDomain: *mut IUnknown) -> HRESULT,
|
||||
pub CurrentDomain: unsafe extern "system" fn(
|
||||
This: *mut ICorRuntimeHost,
|
||||
pAppDomain: *mut *mut IUnknown,
|
||||
) -> HRESULT,
|
||||
}
|
||||
|
||||
impl ICorRuntimeHost {
|
||||
pub fn start(&self) -> Result<(), String> {
|
||||
return match unsafe { (*self).Start().ok() } {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(format!("Could not start runtime host: {:?}", e)),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn get_default_domain(&self) -> Result<*mut _AppDomain, String> {
|
||||
let mut unknown: *mut IUnknown = ptr::null_mut();
|
||||
|
||||
let hr = unsafe { (*self).GetDefaultDomain(&mut unknown) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Could not retrieve default app domain: {:?}", hr));
|
||||
}
|
||||
|
||||
if unknown.is_null() {
|
||||
return Err("Could not retrieve default app domain".into());
|
||||
}
|
||||
|
||||
let mut app_domain: *mut _AppDomain = ptr::null_mut();
|
||||
|
||||
let hr = unsafe {
|
||||
(*unknown).QueryInterface(
|
||||
&_AppDomain::IID,
|
||||
&mut app_domain as *mut *mut _ as *mut *mut c_void,
|
||||
)
|
||||
};
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Could not retrieve default app domain: {:?}", hr));
|
||||
}
|
||||
|
||||
if app_domain.is_null() {
|
||||
return Err("Could not retrieve default app domain".into());
|
||||
}
|
||||
|
||||
Ok(app_domain)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn CreateLogicalThreadState(&self) -> HRESULT {
|
||||
((*self.vtable).CreateLogicalThreadState)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn DeleteLogicalThreadState(&self) -> HRESULT {
|
||||
((*self.vtable).DeleteLogicalThreadState)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn SwitchInLogicalThreadState(&self, pFiberCookie: *mut u32) -> HRESULT {
|
||||
((*self.vtable).SwitchInLogicalThreadState)(self as *const _ as *mut _, pFiberCookie)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn SwitchOutLogicalThreadState(&self, pFiberCookie: *mut *mut u32) -> HRESULT {
|
||||
((*self.vtable).SwitchOutLogicalThreadState)(self as *const _ as *mut _, pFiberCookie)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn LocksHeldByLogicalThread(&self, pCount: *mut u32) -> HRESULT {
|
||||
((*self.vtable).LocksHeldByLogicalThread)(self as *const _ as *mut _, pCount)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn MapFile(&self, hFile: HANDLE, hMapAddress: *mut HINSTANCE) -> HRESULT {
|
||||
((*self.vtable).MapFile)(self as *const _ as *mut _, hFile, hMapAddress)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetConfiguration(&self, pConfiguration: *mut *mut c_void) -> HRESULT {
|
||||
((*self.vtable).GetConfiguration)(self as *const _ as *mut _, pConfiguration)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn Start(&self) -> HRESULT {
|
||||
((*self.vtable).Start)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn Stop(&self) -> HRESULT {
|
||||
((*self.vtable).Stop)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn CreateDomain(
|
||||
&self,
|
||||
pwzFriendlyName: *const u16,
|
||||
pIdentityArray: *mut IUnknown,
|
||||
pAppDomain: *mut *mut IUnknown,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).CreateDomain)(
|
||||
self as *const _ as *mut _,
|
||||
pwzFriendlyName,
|
||||
pIdentityArray,
|
||||
pAppDomain,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetDefaultDomain(&self, pAppDomain: *mut *mut IUnknown) -> HRESULT {
|
||||
((*self.vtable).GetDefaultDomain)(self as *const _ as *mut _, pAppDomain)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn EnumDomains(&self, hEnum: *mut *mut c_void) -> HRESULT {
|
||||
((*self.vtable).EnumDomains)(self as *const _ as *mut _, hEnum)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn NextDomain(&self, hEnum: *mut c_void, pAppDomain: *mut *mut IUnknown) -> HRESULT {
|
||||
((*self.vtable).NextDomain)(self as *const _ as *mut _, hEnum, pAppDomain)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn CloseEnum(&self, hEnum: *mut c_void) -> HRESULT {
|
||||
((*self.vtable).CloseEnum)(self as *const _ as *mut _, hEnum)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn CreateDomainEx(
|
||||
&self,
|
||||
pwzFriendlyName: *const u16,
|
||||
pSetup: *mut IUnknown,
|
||||
pEvidence: *mut IUnknown,
|
||||
pAppDomain: *mut *mut IUnknown,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).CreateDomainEx)(
|
||||
self as *const _ as *mut _,
|
||||
pwzFriendlyName,
|
||||
pSetup,
|
||||
pEvidence,
|
||||
pAppDomain,
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn CreateDomainSetup(&self, pAppDomain: *mut *mut IUnknown) -> HRESULT {
|
||||
((*self.vtable).CreateDomainSetup)(self as *const _ as *mut _, pAppDomain)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn CreateEvidence(&self, pEvidence: *mut *mut IUnknown) -> HRESULT {
|
||||
((*self.vtable).CreateEvidence)(self as *const _ as *mut _, pEvidence)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn UnloadDomain(&self, pAppDomain: *mut IUnknown) -> HRESULT {
|
||||
((*self.vtable).UnloadDomain)(self as *const _ as *mut _, pAppDomain)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn CurrentDomain(&self, pAppDomain: *mut *mut IUnknown) -> HRESULT {
|
||||
((*self.vtable).CurrentDomain)(self as *const _ as *mut _, pAppDomain)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interface for ICorRuntimeHost {
|
||||
const IID: GUID = GUID::from_values(
|
||||
0xCB2F6722,
|
||||
0xAB3A,
|
||||
0x11d2,
|
||||
[0x9C, 0x40, 0x00, 0xC0, 0x4F, 0xA3, 0x0A, 0x3E],
|
||||
);
|
||||
|
||||
fn vtable(&self) -> *const c_void {
|
||||
self.vtable as *const _ as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
impl Class for ICorRuntimeHost {
|
||||
const CLSID: GUID = GUID::from_values(
|
||||
0xcb2f6723,
|
||||
0xab3a,
|
||||
0x11d2,
|
||||
[0x9c, 0x40, 0x00, 0xc0, 0x4f, 0xa3, 0x0a, 0x3e],
|
||||
);
|
||||
}
|
||||
|
||||
impl Deref for ICorRuntimeHost {
|
||||
type Target = IUnknown;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &IUnknown {
|
||||
unsafe { &*(self as *const ICorRuntimeHost as *const IUnknown) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
use crate::primitives::{IUnknown, IUnknownVtbl, Interface, GUID, HRESULT};
|
||||
use std::{ffi::c_void, ops::Deref};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct IEnumUnknown {
|
||||
pub vtable: *const IEnumUnknownVtbl,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct IEnumUnknownVtbl {
|
||||
pub parent: IUnknownVtbl,
|
||||
pub Next: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
celt: u32,
|
||||
rgelt: *mut *mut IUnknown,
|
||||
pceltFetched: *mut u32,
|
||||
) -> HRESULT,
|
||||
pub Skip: unsafe extern "system" fn(this: *mut c_void, celt: u32) -> HRESULT,
|
||||
pub Reset: unsafe extern "system" fn(this: *mut c_void) -> HRESULT,
|
||||
pub Clone:
|
||||
unsafe extern "system" fn(this: *mut c_void, ppenum: *mut *mut IEnumUnknown) -> HRESULT,
|
||||
}
|
||||
|
||||
impl IEnumUnknown {
|
||||
#[inline]
|
||||
pub unsafe fn Next(
|
||||
&self,
|
||||
celt: u32,
|
||||
rgelt: *mut *mut IUnknown,
|
||||
pceltFetched: *mut u32,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).Next)(self as *const _ as *mut _, celt, rgelt, pceltFetched)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn Skip(&self, celt: u32) -> HRESULT {
|
||||
((*self.vtable).Skip)(self as *const _ as *mut _, celt)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn Reset(&self) -> HRESULT {
|
||||
((*self.vtable).Reset)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn Clone(&self, ppenum: *mut *mut IEnumUnknown) -> HRESULT {
|
||||
((*self.vtable).Clone)(self as *const _ as *mut _, ppenum)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interface for IEnumUnknown {
|
||||
const IID: GUID = GUID::from_values(
|
||||
0x00000100,
|
||||
0x0000,
|
||||
0x0000,
|
||||
[0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46],
|
||||
);
|
||||
|
||||
fn vtable(&self) -> *const c_void {
|
||||
self.vtable as *const _ as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for IEnumUnknown {
|
||||
type Target = IUnknown;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &IUnknown {
|
||||
unsafe { &*(self as *const IEnumUnknown as *const IUnknown) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
use crate::primitives::{
|
||||
empty_array, get_array_length, itype::_Type, IUnknown, IUnknownVtbl, Interface, GUID, HRESULT,
|
||||
};
|
||||
use std::{
|
||||
ffi::{c_long, c_void},
|
||||
ops::Deref,
|
||||
};
|
||||
use windows::{
|
||||
core::BSTR,
|
||||
Win32::System::{
|
||||
Com::{SAFEARRAY, VARIANT, VT_UNKNOWN},
|
||||
Ole::{SafeArrayCreateVector, SafeArrayGetLBound, SafeArrayGetUBound},
|
||||
},
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct _MethodInfo {
|
||||
pub vtable: *const _MethodInfoVtbl,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct _MethodInfoVtbl {
|
||||
pub parent: IUnknownVtbl,
|
||||
pub GetTypeInfoCount: *const c_void,
|
||||
pub GetTypeInfo: *const c_void,
|
||||
pub GetIDsOfNames: *const c_void,
|
||||
pub Invoke: *const c_void,
|
||||
pub ToString: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
|
||||
pub Equals: *const c_void,
|
||||
pub GetHashCode: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut c_long) -> HRESULT,
|
||||
pub GetType: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut _Type) -> HRESULT,
|
||||
pub get_MemberType: *const c_void,
|
||||
pub get_name: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
|
||||
pub get_DeclaringType: *const c_void,
|
||||
pub get_ReflectedType: *const c_void,
|
||||
pub GetCustomAttributes: *const c_void,
|
||||
pub GetCustomAttributes_2: *const c_void,
|
||||
pub IsDefined: *const c_void,
|
||||
pub GetParameters:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut SAFEARRAY) -> HRESULT,
|
||||
pub GetMethodImplementationFlags: *const c_void,
|
||||
pub get_MethodHandle: *const c_void,
|
||||
pub get_Attributes: *const c_void,
|
||||
pub get_CallingConvention: *const c_void,
|
||||
pub Invoke_2: *const c_void,
|
||||
pub get_IsPublic: *const c_void,
|
||||
pub get_IsPrivate: *const c_void,
|
||||
pub get_IsFamily: *const c_void,
|
||||
pub get_IsAssembly: *const c_void,
|
||||
pub get_IsFamilyAndAssembly: *const c_void,
|
||||
pub get_IsFamilyOrAssembly: *const c_void,
|
||||
pub get_IsStatic: *const c_void,
|
||||
pub get_IsFinal: *const c_void,
|
||||
pub get_IsVirtual: *const c_void,
|
||||
pub get_IsHideBySig: *const c_void,
|
||||
pub get_IsAbstract: *const c_void,
|
||||
pub get_IsSpecialName: *const c_void,
|
||||
pub get_IsConstructor: *const c_void,
|
||||
pub Invoke_3: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
obj: VARIANT,
|
||||
parameters: *mut SAFEARRAY,
|
||||
pRetVal: *mut VARIANT,
|
||||
) -> HRESULT,
|
||||
pub get_returnType: *const c_void,
|
||||
pub get_ReturnTypeCustomAttributes: *const c_void,
|
||||
pub GetBaseDefinition:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut _MethodInfo) -> HRESULT,
|
||||
}
|
||||
|
||||
impl _MethodInfo {
|
||||
pub fn invoke(&self, args: *mut SAFEARRAY) -> Result<VARIANT, String> {
|
||||
let args_len = get_array_length(args);
|
||||
let parameter_count = unsafe { (*self).get_parameter_count()? };
|
||||
|
||||
if args_len != parameter_count {
|
||||
return Err(format!(
|
||||
"Arguments do not match method signature: {} given, {} expected",
|
||||
args_len, parameter_count
|
||||
));
|
||||
}
|
||||
|
||||
let mut return_value: VARIANT = unsafe { std::mem::zeroed() };
|
||||
let object: VARIANT = unsafe { std::mem::zeroed() };
|
||||
|
||||
let hr = unsafe { (*self).Invoke_3(object, args, &mut return_value) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Could not invoke method: {:?}", hr));
|
||||
}
|
||||
|
||||
Ok(return_value)
|
||||
}
|
||||
|
||||
pub fn invoke_without_args(&self) -> Result<VARIANT, String> {
|
||||
let method_args = empty_array();
|
||||
|
||||
unsafe { (*self).invoke(method_args) }
|
||||
}
|
||||
|
||||
pub fn get_parameter_count(&self) -> Result<i32, String> {
|
||||
let mut safe_array_ptr: *mut SAFEARRAY =
|
||||
unsafe { SafeArrayCreateVector(VT_UNKNOWN, 0, 255) };
|
||||
|
||||
let hr = unsafe { (*self).GetParameters(&mut safe_array_ptr) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Could not get parameter count: {:?}", hr));
|
||||
}
|
||||
|
||||
Ok(get_array_length(safe_array_ptr))
|
||||
}
|
||||
|
||||
pub fn to_string(&self) -> Result<String, String> {
|
||||
let mut buffer = BSTR::new();
|
||||
|
||||
let hr = unsafe { (*self).ToString(&mut buffer as *mut _ as *mut *mut u16) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Failed while running `ToString`: {:?}", hr));
|
||||
}
|
||||
|
||||
Ok(buffer.to_string())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn ToString(&self, pRetVal: *mut *mut u16) -> HRESULT {
|
||||
((*self.vtable).ToString)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetHashCode(&self, pRetVal: *mut c_long) -> HRESULT {
|
||||
((*self.vtable).GetHashCode)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetType(&self, pRetVal: *mut *mut _Type) -> HRESULT {
|
||||
((*self.vtable).GetType)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_name(&self, pRetVal: *mut *mut u16) -> HRESULT {
|
||||
((*self.vtable).get_name)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetParameters(&self, pRetVal: *mut *mut SAFEARRAY) -> HRESULT {
|
||||
((*self.vtable).GetParameters)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn Invoke_3(
|
||||
&self,
|
||||
obj: VARIANT,
|
||||
parameters: *mut SAFEARRAY,
|
||||
pRetVal: *mut VARIANT,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).Invoke_3)(self as *const _ as *mut _, obj, parameters, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetBaseDefinition(&self, pRetVal: *mut *mut _MethodInfo) -> HRESULT {
|
||||
((*self.vtable).GetBaseDefinition)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interface for _MethodInfo {
|
||||
const IID: GUID = GUID::from_values(
|
||||
0xffcc1b5d,
|
||||
0xecb8,
|
||||
0x38dd,
|
||||
[0x9b, 0x01, 0x3d, 0xc8, 0xab, 0xc2, 0xaa, 0x5f],
|
||||
);
|
||||
|
||||
fn vtable(&self) -> *const c_void {
|
||||
self.vtable as *const _ as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for _MethodInfo {
|
||||
type Target = IUnknown;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &IUnknown {
|
||||
unsafe { &*(self as *const _MethodInfo as *const IUnknown) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
use crate::primitives::{IUnknown, IUnknownVtbl, Interface, GUID, HRESULT};
|
||||
use std::{ffi::c_void, ops::Deref};
|
||||
use windows::core::BSTR;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct _StringWriter {
|
||||
pub vtable: *const _StringWriterVtbl,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct _StringWriterVtbl {
|
||||
pub parent: IUnknownVtbl,
|
||||
pub GetTypeInfoCount: *const c_void,
|
||||
pub GetTypeInfo: *const c_void,
|
||||
pub GetIDsOfNames: *const c_void,
|
||||
pub Invoke: *const c_void,
|
||||
pub ToString: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
|
||||
}
|
||||
|
||||
impl _StringWriter {
|
||||
pub fn to_string(&self) -> Result<String, String> {
|
||||
let mut buffer = BSTR::new();
|
||||
|
||||
let hr = unsafe { (*self).ToString(&mut buffer as *mut _ as *mut *mut u16) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Failed while running `ToString`: {:?}", hr));
|
||||
}
|
||||
|
||||
Ok(buffer.to_string())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn ToString(&self, pRetVal: *mut *mut u16) -> HRESULT {
|
||||
((*self.vtable).ToString)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interface for _StringWriter {
|
||||
const IID: GUID = GUID::from_values(
|
||||
0xcb9f94c0,
|
||||
0xd691,
|
||||
0x3b62,
|
||||
[0xb0, 0xb2, 0x3c, 0xe5, 0x30, 0x9c, 0xfa, 0x62],
|
||||
);
|
||||
|
||||
fn vtable(&self) -> *const c_void {
|
||||
self.vtable as *const _ as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for _StringWriter {
|
||||
type Target = IUnknown;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &IUnknown {
|
||||
unsafe { &*(self as *const _StringWriter as *const IUnknown) }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,392 @@
|
||||
use crate::primitives::{IUnknown, IUnknownVtbl, Interface, _Assembly, _MethodInfo, GUID, HRESULT};
|
||||
use std::{
|
||||
ffi::{c_long, c_void},
|
||||
ops::Deref,
|
||||
ptr,
|
||||
};
|
||||
use windows::{
|
||||
core::BSTR,
|
||||
Win32::System::{
|
||||
Com::{SAFEARRAY, VT_UNKNOWN},
|
||||
Ole::{SafeArrayCreateVector, SafeArrayGetElement, SafeArrayGetLBound, SafeArrayGetUBound},
|
||||
},
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct _Type {
|
||||
pub vtable: *const _TypeVtbl,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct _TypeVtbl {
|
||||
pub parent: IUnknownVtbl,
|
||||
pub GetTypeInfoCount:
|
||||
unsafe extern "system" fn(this: *mut c_void, pctinfo: *mut u32) -> HRESULT,
|
||||
pub GetTypeInfo: *const c_void,
|
||||
pub GetIDsOfNames: *const c_void,
|
||||
pub Invoke: *const c_void,
|
||||
pub ToString: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
|
||||
pub Equals: *const c_void,
|
||||
pub GetHashCode: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut c_long) -> HRESULT,
|
||||
pub GetType: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut _Type) -> HRESULT,
|
||||
pub get_MemberType: *const c_void,
|
||||
pub get_Name: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
|
||||
pub get_DeclaringType:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut _Type) -> HRESULT,
|
||||
pub get_ReflectedType:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut _Type) -> HRESULT,
|
||||
pub GetCustomAttributes: *const c_void,
|
||||
pub GetCustomAttributes_2: *const c_void,
|
||||
pub IsDefined: *const c_void,
|
||||
pub get_Guid: unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut GUID) -> HRESULT,
|
||||
pub get_Module: *const c_void,
|
||||
pub get_Assembly:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut _Assembly) -> HRESULT,
|
||||
pub get_TypeHandle: *const c_void,
|
||||
pub get_FullName:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
|
||||
pub get_Namespace:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
|
||||
pub get_AssemblyQualifiedName:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut u16) -> HRESULT,
|
||||
pub GetArrayRank: *const c_void,
|
||||
pub get_BaseType:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut _Type) -> HRESULT,
|
||||
pub GetConstructors: *const c_void,
|
||||
pub GetInterface: *const c_void,
|
||||
pub GetInterfaces: *const c_void,
|
||||
pub FindInterfaces: *const c_void,
|
||||
pub GetEvent: *const c_void,
|
||||
pub GetEvents: *const c_void,
|
||||
pub GetEvents_2: *const c_void,
|
||||
pub GetNestedTypes: *const c_void,
|
||||
pub GetNestedType: *const c_void,
|
||||
pub GetMember: *const c_void,
|
||||
pub GetDefaultMembers: *const c_void,
|
||||
pub FindMembers: *const c_void,
|
||||
pub GetElementType: *const c_void,
|
||||
pub IsSubclassOf: *const c_void,
|
||||
pub IsInstanceOfType: *const c_void,
|
||||
pub IsAssignableFrom: *const c_void,
|
||||
pub GetInterfaceMap: *const c_void,
|
||||
pub GetMethod: *const c_void,
|
||||
pub GetMethod_2: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
name: *mut u16,
|
||||
bindingAttr: BindingFlags,
|
||||
pRetVal: *mut *mut _MethodInfo,
|
||||
) -> HRESULT,
|
||||
pub GetMethods: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
bindingAttr: BindingFlags,
|
||||
pRetVal: *mut *mut SAFEARRAY,
|
||||
) -> HRESULT,
|
||||
pub GetField: *const c_void,
|
||||
pub GetFields: *const c_void,
|
||||
pub GetProperty: *const c_void,
|
||||
pub GetProperty_2: *const c_void,
|
||||
pub GetProperties: *const c_void,
|
||||
pub GetMember_2: *const c_void,
|
||||
pub GetMembers: *const c_void,
|
||||
pub InvokeMember: *const c_void,
|
||||
pub get_UnderlyingSystemType: *const c_void,
|
||||
pub InvokeMember_2: *const c_void,
|
||||
pub InvokeMember_3: *const c_void,
|
||||
pub GetConstructor: *const c_void,
|
||||
pub GetConstructor_2: *const c_void,
|
||||
pub GetConstructor_3: *const c_void,
|
||||
pub GetConstructors_2: *const c_void,
|
||||
pub get_TypeInitializer: *const c_void,
|
||||
pub GetMethod_3: *const c_void,
|
||||
pub GetMethod_4: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
name: *mut u16,
|
||||
types: *mut SAFEARRAY,
|
||||
modifiers: *mut SAFEARRAY,
|
||||
pRetVal: *mut *mut _MethodInfo,
|
||||
) -> HRESULT,
|
||||
pub GetMethod_5: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
name: *mut u16,
|
||||
types: *mut SAFEARRAY,
|
||||
pRetVal: *mut *mut _MethodInfo,
|
||||
) -> HRESULT,
|
||||
pub GetMethod_6: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
name: *mut u16,
|
||||
pRetVal: *mut *mut _MethodInfo,
|
||||
) -> HRESULT,
|
||||
pub GetMethods_2:
|
||||
unsafe extern "system" fn(this: *mut c_void, pRetVal: *mut *mut SAFEARRAY) -> HRESULT,
|
||||
pub GetField_2: *const c_void,
|
||||
pub GetFields_2: *const c_void,
|
||||
pub GetInterface_2: *const c_void,
|
||||
pub GetEvent_2: *const c_void,
|
||||
pub GetProperty_3: *const c_void,
|
||||
pub GetProperty_4: *const c_void,
|
||||
pub GetProperty_5: *const c_void,
|
||||
pub GetProperty_6: *const c_void,
|
||||
pub GetProperty_7: *const c_void,
|
||||
pub GetProperties_2: *const c_void,
|
||||
pub GetNestedTypes_2: *const c_void,
|
||||
pub GetNestedType_2: *const c_void,
|
||||
pub GetMember_3: *const c_void,
|
||||
pub GetMembers_2: *const c_void,
|
||||
pub get_Attributes: *const c_void,
|
||||
pub get_IsNotPublic: *const c_void,
|
||||
pub get_IsPublic: *const c_void,
|
||||
pub get_IsNestedPublic: *const c_void,
|
||||
pub get_IsNestedPrivate: *const c_void,
|
||||
pub get_IsNestedFamily: *const c_void,
|
||||
pub get_IsNestedAssembly: *const c_void,
|
||||
pub get_IsNestedFamANDAssem: *const c_void,
|
||||
pub get_IsNestedFamORAssem: *const c_void,
|
||||
pub get_IsAutoLayout: *const c_void,
|
||||
pub get_IsLayoutSequential: *const c_void,
|
||||
pub get_IsExplicitLayout: *const c_void,
|
||||
pub get_IsClass: *const c_void,
|
||||
pub get_IsInterface: *const c_void,
|
||||
pub get_IsValueType: *const c_void,
|
||||
pub get_IsAbstract: *const c_void,
|
||||
pub get_IsSealed: *const c_void,
|
||||
pub get_IsEnum: *const c_void,
|
||||
pub get_IsSpecialName: *const c_void,
|
||||
pub get_IsImport: *const c_void,
|
||||
pub get_IsSerializable: *const c_void,
|
||||
pub get_IsAnsiClass: *const c_void,
|
||||
pub get_IsUnicodeClass: *const c_void,
|
||||
pub get_IsAutoClass: *const c_void,
|
||||
pub get_IsArray: *const c_void,
|
||||
pub get_IsByRef: *const c_void,
|
||||
pub get_IsPointer: *const c_void,
|
||||
pub get_IsPrimitive: *const c_void,
|
||||
pub get_IsCOMObject: *const c_void,
|
||||
pub get_HasElementType: *const c_void,
|
||||
pub get_IsContextful: *const c_void,
|
||||
pub get_IsMarshalByRef: *const c_void,
|
||||
pub Equals_2: *const c_void,
|
||||
}
|
||||
|
||||
impl _Type {
|
||||
pub fn to_string(&self) -> Result<String, String> {
|
||||
let mut buffer = BSTR::new();
|
||||
|
||||
let hr = unsafe { (*self).ToString(&mut buffer as *mut _ as *mut *mut u16) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Failed while running `ToString`: {:?}", hr));
|
||||
}
|
||||
|
||||
Ok(buffer.to_string())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetTypeInfoCount(&self, pctinfo: *mut u32) -> HRESULT {
|
||||
((*self.vtable).GetTypeInfoCount)(self as *const _ as *mut _, pctinfo)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn ToString(&self, pRetVal: *mut *mut u16) -> HRESULT {
|
||||
((*self.vtable).ToString)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetHashCode(&self, pRetVal: *mut c_long) -> HRESULT {
|
||||
((*self.vtable).GetHashCode)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetType(&self, pRetVal: *mut *mut _Type) -> HRESULT {
|
||||
((*self.vtable).GetType)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_Name(&self, pRetVal: *mut *mut u16) -> HRESULT {
|
||||
((*self.vtable).get_Name)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_DeclaringType(&self, pRetVal: *mut *mut _Type) -> HRESULT {
|
||||
((*self.vtable).get_DeclaringType)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_ReflectedType(&self, pRetVal: *mut *mut _Type) -> HRESULT {
|
||||
((*self.vtable).get_ReflectedType)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_Guid(&self, pRetVal: *mut *mut GUID) -> HRESULT {
|
||||
((*self.vtable).get_Guid)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_Assembly(&self, pRetVal: *mut *mut _Assembly) -> HRESULT {
|
||||
((*self.vtable).get_Assembly)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_FullName(&self, pRetVal: *mut *mut u16) -> HRESULT {
|
||||
((*self.vtable).get_FullName)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_Namespace(&self, pRetVal: *mut *mut u16) -> HRESULT {
|
||||
((*self.vtable).get_Namespace)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_AssemblyQualifiedName(&self, pRetVal: *mut *mut u16) -> HRESULT {
|
||||
((*self.vtable).get_AssemblyQualifiedName)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn get_BaseType(&self, pRetVal: *mut *mut _Type) -> HRESULT {
|
||||
((*self.vtable).get_BaseType)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetMethod_2(
|
||||
&self,
|
||||
name: *mut u16,
|
||||
bindingAttr: BindingFlags,
|
||||
pRetVal: *mut *mut _MethodInfo,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).GetMethod_2)(self as *const _ as *mut _, name, bindingAttr, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetMethods(
|
||||
&self,
|
||||
bindingAttr: BindingFlags,
|
||||
pRetVal: *mut *mut SAFEARRAY,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).GetMethods)(self as *const _ as *mut _, bindingAttr, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetMethod_4(
|
||||
&self,
|
||||
name: *mut u16,
|
||||
types: *mut SAFEARRAY,
|
||||
modifiers: *mut SAFEARRAY,
|
||||
pRetVal: *mut *mut _MethodInfo,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).GetMethod_4)(self as *const _ as *mut _, name, types, modifiers, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetMethod_5(
|
||||
&self,
|
||||
name: *mut u16,
|
||||
types: *mut SAFEARRAY,
|
||||
pRetVal: *mut *mut _MethodInfo,
|
||||
) -> HRESULT {
|
||||
((*self.vtable).GetMethod_5)(self as *const _ as *mut _, name, types, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetMethod_6(&self, name: *mut u16, pRetVal: *mut *mut _MethodInfo) -> HRESULT {
|
||||
((*self.vtable).GetMethod_6)(self as *const _ as *mut _, name, pRetVal)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn GetMethods_2(&self, pRetVal: *mut *mut SAFEARRAY) -> HRESULT {
|
||||
((*self.vtable).GetMethods_2)(self as *const _ as *mut _, pRetVal)
|
||||
}
|
||||
|
||||
pub fn get_method(&self, name: &str) -> Result<*mut _MethodInfo, String> {
|
||||
let mut dw = BSTR::from(name);
|
||||
|
||||
let mut method_ptr: *mut _MethodInfo = ptr::null_mut();
|
||||
let hr = unsafe { (*self).GetMethod_6(dw.into_raw() as *mut _, &mut method_ptr) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!(
|
||||
"Error while retrieving method `{}`: 0x{:x}",
|
||||
name, hr.0
|
||||
));
|
||||
}
|
||||
|
||||
if method_ptr.is_null() {
|
||||
return Err(format!("Could not retrieve method `{}`", name));
|
||||
}
|
||||
|
||||
Ok(method_ptr)
|
||||
}
|
||||
|
||||
pub fn get_methods(&self) -> Result<Vec<*mut _MethodInfo>, String> {
|
||||
let mut results: Vec<*mut _MethodInfo> = vec![];
|
||||
|
||||
let mut safe_array_ptr: *mut SAFEARRAY =
|
||||
unsafe { SafeArrayCreateVector(VT_UNKNOWN, 0, 255) };
|
||||
|
||||
let hr = unsafe { (*self).GetMethods_2(&mut safe_array_ptr) };
|
||||
|
||||
if hr.is_err() {
|
||||
return Err(format!("Error while retrieving methods: 0x{:x}", hr.0));
|
||||
}
|
||||
|
||||
let ubound = unsafe { SafeArrayGetUBound(safe_array_ptr, 1) }.unwrap_or(0);
|
||||
|
||||
for i in 0..ubound {
|
||||
let indices: [i32; 1] = [i as _];
|
||||
let mut variant: *mut _MethodInfo = ptr::null_mut();
|
||||
let pv = &mut variant as *mut _ as *mut c_void;
|
||||
|
||||
match unsafe { SafeArrayGetElement(safe_array_ptr, indices.as_ptr(), pv) } {
|
||||
Ok(_) => {},
|
||||
Err(e) => return Err(format!("Could not access safe array: {:?}", e.code())),
|
||||
}
|
||||
|
||||
if !pv.is_null() {
|
||||
results.push(variant)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(results)
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for _Type {
|
||||
type Target = IUnknown;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &IUnknown {
|
||||
unsafe { &*(self as *const _Type as *const IUnknown) }
|
||||
}
|
||||
}
|
||||
impl Interface for _Type {
|
||||
const IID: GUID = GUID::from_values(
|
||||
0xbca8b44d,
|
||||
0xaad6,
|
||||
0x3a86,
|
||||
[0x8a, 0xb7, 0x03, 0x34, 0x9f, 0x4f, 0x2d, 0xa2],
|
||||
);
|
||||
|
||||
fn vtable(&self) -> *const c_void {
|
||||
self.vtable as *const _ as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
pub type BindingFlags = u32;
|
||||
pub const BindingFlags_Default: BindingFlags = 0;
|
||||
pub const BindingFlags_IgnoreCase: BindingFlags = 1;
|
||||
pub const BindingFlags_DeclaredOnly: BindingFlags = 2;
|
||||
pub const BindingFlags_Instance: BindingFlags = 4;
|
||||
pub const BindingFlags_Static: BindingFlags = 8;
|
||||
pub const BindingFlags_Public: BindingFlags = 16;
|
||||
pub const BindingFlags_NonPublic: BindingFlags = 32;
|
||||
pub const BindingFlags_FlattenHierarchy: BindingFlags = 64;
|
||||
pub const BindingFlags_InvokeMethod: BindingFlags = 256;
|
||||
pub const BindingFlags_CreateInstance: BindingFlags = 512;
|
||||
pub const BindingFlags_GetField: BindingFlags = 1024;
|
||||
pub const BindingFlags_SetField: BindingFlags = 2048;
|
||||
pub const BindingFlags_GetProperty: BindingFlags = 4096;
|
||||
pub const BindingFlags_SetProperty: BindingFlags = 8192;
|
||||
pub const BindingFlags_PutDispProperty: BindingFlags = 16384;
|
||||
pub const BindingFlags_PutRefDispProperty: BindingFlags = 32768;
|
||||
pub const BindingFlags_ExactBinding: BindingFlags = 65536;
|
||||
pub const BindingFlags_SuppressChangeType: BindingFlags = 131072;
|
||||
pub const BindingFlags_OptionalParamBinding: BindingFlags = 262144;
|
||||
pub const BindingFlags_IgnoreReturn: BindingFlags = 16777216;
|
||||
@@ -0,0 +1,67 @@
|
||||
use crate::primitives::{Interface, GUID, HRESULT};
|
||||
use std::{ffi::c_void, mem::transmute_copy};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct IUnknown {
|
||||
pub vtable: *const IUnknownVtbl,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct IUnknownVtbl {
|
||||
pub QueryInterface: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
iid: *const GUID,
|
||||
interface: *mut *mut c_void,
|
||||
) -> HRESULT,
|
||||
pub AddRef: unsafe extern "system" fn(this: *mut c_void) -> u32,
|
||||
pub Release: unsafe extern "system" fn(this: *mut c_void) -> u32,
|
||||
}
|
||||
|
||||
impl IUnknown {
|
||||
#[inline]
|
||||
pub unsafe fn QueryInterface(&self, riid: *const GUID, ppvObject: *mut *mut c_void) -> HRESULT {
|
||||
((*self.vtable).QueryInterface)(self as *const _ as *mut _, riid, ppvObject)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn AddRef(&self) -> u32 {
|
||||
((*self.vtable).AddRef)(self as *const _ as *mut _)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn Release(&self) -> u32 {
|
||||
((*self.vtable).Release)(self as *const _ as *mut _)
|
||||
}
|
||||
}
|
||||
|
||||
impl Interface for IUnknown {
|
||||
const IID: GUID = GUID::from_u128(0x00000000_0000_0000_c000_000000000046);
|
||||
|
||||
fn vtable(&self) -> *const c_void {
|
||||
self.vtable as *const _ as *const c_void
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for IUnknown {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe {
|
||||
self.AddRef();
|
||||
}
|
||||
|
||||
unsafe { transmute_copy(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for IUnknown {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for IUnknown {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("IUnknown").field(&self).finish()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
mod helpers;
|
||||
mod iappdomain;
|
||||
mod iassembly;
|
||||
mod iclrmetahost;
|
||||
mod iclrruntimeinfo;
|
||||
mod icorruntimehost;
|
||||
mod ienumunknown;
|
||||
mod imethodinfo;
|
||||
mod istringwriter;
|
||||
mod itype;
|
||||
mod iunknown;
|
||||
mod types;
|
||||
|
||||
pub use helpers::*;
|
||||
pub use iappdomain::*;
|
||||
pub use iassembly::*;
|
||||
pub use iclrmetahost::*;
|
||||
pub use iclrruntimeinfo::*;
|
||||
pub use icorruntimehost::*;
|
||||
pub use ienumunknown::*;
|
||||
pub use imethodinfo::*;
|
||||
pub use istringwriter::*;
|
||||
pub use itype::*;
|
||||
pub use iunknown::*;
|
||||
pub use types::*;
|
||||
|
||||
pub trait Interface: Sized {
|
||||
const IID: GUID;
|
||||
|
||||
fn vtable(&self) -> *const std::ffi::c_void;
|
||||
}
|
||||
|
||||
pub trait Class: Sized {
|
||||
const CLSID: GUID;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
pub use windows::{
|
||||
core::{GUID, HRESULT},
|
||||
Win32::Foundation::{BOOL, HANDLE, HINSTANCE},
|
||||
};
|
||||
Reference in New Issue
Block a user