win_idispatch/
unknown.rs

1use log::trace;
2use std::ptr;
3use winapi::{
4    shared::{guiddef::GUID, minwindef::LPVOID, winerror::NOERROR, wtypesbase::CLSCTX},
5    um::{combaseapi::CoCreateInstance, oaidl::LPDISPATCH, unknwnbase::LPUNKNOWN},
6};
7
8use super::guids::{IID_IDISPATCH, IID_IUNKNOWN};
9use super::{dispatch::DispatchInterface, Error};
10
11/// UnknownInterface is a structure that maintains access to an IUnkonwn
12/// pointer. The pointer will be cleaned up correctly when the reference
13/// is dropped.
14pub struct UnknownInterface {
15    unknown: LPUNKNOWN,
16    released: bool,
17}
18
19impl UnknownInterface {
20    /// Create a new Unknown interface based on the provided class GUID and
21    /// the class context.
22    pub fn new(class_id: GUID, class_context: CLSCTX) -> Result<UnknownInterface, Error> {
23        let mut unknown: LPVOID = ptr::null_mut();
24        let result = unsafe {
25            CoCreateInstance(
26                &class_id,
27                ptr::null_mut(),
28                class_context,
29                &IID_IUNKNOWN,
30                &mut unknown,
31            )
32        };
33        if result != NOERROR {
34            Err(result.into())
35        } else {
36            Ok(UnknownInterface {
37                unknown: unknown as LPUNKNOWN,
38                released: false,
39            })
40        }
41    }
42    /// Gets a DisptachInterface to work with the COM server registered with
43    /// the class GUID provided to the unknown interface.
44    pub fn get_dispatch_interface(&self) -> Result<DispatchInterface, Error> {
45        let mut dispatch: LPVOID = ptr::null_mut();
46        let result = unsafe {
47            if let Some(r) = self.unknown.as_ref() {
48                r.QueryInterface(&IID_IDISPATCH, &mut dispatch)
49            } else {
50                return Err(Error::NullUnknownPointer);
51            }
52        };
53        if result != NOERROR {
54            Err(result.into())
55        } else {
56            Ok(DispatchInterface::new(dispatch as LPDISPATCH))
57        }
58    }
59
60    fn release(&mut self) {
61        if self.released {
62            return;
63        }
64        unsafe {
65            if let Some(r) = self.unknown.as_ref() {
66                r.Release();
67                self.released = true;
68                self.unknown = ptr::null_mut();
69            }
70        }
71    }
72}
73
74impl Drop for UnknownInterface {
75    fn drop(&mut self) {
76        trace!("dropping unknown interface");
77        self.release();
78    }
79}