winsafe/ole/
structs.rs

1#![allow(non_camel_case_types, non_snake_case)]
2
3use std::marker::PhantomData;
4
5use crate::co;
6use crate::decl::*;
7use crate::guard::*;
8use crate::kernel::ffi_types::*;
9
10/// [`BIND_OPTS3`](https://learn.microsoft.com/en-us/windows/win32/api/objidl/ns-objidl-bind_opts3-r1)
11/// struct.
12#[repr(C)]
13pub struct BIND_OPTS3<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'i> {
14	cbStruct: u32,
15	pub grfFlags: co::BIND,
16	pub grfMode: co::STGM,
17	pub dwTickCountDeadline: u32,
18	pub dwTrackFlags: co::SLR,
19	pub dwClassContext: co::CLSCTX,
20	pub locale: LCID,
21	pServerInfo: *mut COSERVERINFO<'b, 'c, 'd, 'e, 'f, 'g, 'i>,
22	pub hWnd: HWND,
23
24	_pServerInfo: PhantomData<&'a mut COSERVERINFO<'b, 'c, 'd, 'e, 'f, 'g, 'i>>,
25}
26
27impl_default!(BIND_OPTS3, cbStruct, 'a, 'b, 'c, 'd, 'e, 'f, 'g, 'i);
28
29impl<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'i> BIND_OPTS3<'a, 'b, 'c, 'd, 'e, 'f, 'g, 'i> {
30	pub_fn_ptr_get_set!('a, pServerInfo, set_pServerInfo, COSERVERINFO<'b, 'c, 'd, 'e, 'f, 'g, 'i>);
31}
32
33/// [`COAUTHIDENTITY`](https://learn.microsoft.com/en-us/windows/win32/api/wtypesbase/ns-wtypesbase-coauthidentity)
34/// struct.
35#[repr(C)]
36pub struct COAUTHIDENTITY<'a, 'b, 'c> {
37	User: *mut u16,
38	UserLength: u32,
39	Domain: *mut u16,
40	DomainLength: u32,
41	Password: *mut u16,
42	PasswordLength: u32,
43	pub Flags: co::SEC_WINNT_AUTH_IDENTITY,
44
45	_User: PhantomData<&'a mut u16>,
46	_Domain: PhantomData<&'b mut u16>,
47	_Password: PhantomData<&'c mut u16>,
48}
49
50impl_default!(COAUTHIDENTITY, 'a, 'b, 'c);
51
52impl<'a, 'b, 'c> COAUTHIDENTITY<'a, 'b, 'c> {
53	pub_fn_string_ptrlen_get_set!('a, User, set_User, UserLength);
54	pub_fn_string_ptrlen_get_set!('b, Domain, set_Domain, DomainLength);
55	pub_fn_string_ptrlen_get_set!('c, Password, set_Password, PasswordLength);
56}
57
58/// [`COAUTHINFO`](https://learn.microsoft.com/en-us/windows/win32/api/wtypesbase/ns-wtypesbase-coauthinfo)
59/// struct.
60#[repr(C)]
61pub struct COAUTHINFO<'a, 'b, 'c, 'd, 'e> {
62	pub dwAuthnSvc: co::RPC_C_AUTHN,
63	pub dwAuthzSvc: co::RPC_C_AUTHZ,
64	pwszServerPrincName: *mut u16,
65	pub dwAuthnLevel: co::RPC_C_AUTHN_LEVEL,
66	pub dwImpersonationLevel: co::RPC_C_IMP_LEVEL,
67	pAuthIdentityData: *mut COAUTHIDENTITY<'c, 'd, 'e>,
68	pub dwCapabilities: co::RPC_C_QOS_CAPABILITIES,
69
70	_pwszServerPrincName: PhantomData<&'a mut u16>,
71	_pAuthIdentityData: PhantomData<&'b mut COAUTHIDENTITY<'c, 'd, 'e>>,
72}
73
74impl_default!(COAUTHINFO, 'a, 'b, 'c, 'd, 'e);
75
76impl<'a, 'b, 'c, 'd, 'e> COAUTHINFO<'a, 'b, 'c, 'd, 'e> {
77	pub_fn_string_ptr_get_set!('a, pwszServerPrincName, set_pwszServerPrincName);
78	pub_fn_ptr_get_set!('b, pAuthIdentityData, set_pAuthIdentityData, COAUTHIDENTITY<'c, 'd, 'e>);
79}
80
81/// [`COSERVERINFO`](https://learn.microsoft.com/en-us/windows/win32/api/objidl/ns-objidl-coserverinfo)
82/// struct.
83#[repr(C)]
84pub struct COSERVERINFO<'a, 'b, 'c, 'd, 'e, 'f, 'g> {
85	dwReserved1: u32,
86	pwszName: *mut u16,
87	pAuthInfo: *mut COAUTHINFO<'c, 'd, 'e, 'f, 'g>,
88	dwReserved2: u32,
89
90	_pwszName: PhantomData<&'a mut u16>,
91	_pAuthInfo: PhantomData<&'b COAUTHINFO<'c, 'd, 'e, 'f, 'g>>,
92}
93
94impl_default!(COSERVERINFO, 'a, 'b, 'c, 'd, 'e, 'f, 'g);
95
96impl<'a, 'b, 'c, 'd, 'e, 'f, 'g> COSERVERINFO<'a, 'b, 'c, 'd, 'e, 'f, 'g> {
97	pub_fn_string_ptr_get_set!('a, pwszName, set_pwszName);
98	pub_fn_ptr_get_set!('b, pAuthInfo, set_pAuthInfo, COAUTHINFO<'c, 'd, 'e, 'f, 'g>);
99}
100
101/// [`FORMATETC`](https://learn.microsoft.com/en-us/windows/win32/api/objidl/ns-objidl-formatetc)
102/// struct.
103///
104/// The [`Default`] trait automatically initializes `lindex` to `-1`.
105#[repr(C)]
106pub struct FORMATETC<'a> {
107	pub cfFormat: co::CF,
108	ptd: *mut DVTARGETDEVICE,
109	pub dwAspect: co::DVASPECT,
110	pub lindex: i32,
111	pub tymed: co::TYMED,
112
113	_ptd: PhantomData<&'a mut DVTARGETDEVICE>,
114}
115
116impl<'a> Default for FORMATETC<'a> {
117	fn default() -> Self {
118		Self {
119			cfFormat: co::CF::default(),
120			ptd: std::ptr::null_mut(),
121			dwAspect: co::DVASPECT::default(),
122			lindex: -1,
123			tymed: co::TYMED::default(),
124			_ptd: PhantomData,
125		}
126	}
127}
128
129impl<'a> FORMATETC<'a> {
130	pub_fn_ptr_get_set!('a, ptd, set_ptd, DVTARGETDEVICE);
131}
132
133/// [`DVTARGETDEVICE`](https://learn.microsoft.com/en-us/windows/win32/api/objidl/ns-objidl-dvtargetdevice)
134/// struct.
135///
136/// The `tdData` field is dynamically allocated.
137#[repr(C)]
138#[derive(Default)]
139pub struct DVTARGETDEVICE {
140	pub tdSize: u32,
141	pub tdDriverNameOffset: u16,
142	pub tdDeviceNameOffset: u16,
143	pub tdPortNameOffset: u16,
144	pub tdExtDevmodeOffset: u16,
145	pub tdData: [u8; 1],
146}
147
148/// [`SNB`](https://learn.microsoft.com/en-us/windows/win32/stg/snb)
149/// struct.
150#[repr(transparent)]
151pub struct SNB(*mut *mut u16);
152
153impl_default!(SNB);
154
155impl Drop for SNB {
156	fn drop(&mut self) {
157		let _ = unsafe { CoTaskMemFreeGuard::new(self.0 as _, 0) }; // size is irrelevant
158	}
159}
160
161impl SNB {
162	/// Creates a new `SNB` by allocating a contiguous memory block for pointers
163	/// and strings.
164	#[must_use]
165	pub fn from_strs(strs: &[impl AsRef<str>]) -> HrResult<Self> {
166		if strs.is_empty() {
167			return Ok(Self::default());
168		}
169
170		let tot_bytes_ptrs = (strs.len() + 1) * std::mem::size_of::<*mut u16>(); // plus null
171
172		let wstrs = WString::from_str_vec(strs);
173		let num_valid_chars = wstrs
174			.as_slice() // count just the chars; important because stack alloc has zero fills
175			.iter()
176			.filter(|ch| **ch != 0x0000)
177			.count();
178		let tot_bytes_wstrs = ( num_valid_chars + strs.len() ) // plus one null for each string
179			* std::mem::size_of::<u16>();
180
181		let mut block = CoTaskMemAlloc(tot_bytes_ptrs + tot_bytes_wstrs)?; // alloc block for pointers and strings
182		let ptr_block = block.as_mut_ptr() as *mut u8;
183		let ptr_block_wstrs = unsafe { ptr_block.add(tot_bytes_ptrs) } as *mut u16; // start of strings block
184
185		let mut idx_cur_wstr = 0; // current string to be copied to block
186		*unsafe { block.as_mut_slice_aligned::<*mut u16>() }
187			.get_mut(idx_cur_wstr)
188			.unwrap() = ptr_block_wstrs; // copy pointer to 1st string
189		idx_cur_wstr += 1;
190
191		wstrs.as_slice().iter().enumerate().for_each(|(idx, ch)| {
192			if *ch == 0x0000 && idx_cur_wstr < strs.len() {
193				unsafe {
194					*block
195						.as_mut_slice_aligned::<*mut u16>() // copy pointer to subsequent strings in the block
196						.get_mut(idx_cur_wstr)
197						.unwrap() = ptr_block_wstrs.add(idx + 1);
198				}
199				idx_cur_wstr += 1;
200			}
201		});
202
203		*unsafe { block.as_mut_slice_aligned::<*mut u16>() }
204			.get_mut(idx_cur_wstr)
205			.unwrap() = std::ptr::null_mut(); // null pointer after string pointers
206
207		wstrs.copy_to_slice(
208			// Beyond pointers, copy each null-terminated string sequentially.
209			unsafe {
210				std::slice::from_raw_parts_mut(
211					ptr_block_wstrs,
212					tot_bytes_wstrs / std::mem::size_of::<u16>(),
213				)
214			},
215		);
216
217		let (ptr, _) = block.leak();
218		Ok(Self(ptr as _))
219	}
220
221	/// Returns the underlying pointer.
222	#[must_use]
223	pub const fn as_ptr(&self) -> *mut *mut u16 {
224		self.0
225	}
226
227	/// Converts the internal UTF-16 blocks into strings.
228	#[must_use]
229	pub fn to_strings(&self) -> Vec<String> {
230		let mut vec = Vec::<String>::new();
231		if !self.0.is_null() {
232			let mut idx_ptr = 0;
233			loop {
234				let ptr_ws = unsafe {
235					let sli_ptrs = std::slice::from_raw_parts(self.0, idx_ptr + 1);
236					*sli_ptrs.get_unchecked(idx_ptr) // get nth pointer to string
237				};
238				if ptr_ws.is_null() {
239					// a null pointer means the end of pointers block
240					break;
241				}
242				let ws = unsafe { WString::from_wchars_nullt(ptr_ws) };
243				vec.push(ws.to_string());
244				idx_ptr += 1;
245			}
246		}
247		vec
248	}
249}
250
251/// [`STGMEDIUM`](https://learn.microsoft.com/en-us/windows/win32/api/objidl/ns-objidl-ustgmedium-r1)
252/// struct.
253#[repr(C)]
254pub struct STGMEDIUM {
255	pub tymed: co::TYMED,
256	pub ptr: usize,
257	pub pUnkForRelease: COMPTR,
258}
259
260impl_default!(STGMEDIUM);
261
262impl STGMEDIUM {
263	/// Returns `ptr` as [`HGLOBAL`](crate::HGLOBAL) if `tymed` is
264	/// [`TYMED::GDI`](crate::co::TYMED::HGLOBAL).
265	///
266	/// # Safety
267	///
268	/// Make sure the struct has been properly initialized.
269	#[must_use]
270	pub const unsafe fn ptr_hglobal(&self) -> Option<HGLOBAL> {
271		match &self.tymed {
272			&co::TYMED::HGLOBAL => Some(unsafe { HGLOBAL::from_ptr(self.ptr as _) }),
273			_ => None,
274		}
275	}
276}