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}