1 // Copyright © 2017 winapi-rs developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
4 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
5 // All files in the project carrying such notice may not be copied, modified, or distributed
6 // except according to those terms.
7 
8 #![allow(bad_style)]
9 #![allow(unused)]
10 
11 use crate::winapi::Interface;
12 use crate::winapi::BSTR;
13 use crate::winapi::LPCOLESTR;
14 use crate::winapi::LPSAFEARRAY;
15 use crate::winapi::S_FALSE;
16 use crate::winapi::{CoCreateInstance, CLSCTX_ALL};
17 use crate::winapi::{IUnknown, IUnknownVtbl};
18 use crate::winapi::{HRESULT, LCID, LPCWSTR, PULONGLONG};
19 use crate::winapi::{LPFILETIME, ULONG};
20 use std::ffi::OsString;
21 use std::ptr::null_mut;
22 
23 use crate::com::{BStr, ComPtr};
24 
25 // Bindings to the Setup.Configuration stuff
26 pub type InstanceState = u32;
27 
28 pub const eNone: InstanceState = 0;
29 pub const eLocal: InstanceState = 1;
30 pub const eRegistered: InstanceState = 2;
31 pub const eNoRebootRequired: InstanceState = 4;
32 pub const eComplete: InstanceState = -1i32 as u32;
33 
34 RIDL! {#[uuid(0xb41463c3, 0x8866, 0x43b5, 0xbc, 0x33, 0x2b, 0x06, 0x76, 0xf7, 0xf4, 0x2e)]
35 interface ISetupInstance(ISetupInstanceVtbl): IUnknown(IUnknownVtbl) {
36     fn GetInstanceId(
37         pbstrInstanceId: *mut BSTR,
38     ) -> HRESULT,
39     fn GetInstallDate(
40         pInstallDate: LPFILETIME,
41     ) -> HRESULT,
42     fn GetInstallationName(
43         pbstrInstallationName: *mut BSTR,
44     ) -> HRESULT,
45     fn GetInstallationPath(
46         pbstrInstallationPath: *mut BSTR,
47     ) -> HRESULT,
48     fn GetInstallationVersion(
49         pbstrInstallationVersion: *mut BSTR,
50     ) -> HRESULT,
51     fn GetDisplayName(
52         lcid: LCID,
53         pbstrDisplayName: *mut BSTR,
54     ) -> HRESULT,
55     fn GetDescription(
56         lcid: LCID,
57         pbstrDescription: *mut BSTR,
58     ) -> HRESULT,
59     fn ResolvePath(
60         pwszRelativePath: LPCOLESTR,
61         pbstrAbsolutePath: *mut BSTR,
62     ) -> HRESULT,
63 }}
64 
65 RIDL! {#[uuid(0x89143c9a, 0x05af, 0x49b0, 0xb7, 0x17, 0x72, 0xe2, 0x18, 0xa2, 0x18, 0x5c)]
66 interface ISetupInstance2(ISetupInstance2Vtbl): ISetupInstance(ISetupInstanceVtbl) {
67     fn GetState(
68         pState: *mut InstanceState,
69     ) -> HRESULT,
70     fn GetPackages(
71         ppsaPackages: *mut LPSAFEARRAY,
72     ) -> HRESULT,
73     fn GetProduct(
74         ppPackage: *mut *mut ISetupPackageReference,
75     ) -> HRESULT,
76     fn GetProductPath(
77         pbstrProductPath: *mut BSTR,
78     ) -> HRESULT,
79 }}
80 
81 RIDL! {#[uuid(0x6380bcff, 0x41d3, 0x4b2e, 0x8b, 0x2e, 0xbf, 0x8a, 0x68, 0x10, 0xc8, 0x48)]
82 interface IEnumSetupInstances(IEnumSetupInstancesVtbl): IUnknown(IUnknownVtbl) {
83     fn Next(
84         celt: ULONG,
85         rgelt: *mut *mut ISetupInstance,
86         pceltFetched: *mut ULONG,
87     ) -> HRESULT,
88     fn Skip(
89         celt: ULONG,
90     ) -> HRESULT,
91     fn Reset() -> HRESULT,
92     fn Clone(
93         ppenum: *mut *mut IEnumSetupInstances,
94     ) -> HRESULT,
95 }}
96 
97 RIDL! {#[uuid(0x42843719, 0xdb4c, 0x46c2, 0x8e, 0x7c, 0x64, 0xf1, 0x81, 0x6e, 0xfd, 0x5b)]
98 interface ISetupConfiguration(ISetupConfigurationVtbl): IUnknown(IUnknownVtbl) {
99     fn EnumInstances(
100         ppEnumInstances: *mut *mut IEnumSetupInstances,
101     ) -> HRESULT,
102     fn GetInstanceForCurrentProcess(
103         ppInstance: *mut *mut ISetupInstance,
104     ) -> HRESULT,
105     fn GetInstanceForPath(
106         wzPath: LPCWSTR,
107         ppInstance: *mut *mut ISetupInstance,
108     ) -> HRESULT,
109 }}
110 
111 RIDL! {#[uuid(0x26aab78c, 0x4a60, 0x49d6, 0xaf, 0x3b, 0x3c, 0x35, 0xbc, 0x93, 0x36, 0x5d)]
112 interface ISetupConfiguration2(ISetupConfiguration2Vtbl):
113     ISetupConfiguration(ISetupConfigurationVtbl) {
114     fn EnumAllInstances(
115         ppEnumInstances: *mut *mut IEnumSetupInstances,
116     ) -> HRESULT,
117 }}
118 
119 RIDL! {#[uuid(0xda8d8a16, 0xb2b6, 0x4487, 0xa2, 0xf1, 0x59, 0x4c, 0xcc, 0xcd, 0x6b, 0xf5)]
120 interface ISetupPackageReference(ISetupPackageReferenceVtbl): IUnknown(IUnknownVtbl) {
121     fn GetId(
122         pbstrId: *mut BSTR,
123     ) -> HRESULT,
124     fn GetVersion(
125         pbstrVersion: *mut BSTR,
126     ) -> HRESULT,
127     fn GetChip(
128         pbstrChip: *mut BSTR,
129     ) -> HRESULT,
130     fn GetLanguage(
131         pbstrLanguage: *mut BSTR,
132     ) -> HRESULT,
133     fn GetBranch(
134         pbstrBranch: *mut BSTR,
135     ) -> HRESULT,
136     fn GetType(
137         pbstrType: *mut BSTR,
138     ) -> HRESULT,
139     fn GetUniqueId(
140         pbstrUniqueId: *mut BSTR,
141     ) -> HRESULT,
142 }}
143 
144 RIDL! {#[uuid(0x42b21b78, 0x6192, 0x463e, 0x87, 0xbf, 0xd5, 0x77, 0x83, 0x8f, 0x1d, 0x5c)]
145 interface ISetupHelper(ISetupHelperVtbl): IUnknown(IUnknownVtbl) {
146     fn ParseVersion(
147         pwszVersion: LPCOLESTR,
148         pullVersion: PULONGLONG,
149     ) -> HRESULT,
150     fn ParseVersionRange(
151         pwszVersionRange: LPCOLESTR,
152         pullMinVersion: PULONGLONG,
153         pullMaxVersion: PULONGLONG,
154     ) -> HRESULT,
155 }}
156 
157 DEFINE_GUID! {CLSID_SetupConfiguration,
158 0x177f0c4a, 0x1cd3, 0x4de7, 0xa3, 0x2c, 0x71, 0xdb, 0xbb, 0x9f, 0xa3, 0x6d}
159 
160 // Safe wrapper around the COM interfaces
161 pub struct SetupConfiguration(ComPtr<ISetupConfiguration>);
162 
163 impl SetupConfiguration {
164     pub fn new() -> Result<SetupConfiguration, i32> {
165         let mut obj = null_mut();
166         let err = unsafe {
167             CoCreateInstance(
168                 &CLSID_SetupConfiguration,
169                 null_mut(),
170                 CLSCTX_ALL,
171                 &ISetupConfiguration::uuidof(),
172                 &mut obj,
173             )
174         };
175         if err < 0 {
176             return Err(err);
177         }
178         let obj = unsafe { ComPtr::from_raw(obj as *mut ISetupConfiguration) };
179         Ok(SetupConfiguration(obj))
180     }
181     pub fn get_instance_for_current_process(&self) -> Result<SetupInstance, i32> {
182         let mut obj = null_mut();
183         let err = unsafe { self.0.GetInstanceForCurrentProcess(&mut obj) };
184         if err < 0 {
185             return Err(err);
186         }
187         Ok(unsafe { SetupInstance::from_raw(obj) })
188     }
189     pub fn enum_instances(&self) -> Result<EnumSetupInstances, i32> {
190         let mut obj = null_mut();
191         let err = unsafe { self.0.EnumInstances(&mut obj) };
192         if err < 0 {
193             return Err(err);
194         }
195         Ok(unsafe { EnumSetupInstances::from_raw(obj) })
196     }
197     pub fn enum_all_instances(&self) -> Result<EnumSetupInstances, i32> {
198         let mut obj = null_mut();
199         let this = self.0.cast::<ISetupConfiguration2>()?;
200         let err = unsafe { this.EnumAllInstances(&mut obj) };
201         if err < 0 {
202             return Err(err);
203         }
204         Ok(unsafe { EnumSetupInstances::from_raw(obj) })
205     }
206 }
207 
208 pub struct SetupInstance(ComPtr<ISetupInstance>);
209 
210 impl SetupInstance {
211     pub unsafe fn from_raw(obj: *mut ISetupInstance) -> SetupInstance {
212         SetupInstance(ComPtr::from_raw(obj))
213     }
214     pub fn instance_id(&self) -> Result<OsString, i32> {
215         let mut s = null_mut();
216         let err = unsafe { self.0.GetInstanceId(&mut s) };
217         let bstr = unsafe { BStr::from_raw(s) };
218         if err < 0 {
219             return Err(err);
220         }
221         Ok(bstr.to_osstring())
222     }
223     pub fn installation_name(&self) -> Result<OsString, i32> {
224         let mut s = null_mut();
225         let err = unsafe { self.0.GetInstallationName(&mut s) };
226         let bstr = unsafe { BStr::from_raw(s) };
227         if err < 0 {
228             return Err(err);
229         }
230         Ok(bstr.to_osstring())
231     }
232     pub fn installation_path(&self) -> Result<OsString, i32> {
233         let mut s = null_mut();
234         let err = unsafe { self.0.GetInstallationPath(&mut s) };
235         let bstr = unsafe { BStr::from_raw(s) };
236         if err < 0 {
237             return Err(err);
238         }
239         Ok(bstr.to_osstring())
240     }
241     pub fn installation_version(&self) -> Result<OsString, i32> {
242         let mut s = null_mut();
243         let err = unsafe { self.0.GetInstallationVersion(&mut s) };
244         let bstr = unsafe { BStr::from_raw(s) };
245         if err < 0 {
246             return Err(err);
247         }
248         Ok(bstr.to_osstring())
249     }
250     pub fn product_path(&self) -> Result<OsString, i32> {
251         let mut s = null_mut();
252         let this = self.0.cast::<ISetupInstance2>()?;
253         let err = unsafe { this.GetProductPath(&mut s) };
254         let bstr = unsafe { BStr::from_raw(s) };
255         if err < 0 {
256             return Err(err);
257         }
258         Ok(bstr.to_osstring())
259     }
260 }
261 
262 pub struct EnumSetupInstances(ComPtr<IEnumSetupInstances>);
263 
264 impl EnumSetupInstances {
265     pub unsafe fn from_raw(obj: *mut IEnumSetupInstances) -> EnumSetupInstances {
266         EnumSetupInstances(ComPtr::from_raw(obj))
267     }
268 }
269 
270 impl Iterator for EnumSetupInstances {
271     type Item = Result<SetupInstance, i32>;
272     fn next(&mut self) -> Option<Result<SetupInstance, i32>> {
273         let mut obj = null_mut();
274         let err = unsafe { self.0.Next(1, &mut obj, null_mut()) };
275         if err < 0 {
276             return Some(Err(err));
277         }
278         if err == S_FALSE {
279             return None;
280         }
281         Some(Ok(unsafe { SetupInstance::from_raw(obj) }))
282     }
283 }
284