cfun/
c_dism.rs

1#[cfg(all(feature = "dism", target_os = "windows"))]
2use std::sync::OnceLock;
3
4#[cfg(all(feature = "dism", target_os = "windows"))]
5use libloading::{Library, Symbol};
6
7#[cfg(all(feature = "dism", target_os = "windows"))]
8pub type DismSession = u32;
9
10#[repr(C)]
11#[cfg(all(feature = "dism", target_os = "windows"))]
12pub struct RawDismCustomProperty {
13    pub name: *const u16,
14    pub value: *const u16,
15    pub path: *const u16,
16}
17
18#[allow(non_snake_case)]
19#[cfg(all(feature = "dism", target_os = "windows"))]
20#[repr(C, packed)]
21#[derive(Debug)]
22pub struct RawDismFeatureInfo {
23    pub FeatureName: *const u16,
24    pub FeatureState: i32,
25    pub DisplayName: *const u16,
26    pub Description: *const u16,
27    pub RestartRequired: u32,
28    pub CustomProperty: *const RawDismCustomProperty,
29    pub CustomPropertyCount: u32,
30}
31
32#[derive(Debug, Default)]
33#[cfg(all(feature = "dism", target_os = "windows"))]
34pub struct DismCustomProperty {
35    pub name: String,
36    pub value: String,
37    pub path: String,
38}
39
40#[derive(Debug, PartialEq)]
41#[cfg(all(feature = "dism", target_os = "windows"))]
42pub enum DismPackageFeatureState {
43    DismStateNotPresent = 0,
44    DismStateUninstallPending = 1,
45    DismStateStaged = 2,
46    DismStateRemoved = 3,
47    DismStateInstalled = 4,
48    DismStateInstallPending = 5,
49    DismStateSuperseded = 6,
50    DismStatePartiallyInstalled = 7,
51}
52
53#[cfg(all(feature = "dism", target_os = "windows"))]
54impl Default for DismPackageFeatureState {
55    fn default() -> Self {
56        DismPackageFeatureState::DismStateNotPresent
57    }
58}
59
60#[cfg(all(feature = "dism", target_os = "windows"))]
61impl From<i32> for DismPackageFeatureState {
62    fn from(value: i32) -> Self {
63        match value {
64            0 => DismPackageFeatureState::DismStateNotPresent,
65            1 => DismPackageFeatureState::DismStateUninstallPending,
66            2 => DismPackageFeatureState::DismStateStaged,
67            3 => DismPackageFeatureState::DismStateRemoved,
68            4 => DismPackageFeatureState::DismStateInstalled,
69            5 => DismPackageFeatureState::DismStateInstallPending,
70            6 => DismPackageFeatureState::DismStateSuperseded,
71            7 => DismPackageFeatureState::DismStatePartiallyInstalled,
72            _ => panic!("unexpect value"),
73        }
74    }
75}
76
77#[derive(Debug, PartialEq)]
78#[cfg(all(feature = "dism", target_os = "windows"))]
79pub enum DismRestartType {
80    DismRestartNo = 0,
81    DismRestartPossible = 1,
82    DismRestartRequired = 2,
83}
84#[cfg(all(feature = "dism", target_os = "windows"))]
85impl Default for DismRestartType {
86    fn default() -> Self {
87        DismRestartType::DismRestartNo
88    }
89}
90
91#[cfg(all(feature = "dism", target_os = "windows"))]
92impl From<u32> for DismRestartType {
93    fn from(value: u32) -> Self {
94        match value {
95            0 => DismRestartType::DismRestartNo,
96            1 => DismRestartType::DismRestartPossible,
97            2 => DismRestartType::DismRestartRequired,
98            _ => panic!("unexpect value"),
99        }
100    }
101}
102
103#[derive(Debug, Default)]
104#[cfg(all(feature = "dism", target_os = "windows"))]
105pub struct DismFeatureInfo {
106    pub feature_name: String,
107    pub feature_state: DismPackageFeatureState,
108    pub display_name: String,
109    pub description: String,
110    pub restart_required: DismRestartType,
111    pub custom_property: Vec<DismCustomProperty>,
112}
113
114#[cfg(all(feature = "dism", target_os = "windows"))]
115type DismInitializeFn = unsafe extern "system" fn(
116    logLevel: u32,
117    logFilePath: *const u16,
118    scratchDirectory: *const u16,
119) -> i32;
120#[cfg(all(feature = "dism", target_os = "windows"))]
121type DismOpenSessionFn = unsafe extern "system" fn(
122    ImagePath: *const u16,
123    WindowsDirectory: *const u16,
124    SystemDrive: *const u16,
125    Session: *mut DismSession,
126) -> i32;
127#[cfg(all(feature = "dism", target_os = "windows"))]
128type DismGetFeatureInfoFn = unsafe extern "system" fn(
129    session: DismSession,
130    featureName: *const u16,
131    Identifier: *const u16,
132    PackageIdentifier: u32,
133    featureInfo: *mut *mut RawDismFeatureInfo,
134) -> i32;
135
136#[cfg(all(feature = "dism", target_os = "windows"))]
137type DismProgressCallback =
138    unsafe extern "system" fn(Current: u32, Total: u32, UserData: *mut std::ffi::c_void);
139
140#[cfg(all(feature = "dism", target_os = "windows"))]
141type DismEnableFeatureFn = unsafe extern "system" fn(
142    session: DismSession,
143    featureName: *const u16,
144    identifier: *const u16,
145    packageIdentifier: u32,
146    limitAccess: i32,
147    sourcePaths: *const *const u16,
148    sourcePathsCount: u32,
149    enableAll: i32,
150    cancelEvent: *const std::ffi::c_void,
151    progress: DismProgressCallback,
152    userData: *const std::ffi::c_void,
153) -> i32;
154
155#[cfg(all(feature = "dism", target_os = "windows"))]
156type DismCloseSessionFn = unsafe extern "system" fn(session: DismSession) -> i32;
157#[cfg(all(feature = "dism", target_os = "windows"))]
158type DismShutdownFn = unsafe extern "system" fn() -> i32;
159
160#[cfg(all(feature = "dism", target_os = "windows"))]
161struct DismString {
162    value: *const u16,
163}
164
165#[cfg(all(feature = "dism", target_os = "windows"))]
166type DismGetLastErrorMessageFn =
167    unsafe extern "system" fn(ErrorMessage: *mut *mut DismString) -> i32;
168#[cfg(all(feature = "dism", target_os = "windows"))]
169type DismDeleteFn = unsafe extern "system" fn(resource: *const std::ffi::c_void);
170
171#[cfg(all(feature = "dism", target_os = "windows"))]
172static DISM_LIB: OnceLock<Library> = OnceLock::new();
173#[cfg(all(feature = "dism", target_os = "windows"))]
174static DISM_INITIALIZE_FN: OnceLock<Symbol<DismInitializeFn>> = OnceLock::new();
175#[cfg(all(feature = "dism", target_os = "windows"))]
176static DISM_OPEN_SESSION_FN: OnceLock<Symbol<DismOpenSessionFn>> = OnceLock::new();
177#[cfg(all(feature = "dism", target_os = "windows"))]
178static DISM_GET_FEATURE_INFO_FN: OnceLock<Symbol<DismGetFeatureInfoFn>> = OnceLock::new();
179#[cfg(all(feature = "dism", target_os = "windows"))]
180static DISM_ENABLE_FEATURE_FN: OnceLock<Symbol<DismEnableFeatureFn>> = OnceLock::new();
181#[cfg(all(feature = "dism", target_os = "windows"))]
182static DISM_CLOSE_SESSION_FN: OnceLock<Symbol<DismCloseSessionFn>> = OnceLock::new();
183#[cfg(all(feature = "dism", target_os = "windows"))]
184static DISM_SHUTDOWN_FN: OnceLock<Symbol<DismShutdownFn>> = OnceLock::new();
185#[cfg(all(feature = "dism", target_os = "windows"))]
186static DISM_GET_LAST_ERROR_MESSAGE_FN: OnceLock<Symbol<DismGetLastErrorMessageFn>> =
187    OnceLock::new();
188#[cfg(all(feature = "dism", target_os = "windows"))]
189static DISM_DELETE_FN: OnceLock<Symbol<DismDeleteFn>> = OnceLock::new();
190
191#[cfg(all(feature = "dism", target_os = "windows"))]
192fn get_dism_lib() -> Result<&'static Library, windows::core::Error> {
193    if DISM_LIB.get().is_none() {
194        unsafe {
195            let dismapi = Library::new("dismapi.dll");
196            let dismapi = match dismapi {
197                Ok(f) => f,
198                Err(_e) => return Err(windows::core::Error::from_win32()),
199            };
200            DISM_LIB.get_or_init(|| dismapi);
201        }
202    };
203    Ok(DISM_LIB.get().unwrap())
204}
205
206#[derive(Debug)]
207#[cfg(all(feature = "dism", target_os = "windows"))]
208pub enum DismLogLevel {
209    DismLogErrors,
210    DismLogErrorsWarnings,
211    DismLogErrorsWarningsInfo,
212}
213
214#[cfg(all(feature = "dism", target_os = "windows"))]
215impl From<DismLogLevel> for u32 {
216    fn from(v: DismLogLevel) -> Self {
217        match v {
218            DismLogLevel::DismLogErrors => 0,
219            DismLogLevel::DismLogErrorsWarnings => 1,
220            DismLogLevel::DismLogErrorsWarningsInfo => 2,
221        }
222    }
223}
224
225#[cfg(all(feature = "dism", target_os = "windows"))]
226#[allow(non_snake_case)]
227pub fn DismInitialize(
228    log_level: DismLogLevel,
229    log_file_path: Option<&str>,
230    scratch_directory: Option<&str>,
231) -> Result<(), windows::core::Error> {
232    use windows::core::HRESULT;
233
234    let dism_lib = get_dism_lib()?;
235
236    unsafe {
237        if DISM_INITIALIZE_FN.get().is_none() {
238            let dism_init_fn = dism_lib.get(b"DismInitialize");
239            let dism_init_fn = match dism_init_fn {
240                Ok(f) => f,
241                Err(_e) => return Err(windows::core::Error::from_win32()),
242            };
243            DISM_INITIALIZE_FN.get_or_init(|| dism_init_fn);
244        }
245    }
246    let dism_init_fn = DISM_INITIALIZE_FN.get().unwrap();
247
248    let log_file_path = match log_file_path {
249        Some(path) => {
250            let path: Vec<u16> = path.encode_utf16().chain([0]).collect();
251            path
252        }
253        None => Vec::new(),
254    };
255
256    let log_file_path = if log_file_path.is_empty() {
257        std::ptr::null()
258    } else {
259        log_file_path.as_ptr()
260    };
261
262    let scratch_directory = match scratch_directory {
263        Some(path) => {
264            let path: Vec<u16> = path.encode_utf16().chain([0]).collect();
265            path
266        }
267        None => Vec::new(),
268    };
269
270    let scratch_directory = if scratch_directory.is_empty() {
271        std::ptr::null()
272    } else {
273        scratch_directory.as_ptr()
274    };
275
276    unsafe {
277        let ret = dism_init_fn(log_level.into(), log_file_path, scratch_directory);
278        if ret != 0 {
279            return Err(windows::core::Error::from_hresult(HRESULT::from_win32(
280                ret as u32,
281            )));
282        }
283        Ok(())
284    }
285}
286
287#[cfg(all(feature = "dism", target_os = "windows"))]
288pub static DISM_ONLINE_IMAGE: &str = "DISM_{53BFAE52-B167-4E2F-A258-0A37B57FF845}";
289
290#[cfg(all(feature = "dism", target_os = "windows"))]
291#[allow(non_snake_case)]
292pub fn DismOpenSession(
293    ImagePath: &str,
294    WindowsDirectory: Option<&str>,
295    SystemDrive: Option<&str>,
296) -> Result<DismSession, windows::core::Error> {
297    use windows::core::HRESULT;
298
299    unsafe {
300        let dism_lib = get_dism_lib()?;
301
302        if DISM_OPEN_SESSION_FN.get().is_none() {
303            let dism_open_session = dism_lib.get(b"DismOpenSession");
304            let dism_open_session = match dism_open_session {
305                Ok(f) => f,
306                Err(_e) => return Err(windows::core::Error::from_win32()),
307            };
308            DISM_OPEN_SESSION_FN.get_or_init(|| dism_open_session);
309        }
310        let dism_open_session = DISM_OPEN_SESSION_FN.get().unwrap();
311
312        let mut ImagePath: Vec<u16> = ImagePath.encode_utf16().chain([0]).collect();
313
314        let WindowsDirectory = match WindowsDirectory {
315            Some(path) => {
316                let path: Vec<u16> = path.encode_utf16().chain([0]).collect();
317                path
318            }
319            None => Vec::new(),
320        };
321
322        let WindowsDirectory = if WindowsDirectory.is_empty() {
323            std::ptr::null()
324        } else {
325            WindowsDirectory.as_ptr()
326        };
327
328        let SystemDrive = match SystemDrive {
329            Some(path) => {
330                let path: Vec<u16> = path.encode_utf16().chain([0]).collect();
331                path
332            }
333            None => Vec::new(),
334        };
335
336        let SystemDrive = if SystemDrive.is_empty() {
337            std::ptr::null()
338        } else {
339            SystemDrive.as_ptr()
340        };
341        let mut session = DismSession::default();
342
343        let ret = dism_open_session(
344            ImagePath.as_mut_ptr(),
345            WindowsDirectory,
346            SystemDrive,
347            &mut session,
348        );
349        if ret != 0 {
350            return Err(windows::core::Error::from_hresult(HRESULT::from_win32(
351                ret as u32,
352            )));
353        }
354        Ok(session)
355    }
356}
357
358#[cfg(all(feature = "dism", target_os = "windows"))]
359pub enum DismPackageIdentifier {
360    DismPackageNone = 0,
361    DismPackageName = 1,
362    DismPackagePath = 2,
363}
364
365#[cfg(all(feature = "dism", target_os = "windows"))]
366impl From<DismPackageIdentifier> for u32 {
367    fn from(v: DismPackageIdentifier) -> Self {
368        match v {
369            DismPackageIdentifier::DismPackageNone => 0,
370            DismPackageIdentifier::DismPackageName => 1,
371            DismPackageIdentifier::DismPackagePath => 2,
372        }
373    }
374}
375
376#[cfg(all(feature = "dism", target_os = "windows"))]
377#[allow(non_snake_case)]
378pub fn DismGetFeatureInfo(
379    session: DismSession,
380    featureName: &str,
381    Identifier: Option<&str>,
382    PackageIdentifier: DismPackageIdentifier,
383) -> Result<DismFeatureInfo, windows::core::Error> {
384    use windows::core::{HRESULT, PCWSTR};
385
386    unsafe {
387        let dism_lib = get_dism_lib()?;
388
389        if DISM_GET_FEATURE_INFO_FN.get().is_none() {
390            let dism_get_feature_info = dism_lib.get(b"DismGetFeatureInfo");
391            let dism_get_feature_info = match dism_get_feature_info {
392                Ok(f) => f,
393                Err(_e) => return Err(windows::core::Error::from_win32()),
394            };
395            DISM_GET_FEATURE_INFO_FN.get_or_init(|| dism_get_feature_info);
396        }
397        let dism_get_feature_info = DISM_GET_FEATURE_INFO_FN.get().unwrap();
398
399        let featureName = featureName.encode_utf16().chain([0]).collect::<Vec<u16>>();
400
401        let Identifier = match Identifier {
402            Some(path) => {
403                let path: Vec<u16> = path.encode_utf16().chain([0]).collect();
404                path
405            }
406            None => Vec::new(),
407        };
408
409        let Identifier = if Identifier.is_empty() {
410            std::ptr::null()
411        } else {
412            Identifier.as_ptr()
413        };
414
415        let mut featureInfo: *mut RawDismFeatureInfo = std::ptr::null_mut();
416
417        let ret = dism_get_feature_info(
418            session,
419            featureName.as_ptr(),
420            Identifier,
421            PackageIdentifier.into(),
422            &mut featureInfo,
423        );
424
425        if ret != 0 {
426            return Err(windows::core::Error::from_hresult(HRESULT::from_win32(
427                ret as u32,
428            )));
429        }
430
431        let featureInfo = featureInfo.as_ref().unwrap();
432
433        let mut feature_info = DismFeatureInfo::default();
434        if !featureInfo.FeatureName.is_null() {
435            let name = PCWSTR::from_raw(featureInfo.FeatureName);
436            let name = name.to_string().unwrap_or_default();
437            feature_info.feature_name = name;
438        }
439
440        feature_info.feature_state = featureInfo.FeatureState.into();
441
442        if !featureInfo.DisplayName.is_null() {
443            let display_name = PCWSTR::from_raw(featureInfo.DisplayName);
444            let display_name = display_name.to_string().unwrap_or_default();
445            feature_info.display_name = display_name;
446        }
447
448        if !featureInfo.Description.is_null() {
449            let description = PCWSTR::from_raw(featureInfo.Description);
450            let description = description.to_string().unwrap_or_default();
451            feature_info.description = description;
452        }
453
454        feature_info.restart_required = featureInfo.RestartRequired.into();
455
456        if !featureInfo.CustomProperty.is_null() {
457            for i in 0..featureInfo.CustomPropertyCount {
458                let proper = featureInfo.CustomProperty.add(i.try_into().unwrap());
459                let proper = proper.as_ref().unwrap();
460                let mut custom_property = DismCustomProperty::default();
461                if !proper.name.is_null() {
462                    let name = PCWSTR::from_raw(proper.name);
463                    let name = name.to_string().unwrap_or_default();
464                    custom_property.name = name;
465                }
466
467                if !proper.value.is_null() {
468                    let value = PCWSTR::from_raw(proper.value);
469                    let value = value.to_string().unwrap_or_default();
470                    custom_property.value = value;
471                }
472
473                if !proper.path.is_null() {
474                    let path = PCWSTR::from_raw(proper.path);
475                    let path = path.to_string().unwrap_or_default();
476                    custom_property.path = path;
477                }
478                feature_info.custom_property.push(custom_property);
479            }
480        }
481
482        let _ = DismDelete(featureInfo as *const _ as *const std::ffi::c_void);
483
484        Ok(feature_info)
485    }
486}
487
488#[cfg(all(feature = "dism", target_os = "windows"))]
489#[allow(non_snake_case)]
490pub fn DismEnableFeature(
491    session: DismSession,
492    featureName: &str,
493    identifier: Option<&str>,
494    packageIdentifier: DismPackageIdentifier,
495    enableAll: bool,
496    progress: Option<fn(cur: u32, total: u32, user_data: *const std::ffi::c_void)>,
497    user_data: Option<*const std::ffi::c_void>,
498) -> Result<(), windows::core::Error> {
499    use windows::core::HRESULT;
500
501    let dism_lib = get_dism_lib()?;
502    unsafe {
503        if DISM_ENABLE_FEATURE_FN.get().is_none() {
504            let dism_enable_feature = dism_lib.get(b"DismEnableFeature");
505            let dism_enable_feature = match dism_enable_feature {
506                Ok(f) => f,
507                Err(_e) => return Err(windows::core::Error::from_win32()),
508            };
509            DISM_ENABLE_FEATURE_FN.get_or_init(|| dism_enable_feature);
510        }
511        let dism_enable_feature = DISM_ENABLE_FEATURE_FN.get().unwrap();
512
513        let featureName = featureName.encode_utf16().chain([0]).collect::<Vec<u16>>();
514
515        let identifier = match identifier {
516            Some(path) => {
517                let path: Vec<u16> = path.encode_utf16().chain([0]).collect();
518                path
519            }
520            None => Vec::new(),
521        };
522
523        let identifier = if identifier.is_empty() {
524            std::ptr::null()
525        } else {
526            identifier.as_ptr()
527        };
528
529        let enableAll = if enableAll { 1 } else { 0 };
530
531        let data = EnableFeatureCallBackData {
532            progress,
533            user_data,
534        };
535        let data = Box::new(data);
536
537        let ret = dism_enable_feature(
538            session,
539            featureName.as_ptr(),
540            identifier,
541            packageIdentifier.into(),
542            0,
543            std::ptr::null(),
544            0,
545            enableAll,
546            std::ptr::null(),
547            std::mem::transmute(enable_feature_callback as *const std::ffi::c_void),
548            data.as_ref() as *const _ as *const std::ffi::c_void,
549        );
550        if ret != 0 {
551            return Err(windows::core::Error::from_hresult(HRESULT::from_win32(
552                ret as u32,
553            )));
554        }
555
556        Ok(())
557    }
558}
559
560#[cfg(all(feature = "dism", target_os = "windows"))]
561struct EnableFeatureCallBackData {
562    progress: Option<fn(u32, u32, *const std::ffi::c_void)>,
563    user_data: Option<*const std::ffi::c_void>,
564}
565
566#[cfg(all(feature = "dism", target_os = "windows"))]
567unsafe extern "system" fn enable_feature_callback(
568    current: u32,
569    total: u32,
570    user_data: *mut std::ffi::c_void,
571) {
572    let data = user_data as *const EnableFeatureCallBackData;
573    let data = data.as_ref().unwrap();
574    if let Some(progress) = data.progress {
575        if let Some(user_data) = data.user_data {
576            progress(current, total, user_data);
577        } else {
578            progress(current, total, std::ptr::null());
579        }
580    };
581}
582
583#[cfg(all(feature = "dism", target_os = "windows"))]
584#[allow(non_snake_case)]
585pub fn DismCloseSession(session: DismSession) -> Result<(), windows::core::Error> {
586    use windows::core::HRESULT;
587
588    unsafe {
589        let dism_lib = get_dism_lib()?;
590
591        if DISM_CLOSE_SESSION_FN.get().is_none() {
592            let DismCloseSession = dism_lib.get(b"DismCloseSession");
593            let DismCloseSession = match DismCloseSession {
594                Ok(f) => f,
595                Err(_e) => return Err(windows::core::Error::from_win32()),
596            };
597            DISM_CLOSE_SESSION_FN.get_or_init(|| DismCloseSession);
598        }
599        let dism_close_session = DISM_CLOSE_SESSION_FN.get().unwrap();
600        let ret = dism_close_session(session);
601        if ret != 0 {
602            return Err(windows::core::Error::from_hresult(HRESULT::from_win32(
603                ret as u32,
604            )));
605        }
606        Ok(())
607    }
608}
609
610#[cfg(all(feature = "dism", target_os = "windows"))]
611#[allow(non_snake_case)]
612pub fn DismShutdown() -> Result<(), windows::core::Error> {
613    use windows::core::HRESULT;
614
615    unsafe {
616        let dism_lib = get_dism_lib()?;
617
618        if DISM_SHUTDOWN_FN.get().is_none() {
619            let dism_shutdown = dism_lib.get(b"DismShutdown");
620            let dism_shutdown = match dism_shutdown {
621                Ok(f) => f,
622                Err(_e) => return Err(windows::core::Error::from_win32()),
623            };
624            DISM_SHUTDOWN_FN.get_or_init(|| dism_shutdown);
625        }
626        let dism_shutdown = DISM_SHUTDOWN_FN.get().unwrap();
627        let ret = dism_shutdown();
628        if ret != 0 {
629            return Err(windows::core::Error::from_hresult(HRESULT::from_win32(
630                ret as u32,
631            )));
632        }
633        Ok(())
634    }
635}
636
637#[cfg(all(feature = "dism", target_os = "windows"))]
638#[allow(non_snake_case)]
639pub fn DismGetLastErrorMessage() -> Result<String, windows::core::Error> {
640    use windows::core::{HRESULT, PCWSTR};
641
642    unsafe {
643        let dism_lib = get_dism_lib()?;
644
645        if DISM_GET_LAST_ERROR_MESSAGE_FN.get().is_none() {
646            let dism_get_last_error_message = dism_lib.get(b"DismGetLastErrorMessage");
647            let dism_get_last_error_message = match dism_get_last_error_message {
648                Ok(f) => f,
649                Err(_e) => return Err(windows::core::Error::from_win32()),
650            };
651            DISM_GET_LAST_ERROR_MESSAGE_FN.get_or_init(|| dism_get_last_error_message);
652        }
653        let dism_get_last_error_message = DISM_GET_LAST_ERROR_MESSAGE_FN.get().unwrap();
654        let mut errmsg: *mut DismString = std::ptr::null_mut();
655        let ret = dism_get_last_error_message(&mut errmsg);
656        if ret == 1 {
657            return Ok(String::new());
658        }
659        if ret != 0 {
660            return Err(windows::core::Error::from_hresult(HRESULT::from_win32(
661                ret as u32,
662            )));
663        }
664        let wstr = PCWSTR::from_raw((*errmsg).value);
665        let msg = wstr.to_string().unwrap_or_default();
666        let _ = DismDelete(errmsg as *const _);
667        Ok(msg)
668    }
669}
670
671#[cfg(all(feature = "dism", target_os = "windows"))]
672#[allow(non_snake_case)]
673pub fn DismDelete(resource: *const std::ffi::c_void) -> Result<(), windows::core::Error> {
674    unsafe {
675        let dism_lib = get_dism_lib()?;
676
677        if DISM_DELETE_FN.get().is_none() {
678            let dism_delete = dism_lib.get(b"DismDelete");
679            let dism_delete = match dism_delete {
680                Ok(f) => f,
681                Err(_e) => return Err(windows::core::Error::from_win32()),
682            };
683            DISM_DELETE_FN.get_or_init(|| dism_delete);
684        }
685        let dism_shutdown = DISM_DELETE_FN.get().unwrap();
686        dism_shutdown(resource);
687        Ok(())
688    }
689}