intercom/
lib.rs

1//! Tools to define Rust components compatible with the COM protocol.
2//!
3//! Intercom provides attributes to automatically derive `extern` compatible
4//! functions for Rust methods. These functions are compatible with COM binary
5//! interface standard, which allows them to be used from any language that
6//! supports COM.
7//!
8//! # Examples
9//!
10//! A basic example of a calculator type exposed as a COM object.
11//!
12//! ```
13//! use intercom::{com_library, com_class, com_interface, ComResult};
14//!
15//! // Define COM classes to expose from this library.
16//! com_library!(class Calculator);
17//!
18//! // Define the COM class and the interfaces it implements.
19//! #[com_class(Self)]
20//! #[derive(Default)]
21//! struct Calculator;
22//!
23//! // Define the implementation for the class. The COM interface is defined
24//! // implicitly by the `impl`.
25//! #[com_interface]
26//! impl Calculator {
27//!     fn add(&self, a: i32, b: i32) -> ComResult<i32> { Ok(a + b) }
28//!     fn sub(&self, a: i32, b: i32) -> ComResult<i32> { Ok(a - b) }
29//! }
30//! # // Without 'main()' doctests wraps the whole thing into a function,
31//! # // which would end up expanding com_library!(..) into a statement.
32//! # // And proc macros into statements are not allowed.
33//! # //
34//! # // In addition to that, if we just have `fn main()` followed by open
35//! # // brace _anywhere_ in this doctest (yes, including these comments),
36//! # // clippy would discover that and yell at us for "needless doctest main".
37//! # // Allowing that with a specific #[allow(..)] attribute is impossible
38//! # // since this is crate-level documentation.
39//! # //
40//! # // Fortunately we can hide this from clippy by specifying the (empty)
41//! # // return type.
42//! # fn main() -> () { }
43//! ```
44//!
45//! The above library can be used for example from C# in the following manner.
46//!
47//! ```csharp
48//! void Main()
49//! {
50//!     var calculator = new CalculatorLib.Calculator();
51//!     Console.WriteLine( calculator.Add( 1, 2 ) );
52//! }
53//! ```
54
55#![crate_type = "dylib"]
56#![allow(clippy::match_bool)]
57
58extern crate self as intercom;
59
60#[cfg(not(windows))]
61extern crate libc;
62
63extern crate intercom_attributes;
64pub use intercom_attributes::*;
65
66#[allow(clippy::useless_attribute)]
67#[allow(unused_imports)]
68#[macro_use]
69extern crate failure;
70
71#[cfg(feature = "log")]
72extern crate log;
73
74pub mod prelude;
75
76mod classfactory;
77pub use crate::classfactory::*;
78mod combox;
79pub use crate::combox::*;
80mod comrc;
81pub use crate::comrc::*;
82mod comitf;
83pub use crate::comitf::*;
84mod strings;
85pub use crate::strings::*;
86mod guid;
87pub use crate::guid::GUID;
88pub mod error;
89pub use crate::error::{load_error, store_error, ComError, ErrorValue};
90pub mod alloc;
91pub mod interfaces;
92pub mod runtime;
93mod variant;
94pub use crate::variant::{Variant, VariantError};
95pub mod type_system;
96pub mod typelib;
97pub use type_system::ForeignType;
98pub mod attributes;
99pub mod logging;
100
101#[cfg(windows)]
102pub mod registry;
103
104// No-ops on non-windows platforms.
105#[cfg(not(windows))]
106pub mod registry
107{
108    use crate::raw::HRESULT;
109    use crate::typelib::TypeLib;
110
111    #[allow(clippy::upper_case_acronyms)]
112    type HANDLE = *mut std::os::raw::c_void;
113
114    /// Registers a type library.
115    pub fn register(_dll: HANDLE, _lib: TypeLib) -> Result<(), HRESULT>
116    {
117        Ok(())
118    }
119
120    /// Unregisters a type library.
121    pub fn unregister(_dll: HANDLE, _lib: TypeLib) -> Result<(), HRESULT>
122    {
123        Ok(())
124    }
125}
126
127com_module!(
128    class intercom::alloc::Allocator,
129    class intercom::error::ErrorStore,
130);
131
132/// Raw COM pointer type.
133/// Interface ID GUID.
134pub type IID = GUID;
135
136/// A reference to an interface ID.
137pub type REFIID = *const IID;
138
139/// Class ID GUID.
140pub type CLSID = GUID;
141
142/// A reference to a class ID.
143pub type REFCLSID = *const IID;
144
145pub mod raw
146{
147    use std::marker::PhantomData;
148    use std::os::raw::c_void;
149    use std::ptr::NonNull;
150
151    pub use crate::error::raw::*;
152    pub use crate::type_system::{ForeignType, TypeSystem};
153    pub use crate::variant::raw::*;
154
155    pub type RawComPtr = *mut c_void;
156
157    #[derive(
158        Clone,
159        Copy,
160        intercom_attributes::ExternType,
161        intercom_attributes::ExternInput,
162        intercom_attributes::ExternOutput,
163        intercom_attributes::ForeignType,
164    )]
165    #[repr(transparent)]
166    pub struct BSTR(pub *mut u16);
167
168    #[repr(transparent)]
169    #[derive(PartialEq, Eq)]
170    pub struct InterfacePtr<TS: TypeSystem, I: ?Sized>
171    {
172        pub ptr: NonNull<c_void>,
173        phantom_itf: PhantomData<I>,
174        phantom_ts: PhantomData<TS>,
175    }
176
177    impl<TS: TypeSystem, I: ?Sized> Clone for InterfacePtr<TS, I>
178    {
179        fn clone(&self) -> Self
180        {
181            InterfacePtr {
182                ptr: self.ptr,
183                phantom_itf: PhantomData,
184                phantom_ts: PhantomData,
185            }
186        }
187    }
188
189    impl<TS: TypeSystem, I: ?Sized> Copy for InterfacePtr<TS, I> {}
190
191    impl<TS: TypeSystem, I: ?Sized> std::fmt::Debug for InterfacePtr<TS, I>
192    {
193        fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result
194        {
195            write!(f, "InterfacePtr({:?})", self.ptr)
196        }
197    }
198
199    impl<TS: TypeSystem, I: ?Sized> InterfacePtr<TS, I>
200    {
201        /// # Safety
202        ///
203        /// The raw `ptr` must represent the correct type system and interface.
204        pub unsafe fn new(ptr: RawComPtr) -> Option<InterfacePtr<TS, I>>
205        {
206            let ptr = NonNull::new(ptr);
207            ptr.map(|ptr| InterfacePtr {
208                ptr,
209                phantom_itf: PhantomData,
210                phantom_ts: PhantomData,
211            })
212        }
213    }
214
215    impl<TS: TypeSystem, I: crate::attributes::ComInterface + ?Sized> InterfacePtr<TS, I>
216    {
217        pub fn as_unknown(self) -> InterfacePtr<TS, dyn crate::IUnknown>
218        {
219            InterfacePtr {
220                ptr: self.ptr,
221                phantom_itf: PhantomData,
222                phantom_ts: PhantomData,
223            }
224        }
225    }
226
227    impl<TS: TypeSystem, I: crate::attributes::ComInterface + ?Sized> ForeignType
228        for Option<InterfacePtr<TS, I>>
229    where
230        I: ForeignType,
231    {
232        /// The name of the type.
233        fn type_name() -> &'static str
234        {
235            <I as ForeignType>::type_name()
236        }
237        fn indirection_level() -> u32
238        {
239            <I as ForeignType>::indirection_level() + 1
240        }
241    }
242}
243
244/// `IClassFactory` interface ID.
245#[allow(non_upper_case_globals)]
246pub const IID_IClassFactory: GUID = GUID {
247    data1: 0x0000_0001,
248    data2: 0x0000,
249    data3: 0x0000,
250    data4: [0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46],
251};
252
253/// `IErrorInfo` interface ID.
254#[allow(non_upper_case_globals)]
255pub const IID_IErrorInfo: GUID = GUID {
256    data1: 0x1CF2_B120,
257    data2: 0x547D,
258    data3: 0x101B,
259    data4: [0x8E, 0x65, 0x08, 0x00, 0x2B, 0x2B, 0xD1, 0x19],
260};
261
262pub use crate::interfaces::IUnknown;
263// pub use crate::interfaces::__IUnknown_AutomationVtbl as IUnknownVtbl;
264
265pub use crate::interfaces::ISupportErrorInfo;
266// pub use crate::interfaces::__ISupportErrorInfo_AutomationVtbl as ISupportErrorInfoVtbl;
267
268/// Basic COM result type.
269///
270/// The `ComResult` maps the Rust concept of `Ok` and `Err` values to COM
271/// `[out, retval]` parameter and `HRESULT` return value.
272pub type ComResult<A> = Result<A, ComError>;
273
274/// Basic COM result type.
275///
276/// The `ComResult` maps the Rust concept of `Ok` and `Err` values to COM
277/// `[out, retval]` parameter and `HRESULT` return value.
278pub type RawComResult<A> = Result<A, raw::HRESULT>;