Skip to content

Instantly share code, notes, and snippets.

@SteelCrow

SteelCrow/example.rs

Last active Mar 18, 2019
Embed
What would you like to do?
#![feature(raw)]
use blackmagic::*;
use std::ffi::*;
use std::os::raw::c_uint;
use std::os::raw::c_ulong;
use std::ptr::*;
use std::raw::TraitObject;
use types::*;
// DispServerLocator {3DCF3051-4EA4-40FE-A39B-DC2014E0904B}
DEFINE_GUID!(
CLSID_DispServerLocator,
0x3DCF3051,
0x4EA4,
0x40FE,
0xA3,
0x9B,
0xDC,
0x20,
0x14,
0xE0,
0x90,
0x4B
);
fn main() {
match unsafe { CoInitializeEx(null_mut(), COINIT_APARTMENTTHREADED) } {
S_OK => println!("The COM library was initialized successfully on this thread."),
S_FALSE => println!("The COM library is already initialized on this thread."),
RPC_E_CHANGED_MODE => println!("A previous call to CoInitializeEx specified the concurrency model for this thread as multithread apartment (MTA). This could also indicate that a change from neutral-threaded apartment to single-threaded apartment has occurred."),
result => panic!("call to CoInitializeEx failed: {}", result),
}
// let mut obj: *mut c_void = null_mut();
let mut obj: *mut VtableC<IDispatch_vtable> = null_mut();
match unsafe {
CoCreateInstance(
&CLSID_DispServerLocator,
null_mut(),
CLSCTX_LOCAL_SERVER,
&IID_IDispatch,
std::mem::transmute(&mut obj),
)
} {
S_OK => println!("An instance of the specified object class was successfully created."),
REGDB_E_CLASSNOTREG => println!("A specified class is not registered in the registration database. Also can indicate that the type of server you requested in the CLSCTX enumeration is not registered or the values for the server types in the registry are corrupt."),
CLASS_E_NOAGGREGATION => println!("This class cannot be created as part of an aggregate."),
E_NOINTERFACE => println!("The specified class does not implement the requested interface, or the controlling IUnknown does not expose the requested interface."),
E_POINTER => println!(" The ppv parameter is NULL."),
result => panic!("CoCreateInstance failed: error {:#08x}", result),
}
assert!(obj != null_mut());
let com_ptr = unsafe { transmute::<IDispatch, IDispatch_vtable>(obj as *mut c_void) };
assert_eq!(com_ptr.add_ref(), 2);
assert_eq!(com_ptr.add_ref(), 3);
assert_eq!(com_ptr.release(), 2);
assert_eq!(com_ptr.release(), 1);
let count = Box::into_raw(Box::new(0u32));
println!("{:?}", com_ptr.get_type_info_count(count));
unsafe {
CoUninitialize();
}
}
#[allow(dead_code)]
#[link(name = "ole32")]
extern "stdcall" {
fn CoCreateInstance(
rclsid: REFCLSID,
pUnkOuter: *mut c_void,
dwClsContext: DWORD,
riid: REFIID,
ppv: *mut *mut c_void,
) -> HRESULT;
fn CoInitializeEx(pvReserved: *mut c_void, dwCoInit: DWORD) -> HRESULT;
fn CoUninitialize();
}
#[allow(dead_code)]
mod types {
use std::ffi::c_void;
use std::os::raw::*;
pub const CLSCTX_INPROC_SERVER: DWORD = 0x1;
pub const CLSCTX_INPROC_HANDLER: DWORD = 0x2;
pub const CLSCTX_LOCAL_SERVER: DWORD = 0x4;
pub const CLSCTX_INPROC_SERVER16: DWORD = 0x8;
pub const CLSCTX_REMOTE_SERVER: DWORD = 0x10;
pub const CLSCTX_INPROC_HANDLER16: DWORD = 0x20;
pub const CLSCTX_RESERVED1: DWORD = 0x40;
pub const CLSCTX_RESERVED2: DWORD = 0x80;
pub const CLSCTX_RESERVED3: DWORD = 0x100;
pub const CLSCTX_RESERVED4: DWORD = 0x200;
pub const CLSCTX_NO_CODE_DOWNLOAD: DWORD = 0x400;
pub const CLSCTX_RESERVED5: DWORD = 0x800;
pub const CLSCTX_NO_CUSTOM_MARSHAL: DWORD = 0x1000;
pub const CLSCTX_ENABLE_CODE_DOWNLOAD: DWORD = 0x2000;
pub const CLSCTX_NO_FAILURE_LOG: DWORD = 0x4000;
pub const CLSCTX_DISABLE_AAA: DWORD = 0x8000;
pub const CLSCTX_ENABLE_AAA: DWORD = 0x10000;
pub const CLSCTX_FROM_DEFAULT_CONTEXT: DWORD = 0x20000;
pub const CLSCTX_ACTIVATE_32_BIT_SERVER: DWORD = 0x40000;
pub const CLSCTX_ACTIVATE_64_BIT_SERVER: DWORD = 0x80000;
pub const CLSCTX_ENABLE_CLOAKING: DWORD = 0x100000;
pub const CLSCTX_APPCONTAINER: DWORD = 0x400000;
pub const CLSCTX_ACTIVATE_AAA_AS_IU: DWORD = 0x800000;
pub const CLSCTX_PS_DLL: DWORD = 0x80000000;
pub const COINIT_APARTMENTTHREADED: DWORD = 0x2;
pub const S_OK: HRESULT = 0x00000000;
pub const S_FALSE: HRESULT = 0x00000001;
pub const RPC_E_CHANGED_MODE: HRESULT = 0x80010106;
pub const REGDB_E_CLASSNOTREG: HRESULT = 0x80040154;
pub const CLASS_E_NOAGGREGATION: HRESULT = 0x80040110;
pub const E_NOINTERFACE: HRESULT = 0x80004002;
pub const E_POINTER: HRESULT = 0x80004003;
#[macro_export]
macro_rules! DEFINE_GUID(
($name:ident, $l:expr, $w1:expr, $w2:expr, $($bs:expr),+) => {
#[allow(non_upper_case_globals)]
pub const $name: GUID = GUID {
data1: $l,
data2: $w1,
data3: $w2,
data4: [$($bs),+]
};
};
);
#[repr(C)]
pub struct GUID {
pub data1: c_uint,
pub data2: c_ushort,
pub data3: c_ushort,
pub data4: [c_uchar; 8],
}
pub type LCID = DWORD;
pub type DISPID = c_long;
pub type CLSID = GUID;
pub type IID = GUID;
pub type REFGUID = *const GUID;
pub type REFCLSID = *const CLSID;
pub type REFIID = *const IID;
pub type LPOLESTR = *mut OLECHAR;
pub type OLECHAR = WCHAR;
pub type WCHAR = wchar_t;
pub type wchar_t = c_ushort;
pub type HRESULT = c_uint;
pub type WORD = c_ushort;
pub type DWORD = c_uint;
pub type ComPtr = *mut c_void;
#[repr(C)]
#[allow(non_snake_case)]
pub struct DISPPARAMS {
rgvarg: *mut VARIANTARG,
rgdispidNamedArgs: *mut DISPID,
cArgs: c_uint,
cNamedArgs: c_uint,
}
pub struct VARIANT;
type VARIANTARG = VARIANT;
pub struct EXCEPINFO;
DEFINE_GUID!(
IID_IUnknown,
0x00000000,
0x0000,
0x0000,
0xC0,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x46
);
DEFINE_GUID!(
IID_IDispatch,
0x00020400,
0x0000,
0x0000,
0xc0,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x46
);
}
mod blackmagic {
use crate::types::*;
use std::ffi::c_void;
use std::os::raw::*;
use std::raw::TraitObject;
trait Donor {}
impl<T> Donor for T {}
#[repr(C)]
#[derive(Clone, Copy)]
struct VtableHeader {
destructor: fn(*mut ()),
size: usize,
align: usize,
}
#[repr(C)]
pub struct VtableC<T> {
pub __vtable: *mut T,
}
#[repr(C)]
struct VtableRust<T> {
header: VtableHeader,
funcs: T,
}
#[repr(C)]
#[derive(Clone, Copy)]
#[allow(non_snake_case)]
pub struct IUnknown_vtable {
pub QueryInterface: extern "stdcall" fn(*mut c_void, REFIID, *mut *mut c_void) -> HRESULT,
pub AddRef: extern "stdcall" fn(*mut c_void) -> c_ulong,
pub Release: extern "stdcall" fn(*mut c_void) -> c_ulong,
}
pub trait IUnknown {
fn query_interface(&mut self, riid: REFIID, ppv: *mut ComPtr) -> u64;
fn add_ref(&mut self) -> u64;
fn release(&mut self) -> u64;
}
#[repr(C)]
#[derive(Clone, Copy)]
#[allow(non_snake_case)]
pub struct IDispatch_vtable {
pub __base: IUnknown_vtable,
pub GetTypeInfoCount: extern "stdcall" fn(*mut c_void, *mut c_uint) -> c_ulong,
// FIXME: last params ITypeInfo
pub GetTypeInfo:
extern "stdcall" fn(*mut c_void, c_uint, LCID, *mut *mut c_void) -> c_ulong,
pub GetIDsOfNames: extern "stdcall" fn(
*mut c_void,
REFIID,
*mut LPOLESTR,
c_uint,
LCID,
*mut DISPID,
) -> c_ulong,
pub Invoke: extern "stdcall" fn(
*mut c_void,
DISPID,
REFIID,
LCID,
WORD,
*mut DISPPARAMS,
*mut VARIANT,
*mut EXCEPINFO,
*mut c_uint,
) -> c_ulong,
}
pub trait IDispatch {
fn query_interface(&mut self, riid: REFIID, ppv: *mut ComPtr) -> u64;
fn add_ref(&mut self) -> u64;
fn release(&mut self) -> u64;
// FIXME: last params ITypeInfo
fn get_type_info_count(&mut self, pctinfo: *mut c_uint) -> c_ulong;
fn get_type_info(&mut self, itinfo: u32, lcid: LCID, pptinfo: *mut *mut c_void) -> u32;
fn get_ids_of_names(
&mut self,
riid: REFIID,
rgsz_names: *mut LPOLESTR,
c_names: u32,
lcid: LCID,
rgdispid: *mut DISPID,
) -> u32;
fn invoke(
&mut self,
dispid_member: DISPID,
riid: REFIID,
lcid: LCID,
w_flags: WORD,
pdispparams: *mut DISPPARAMS,
pvar_result: *mut VARIANT,
pexcepinfo: *mut EXCEPINFO,
pu_arg_err: *mut u32,
) -> u32;
}
pub unsafe fn transmute<'a, I: ?Sized, T: Copy>(obj: *mut c_void) -> Box<&'a mut I> {
let c_vtable = std::mem::transmute::<*mut c_void, *mut VtableC<T>>(obj);
let donor: &dyn Donor = &c_vtable;
let donor_obj = std::mem::transmute::<&dyn Donor, TraitObject>(donor);
let donor_vtable_header = donor_obj.vtable as *const VtableHeader;
let mut vtable: VtableRust<T> = VtableRust {
header: *donor_vtable_header,
funcs: *((*c_vtable).__vtable),
};
let object = TraitObject {
data: obj as *mut (),
vtable: &mut vtable as *mut VtableRust<T> as *mut (),
};
std::mem::transmute::<Box<TraitObject>, Box<&mut I>>(Box::new(object))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment