Move everything to its own repo

This commit is contained in:
Kadir Yamamoto
2023-03-16 19:25:33 +09:00
commit 0b12d397ff
20 changed files with 2439 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
/target
/Cargo.lock
+25
View File
@@ -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"]
+67
View File
@@ -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);
}
```
+37
View File
@@ -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);
}
+6
View File
@@ -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
View File
@@ -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),
};
}
+2
View File
@@ -0,0 +1,2 @@
pub mod clr;
pub mod primitives;
+116
View File
@@ -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)
}
+193
View File
@@ -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) }
}
}
+288
View File
@@ -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) }
}
}
+177
View File
@@ -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) }
}
}
+220
View File
@@ -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) }
}
}
+266
View File
@@ -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) }
}
}
+71
View File
@@ -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) }
}
}
+187
View File
@@ -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) }
}
}
+59
View File
@@ -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) }
}
}
+392
View File
@@ -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;
+67
View File
@@ -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()
}
}
+35
View File
@@ -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;
}
+4
View File
@@ -0,0 +1,4 @@
pub use windows::{
core::{GUID, HRESULT},
Win32::Foundation::{BOOL, HANDLE, HINSTANCE},
};