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
//! Convenient extension registry for Command Palette extensions.
use crate::ext::Extension;
use crate::ext_factory::ExtensionClassFactory;
use windows::Win32::System::Com::{
CLSCTX_INPROC_SERVER, CLSCTX_LOCAL_SERVER, CLSID_GlobalOptions, COINIT_MULTITHREADED,
COMGLB_FAST_RUNDOWN, COMGLB_RO_SETTINGS, CoCreateInstance, CoInitializeEx,
CoRegisterClassObject, CoResumeClassObjects, IClassFactory, IGlobalOptions, REGCLS_MULTIPLEUSE,
REGCLS_SUSPENDED,
};
use windows::Win32::UI::WindowsAndMessaging::{
DispatchMessageW, GetMessageW, MSG, TranslateMessage,
};
use windows_core::{ComObject, GUID, Result};
/// A registry for extensions that can be registered and served.
/// Convenient for building a extension executable that can host multiple extensions.
///
pub struct ExtRegistry {
pub(crate) factories: Vec<(GUID, ComObject<ExtensionClassFactory>)>,
}
impl ExtRegistry {
/// Create a new extension registry.
pub fn new() -> Self {
ExtRegistry {
factories: Vec::new(),
}
}
/// Register an extension with the given GUID.
///
/// The GUID should match GUID specified in `AppxManifest.xml` file
pub fn register(mut self, guid: GUID, extension: impl Into<ComObject<Extension>>) -> Self {
self.factories
.push((guid, ExtensionClassFactory(extension.into()).into()));
self
}
/// Register an extension factory with the given GUID.
///
/// The GUID should match GUID specified in `AppxManifest.xml` file.
///
/// Useful when you want to register a custom factory directly.
pub fn register_factory(
mut self,
guid: GUID,
factory: impl Into<ComObject<ExtensionClassFactory>>,
) -> Self {
self.factories.push((guid, factory.into()));
self
}
/// Start serving the registered extensions.
///
/// This will initialize COM, register the class objects,
/// and start a message loop to process messages.
/// This method will run indefinitely until the message loop is exited.
///
pub fn serve(self) -> Result<()> {
// SAFETY: Following code are safe to run on a properly initialized Windows environment
unsafe {
CoInitializeEx(None, COINIT_MULTITHREADED).ok()?;
let global_options: IGlobalOptions =
CoCreateInstance(&CLSID_GlobalOptions, None, CLSCTX_INPROC_SERVER)?;
global_options.Set(COMGLB_RO_SETTINGS, COMGLB_FAST_RUNDOWN.0 as usize)?;
for (guid, factory) in self.factories.into_iter() {
let ifactory: IClassFactory = factory.to_interface();
CoRegisterClassObject(
&guid,
&ifactory,
CLSCTX_LOCAL_SERVER,
REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED,
)?;
}
CoResumeClassObjects()?;
let mut msg: MSG = MSG::default();
while GetMessageW(&mut msg, None, 0, 0).as_bool() {
if TranslateMessage(&msg).as_bool() {
DispatchMessageW(&msg);
}
}
}
Ok(())
}
}