/
com.rs
157 lines (139 loc) · 5.57 KB
/
com.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#![allow(non_snake_case)]
use windows::{core::*, Win32::Foundation::*, Win32::System::Com::*};
/// A custom declaration of implementation of `IUri`
#[interface("a39ee748-6a27-4817-a6f2-13914bef5890")]
unsafe trait ICustomUri: IUnknown {
unsafe fn GetPropertyBSTR(&self, property: Uri_PROPERTY, value: *mut BSTR, flags: u32) -> HRESULT;
unsafe fn GetPropertyLength(&self) -> HRESULT;
unsafe fn GetPropertyDWORD(&self, property: Uri_PROPERTY, value: *mut u32, flags: u32) -> HRESULT;
unsafe fn HasProperty(&self); // Note: this definition is missing its return value
unsafe fn GetAbsoluteUri(&self) -> HRESULT;
unsafe fn GetAuthority(&self) -> HRESULT;
unsafe fn GetDisplayUri(&self) -> i32;
unsafe fn GetDomain(&self, value: *mut BSTR) -> HRESULT;
// etc
}
/// A custom declaration of implementation of `IPersist`
#[interface("0000010c-0000-0000-C000-000000000046")]
unsafe trait ICustomPersist: windows::core::IUnknown {
unsafe fn GetClassID(&self, clsid: *mut GUID) -> HRESULT;
}
/// A custom declaration of implementation of `IPersistMemory`
#[interface("BD1AE5E0-A6AE-11CE-BD37-504200C10000")]
unsafe trait ICustomPersistMemory: ICustomPersist {
unsafe fn IsDirty(&self) -> HRESULT;
unsafe fn Load(&self, input: *const core::ffi::c_void, size: u32) -> HRESULT;
unsafe fn Save(&self, output: *mut core::ffi::c_void, clear_dirty: BOOL, size: u32) -> HRESULT;
unsafe fn GetSizeMax(&self, len: *mut u32) -> HRESULT;
unsafe fn InitNew(&self) -> HRESULT;
}
/// A custom in-memory store
#[implement(ICustomPersistMemory, ICustomPersist)]
#[derive(Default)]
struct Persist(std::sync::RwLock<PersistState>);
impl Persist {
fn new() -> Self {
Self(std::sync::RwLock::new(PersistState::default()))
}
}
#[derive(Default)]
struct PersistState {
memory: [u8; 10],
dirty: bool,
}
impl ICustomPersist_Impl for Persist {
unsafe fn GetClassID(&self, clsid: *mut GUID) -> HRESULT {
*clsid = "117fb826-2155-483a-b50d-bc99a2c7cca3".into();
S_OK
}
}
impl ICustomPersistMemory_Impl for Persist {
unsafe fn IsDirty(&self) -> HRESULT {
let reader = self.0.read().unwrap();
if reader.dirty {
S_OK
} else {
S_FALSE
}
}
unsafe fn Load(&self, input: *const core::ffi::c_void, size: u32) -> HRESULT {
let mut writer = self.0.write().unwrap();
if size <= writer.memory.len() as _ {
std::ptr::copy(input, writer.memory.as_mut_ptr() as _, size as _);
writer.dirty = true;
S_OK
} else {
E_OUTOFMEMORY
}
}
unsafe fn Save(&self, output: *mut core::ffi::c_void, clear_dirty: BOOL, size: u32) -> HRESULT {
let mut writer = self.0.write().unwrap();
if size <= writer.memory.len() as _ {
std::ptr::copy(writer.memory.as_mut_ptr() as _, output, size as _);
if clear_dirty.as_bool() {
writer.dirty = false;
}
S_OK
} else {
E_OUTOFMEMORY
}
}
unsafe fn GetSizeMax(&self, len: *mut u32) -> HRESULT {
let reader = self.0.read().unwrap();
*len = reader.memory.len() as _;
S_OK
}
unsafe fn InitNew(&self) -> HRESULT {
let mut writer = self.0.write().unwrap();
writer.memory = Default::default();
writer.dirty = false;
S_OK
}
}
#[test]
fn test_custom_interface() -> windows::core::Result<()> {
unsafe {
// Use the OS implementation of Uri through the custom `ICustomUri` interface
let a: IUri = CreateUri(w!("http://kennykerr.ca"), URI_CREATE_FLAGS::default(), 0)?;
let b: ICustomUri = a.cast()?;
let mut domain = BSTR::new();
b.GetDomain(&mut domain).ok()?;
assert_eq!(domain, "kennykerr.ca");
let mut property = BSTR::new();
a.GetPropertyBSTR(Uri_PROPERTY_DOMAIN, &mut property, 0)?;
assert_eq!(property, "kennykerr.ca");
let mut property = 0;
a.GetPropertyDWORD(Uri_PROPERTY_PORT, &mut property, 0)?;
assert_eq!(property, 80);
// Use the custom implementation of `Persist` through the OS `IPersistMemory` interface
let p: ICustomPersistMemory = Persist::new().into();
// This works because `ICustomPersistMemory` and `IPersistMemory` share the same guid
let p: IPersistMemory = p.cast()?;
assert_eq!(p.GetClassID()?, "117fb826-2155-483a-b50d-bc99a2c7cca3".into());
assert_eq!(p.GetSizeMax()?, 10);
assert_eq!(p.IsDirty(), S_FALSE);
p.Load(&[0xAAu8, 0xBB, 0xCC])?;
assert_eq!(p.IsDirty(), S_OK);
let mut memory = [0x00u8, 0x00, 0x00, 0x00];
p.Save(&mut memory, true)?;
assert_eq!(memory, [0xAAu8, 0xBB, 0xCC, 0x00]);
assert_eq!(p.IsDirty(), S_FALSE);
// Use the custom implementation of `Persist` through the custom interface of `ICustomPersist`
let p: ICustomPersistMemory = p.cast()?;
let mut size = 0;
p.GetSizeMax(&mut size).ok()?;
assert_eq!(size, 10);
assert_eq!(p.IsDirty(), S_FALSE);
p.Load(&[0xAAu8, 0xBB, 0xCC] as *const _ as *const _, 3).ok()?;
assert_eq!(p.IsDirty(), S_OK);
let mut memory = [0x00u8, 0x00, 0x00, 0x00];
p.Save(&mut memory as *mut _ as *mut _, true.into(), 4).ok()?;
assert_eq!(p.IsDirty(), S_FALSE);
assert_eq!(memory, [0xAAu8, 0xBB, 0xCC, 0x00]);
let p: ICustomPersist = p.cast()?;
let mut b = GUID::default();
p.GetClassID(&mut b).ok()?;
assert_eq!(b, "117fb826-2155-483a-b50d-bc99a2c7cca3".into());
Ok(())
}
}