Skip to content

Instantly share code, notes, and snippets.

@withkittens
Last active August 28, 2017 08:41
Show Gist options
  • Save withkittens/f1363cc25a807374c24d to your computer and use it in GitHub Desktop.
Save withkittens/f1363cc25a807374c24d to your computer and use it in GitHub Desktop.
ЧИСТЕНЬКАЯ реализация COM! азаза
#![allow(dead_code)]
#![allow(unused_imports)]
use std::mem::transmute;
use std::ops::Deref;
#[repr(C)]
struct Dummy {
pub vptr: *const ()
}
trait Vtable { type Vtable; }
trait HasVtable<T: Vtable> : Sized {
fn this(&self) -> &T { unsafe { transmute(self) } }
fn vtable(&self) -> &T::Vtable {
let d: &Dummy = unsafe { transmute(self) };
unsafe { transmute(d.vptr) }
}
}
// IUnknown
// ====================================================================
struct UnknownVtbl {
pub query_interface: usize,
pub add_ref: usize,
pub release: usize
} // <1> abi::vtable
struct Unknown { _vptr: *const UnknownVtbl } // <2> abi::object
trait IUnknown {
fn release(&self) -> usize;
} // <3> rust trait
impl<T: HasVtable<Unknown>> IUnknown for T {
fn release(&self) -> usize {
self.vtable().release
}
} // <4> rust trait impl
impl Vtable for Unknown { type Vtable = UnknownVtbl; } // <5> 'linker': object<->vtable
impl HasVtable<Unknown> for Unknown { } // <6> chain of inheritance
// IDispatch
// ====================================================================
struct DispatchVtbl {
pub base: UnknownVtbl,
pub type_info_count: usize,
pub get_type_info: usize,
pub ids_of_names: usize,
pub invoke: usize
} // <1> vtable
struct Dispatch { _vptr: *const DispatchVtbl } // <2> object
trait IDispatch {
fn invoke(&self) -> usize;
} // <3> rust trait
impl<T: HasVtable<Dispatch>> IDispatch for T {
fn invoke(&self) -> usize {
self.vtable().invoke
}
} // <4> rust trait impl
impl Vtable for Dispatch { type Vtable = DispatchVtbl; } // <5> 'linker'
// <6> chain of inheritance
impl HasVtable<Unknown> for Dispatch { } // IDispatch *is* IUnknown
impl HasVtable<Dispatch> for Dispatch { } // IDispatch *is* IDispatch
// IShellDispatch
// ====================================================================
struct ShellDispatchVtbl {
pub base: DispatchVtbl,
pub file_run: usize
}
struct ShellDispatch { _vptr: *const ShellDispatchVtbl }
trait IShellDispatch {
fn file_run(&self) -> usize;
}
impl<T: HasVtable<ShellDispatch>> IShellDispatch for T {
fn file_run(&self) -> usize {
self.vtable().file_run
}
}
impl Vtable for ShellDispatch { type Vtable = ShellDispatchVtbl; }
impl HasVtable<Unknown> for ShellDispatch { }
impl HasVtable<Dispatch> for ShellDispatch { }
impl HasVtable<ShellDispatch> for ShellDispatch { }
static FOO_VTBL: ShellDispatchVtbl = ShellDispatchVtbl {
base: DispatchVtbl {
base: UnknownVtbl {
query_interface: 42,
add_ref: 43,
release: 44
},
type_info_count: 45,
get_type_info: 46,
ids_of_names: 47,
invoke: 48
},
file_run: 49
};
struct ComRef<T> { ptr: *const T }
impl<T> ComRef<T> {
pub fn new(ptr: *const T) -> Self {
ComRef { ptr: ptr }
}
}
impl<T> Deref for ComRef<T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { transmute(self.ptr) }
}
}
fn main() {
let foo = ShellDispatch { _vptr: &FOO_VTBL };
//let ptr: *const ShellDispatch = &foo;
let obj = ComRef::new( &foo );
//let obj2: &ComRef<Unknown> = unsafe { transmute(&obj) };
//lorem( obj2 );
lorem( &obj );
ipsum( &obj );
assert_eq!(44, obj.release());
}
fn lorem<T: IDispatch>(x: &ComRef<T>) {
assert_eq!(48, x.invoke());
}
fn ipsum<T: IShellDispatch>(x: &ComRef<T>) {
assert_eq!(49, x.file_run());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment