1#![allow(non_snake_case)]
2use std::{cell::UnsafeCell, default::Default, ffi::c_void, mem, ptr};
3
4use windows::{
5 core::{Error, IUnknown, IUnknown_Vtbl, Interface, Result, BOOL, HRESULT, PCWSTR, PWSTR},
6 Win32::{
7 Foundation::{E_POINTER, E_UNEXPECTED, S_OK},
8 System::Com::CoTaskMemAlloc,
9 },
10};
11
12use windows_implement::implement;
13use windows_interface::interface;
14
15use crate::{
16 pwstr::{pwstr_from_str, string_from_pcwstr},
17 Microsoft::Web::WebView2::Win32::{
18 ICoreWebView2CustomSchemeRegistration, ICoreWebView2CustomSchemeRegistration_Impl,
19 ICoreWebView2EnvironmentOptions, ICoreWebView2EnvironmentOptions2,
20 ICoreWebView2EnvironmentOptions2_Impl, ICoreWebView2EnvironmentOptions3,
21 ICoreWebView2EnvironmentOptions3_Impl, ICoreWebView2EnvironmentOptions5,
22 ICoreWebView2EnvironmentOptions5_Impl, ICoreWebView2EnvironmentOptions6,
23 ICoreWebView2EnvironmentOptions6_Impl, ICoreWebView2EnvironmentOptions7,
24 ICoreWebView2EnvironmentOptions7_Impl, ICoreWebView2EnvironmentOptions8,
25 ICoreWebView2EnvironmentOptions8_Impl, ICoreWebView2EnvironmentOptions_Impl,
26 COREWEBVIEW2_CHANNEL_SEARCH_KIND, COREWEBVIEW2_CHANNEL_SEARCH_KIND_MOST_STABLE,
27 COREWEBVIEW2_RELEASE_CHANNELS, COREWEBVIEW2_RELEASE_CHANNELS_BETA,
28 COREWEBVIEW2_RELEASE_CHANNELS_CANARY, COREWEBVIEW2_RELEASE_CHANNELS_DEV,
29 COREWEBVIEW2_RELEASE_CHANNELS_STABLE, COREWEBVIEW2_SCROLLBAR_STYLE,
30 COREWEBVIEW2_SCROLLBAR_STYLE_DEFAULT, CORE_WEBVIEW_TARGET_PRODUCT_VERSION,
31 },
32};
33
34#[implement(
35 ICoreWebView2EnvironmentOptions,
36 ICoreWebView2EnvironmentOptions2,
37 ICoreWebView2EnvironmentOptions3,
38 IFixedEnvironmentOptions4,
39 ICoreWebView2EnvironmentOptions5,
40 ICoreWebView2EnvironmentOptions6,
41 ICoreWebView2EnvironmentOptions7,
42 ICoreWebView2EnvironmentOptions8
43)]
44pub struct CoreWebView2EnvironmentOptions {
45 additional_browser_arguments: UnsafeCell<String>,
46 language: UnsafeCell<String>,
47 target_compatible_browser_version: UnsafeCell<String>,
48 allow_single_sign_on_using_os_primary_account: UnsafeCell<bool>,
49 exclusive_user_data_folder_access: UnsafeCell<bool>,
50 is_custom_crash_reporting_enabled: UnsafeCell<bool>,
51 scheme_registrations: UnsafeCell<Vec<Option<ICoreWebView2CustomSchemeRegistration>>>,
52 enable_tracking_prevention: UnsafeCell<bool>,
53 are_browser_extensions_enabled: UnsafeCell<bool>,
54 channel_search_kind: UnsafeCell<COREWEBVIEW2_CHANNEL_SEARCH_KIND>,
55 release_channels: UnsafeCell<COREWEBVIEW2_RELEASE_CHANNELS>,
56 scroll_bar_style: UnsafeCell<COREWEBVIEW2_SCROLLBAR_STYLE>,
57}
58
59impl Default for CoreWebView2EnvironmentOptions {
60 fn default() -> Self {
61 Self {
62 additional_browser_arguments: String::new().into(),
63 language: String::new().into(),
64 target_compatible_browser_version: unsafe {
65 CORE_WEBVIEW_TARGET_PRODUCT_VERSION.to_string()
66 }
67 .unwrap_or_default()
68 .into(),
69 allow_single_sign_on_using_os_primary_account: false.into(),
70 exclusive_user_data_folder_access: false.into(),
71 is_custom_crash_reporting_enabled: false.into(),
72 scheme_registrations: Vec::new().into(),
73 enable_tracking_prevention: true.into(),
74 are_browser_extensions_enabled: false.into(),
75 channel_search_kind: COREWEBVIEW2_CHANNEL_SEARCH_KIND_MOST_STABLE.into(),
76 release_channels: (COREWEBVIEW2_RELEASE_CHANNELS_BETA
77 | COREWEBVIEW2_RELEASE_CHANNELS_CANARY
78 | COREWEBVIEW2_RELEASE_CHANNELS_DEV
79 | COREWEBVIEW2_RELEASE_CHANNELS_STABLE)
80 .into(),
81 scroll_bar_style: COREWEBVIEW2_SCROLLBAR_STYLE_DEFAULT.into(),
82 }
83 }
84}
85
86impl CoreWebView2EnvironmentOptions {
87 pub unsafe fn additional_browser_arguments(&self) -> &str {
95 (*self.additional_browser_arguments.get()).as_str()
96 }
97
98 pub unsafe fn set_additional_browser_arguments(&self, value: String) {
106 *self.additional_browser_arguments.get() = value;
107 }
108
109 pub unsafe fn language(&self) -> &str {
117 (*self.language.get()).as_str()
118 }
119
120 pub unsafe fn set_language(&self, value: String) {
129 *self.language.get() = value;
130 }
131
132 pub unsafe fn target_compatible_browser_version(&self) -> &str {
140 (*self.target_compatible_browser_version.get()).as_str()
141 }
142
143 pub unsafe fn set_target_compatible_browser_version(&self, value: String) {
152 *self.target_compatible_browser_version.get() = value;
153 }
154
155 pub unsafe fn allow_single_sign_on_using_os_primary_account(&self) -> bool {
163 *self.allow_single_sign_on_using_os_primary_account.get()
164 }
165
166 pub unsafe fn set_allow_single_sign_on_using_os_primary_account(&self, value: bool) {
174 *self.allow_single_sign_on_using_os_primary_account.get() = value;
175 }
176
177 pub unsafe fn exclusive_user_data_folder_access(&self) -> bool {
185 *self.exclusive_user_data_folder_access.get()
186 }
187
188 pub unsafe fn set_exclusive_user_data_folder_access(&self, value: bool) {
196 *self.exclusive_user_data_folder_access.get() = value;
197 }
198
199 pub unsafe fn is_custom_crash_reporting_enabled(&self) -> bool {
207 *self.is_custom_crash_reporting_enabled.get()
208 }
209
210 pub unsafe fn set_is_custom_crash_reporting_enabled(&self, value: bool) {
218 *self.is_custom_crash_reporting_enabled.get() = value;
219 }
220
221 pub unsafe fn scheme_registrations(
229 &self,
230 ) -> Vec<Option<ICoreWebView2CustomSchemeRegistration>> {
231 (*self.scheme_registrations.get()).clone()
232 }
233
234 pub unsafe fn set_scheme_registrations(
243 &self,
244 value: Vec<Option<ICoreWebView2CustomSchemeRegistration>>,
245 ) {
246 *self.scheme_registrations.get() = value;
247 }
248
249 pub unsafe fn enable_tracking_prevention(&self) -> bool {
257 *self.enable_tracking_prevention.get()
258 }
259
260 pub unsafe fn set_enable_tracking_prevention(&self, value: bool) {
268 *self.enable_tracking_prevention.get() = value;
269 }
270
271 pub unsafe fn are_browser_extensions_enabled(&self) -> bool {
279 *self.are_browser_extensions_enabled.get()
280 }
281
282 pub unsafe fn set_are_browser_extensions_enabled(&self, value: bool) {
290 *self.are_browser_extensions_enabled.get() = value;
291 }
292
293 pub unsafe fn channel_search_kind(&self) -> COREWEBVIEW2_CHANNEL_SEARCH_KIND {
301 *self.channel_search_kind.get()
302 }
303
304 pub unsafe fn set_channel_search_kind(&self, value: COREWEBVIEW2_CHANNEL_SEARCH_KIND) {
313 *self.channel_search_kind.get() = value;
314 }
315
316 pub unsafe fn release_channels(&self) -> COREWEBVIEW2_RELEASE_CHANNELS {
324 *self.release_channels.get()
325 }
326
327 pub unsafe fn set_release_channels(&self, value: COREWEBVIEW2_RELEASE_CHANNELS) {
336 *self.release_channels.get() = value;
337 }
338
339 pub unsafe fn scroll_bar_style(&self) -> COREWEBVIEW2_SCROLLBAR_STYLE {
347 *self.scroll_bar_style.get()
348 }
349
350 pub unsafe fn set_scroll_bar_style(&self, value: COREWEBVIEW2_SCROLLBAR_STYLE) {
359 *self.scroll_bar_style.get() = value;
360 }
361}
362
363#[allow(clippy::not_unsafe_ptr_arg_deref)]
364impl ICoreWebView2EnvironmentOptions_Impl for CoreWebView2EnvironmentOptions_Impl {
365 fn AdditionalBrowserArguments(&self, result: *mut PWSTR) -> Result<()> {
366 if result.is_null() {
367 E_POINTER.ok()
368 } else {
369 unsafe { *result = pwstr_from_str(self.additional_browser_arguments()) };
370 Ok(())
371 }
372 }
373
374 fn SetAdditionalBrowserArguments(&self, value: &PCWSTR) -> Result<()> {
375 unsafe { self.set_additional_browser_arguments(string_from_pcwstr(value)) };
376 Ok(())
377 }
378
379 fn Language(&self, result: *mut PWSTR) -> Result<()> {
380 if result.is_null() {
381 E_POINTER.ok()
382 } else {
383 unsafe { *result = pwstr_from_str(self.language()) };
384 Ok(())
385 }
386 }
387
388 fn SetLanguage(&self, value: &PCWSTR) -> Result<()> {
389 unsafe { self.set_language(string_from_pcwstr(value)) };
390 Ok(())
391 }
392
393 fn TargetCompatibleBrowserVersion(&self, result: *mut PWSTR) -> Result<()> {
394 if result.is_null() {
395 E_POINTER.ok()
396 } else {
397 unsafe { *result = pwstr_from_str(self.target_compatible_browser_version()) };
398 Ok(())
399 }
400 }
401
402 fn SetTargetCompatibleBrowserVersion(&self, value: &PCWSTR) -> Result<()> {
403 unsafe { self.set_target_compatible_browser_version(string_from_pcwstr(value)) };
404 Ok(())
405 }
406
407 fn AllowSingleSignOnUsingOSPrimaryAccount(&self, result: *mut BOOL) -> Result<()> {
408 if result.is_null() {
409 E_POINTER.ok()
410 } else {
411 unsafe { *result = self.allow_single_sign_on_using_os_primary_account().into() };
412 Ok(())
413 }
414 }
415
416 fn SetAllowSingleSignOnUsingOSPrimaryAccount(&self, value: BOOL) -> Result<()> {
417 unsafe {
418 self.set_allow_single_sign_on_using_os_primary_account(value.into());
419 }
420 Ok(())
421 }
422}
423
424#[allow(clippy::not_unsafe_ptr_arg_deref)]
425impl ICoreWebView2EnvironmentOptions2_Impl for CoreWebView2EnvironmentOptions_Impl {
426 fn ExclusiveUserDataFolderAccess(&self, result: *mut BOOL) -> Result<()> {
427 if result.is_null() {
428 E_POINTER.ok()
429 } else {
430 unsafe { *result = self.exclusive_user_data_folder_access().into() };
431 Ok(())
432 }
433 }
434
435 fn SetExclusiveUserDataFolderAccess(&self, value: BOOL) -> Result<()> {
436 unsafe {
437 self.set_exclusive_user_data_folder_access(value.into());
438 }
439 Ok(())
440 }
441}
442
443#[allow(clippy::not_unsafe_ptr_arg_deref)]
444impl ICoreWebView2EnvironmentOptions3_Impl for CoreWebView2EnvironmentOptions_Impl {
445 fn IsCustomCrashReportingEnabled(&self, result: *mut BOOL) -> Result<()> {
446 if result.is_null() {
447 E_POINTER.ok()
448 } else {
449 unsafe { *result = self.is_custom_crash_reporting_enabled().into() };
450 Ok(())
451 }
452 }
453
454 fn SetIsCustomCrashReportingEnabled(&self, value: BOOL) -> Result<()> {
455 unsafe {
456 self.set_is_custom_crash_reporting_enabled(value.into());
457 }
458 Ok(())
459 }
460}
461
462#[interface("AC52D13F-0D38-475A-9DCA-876580D6793E")]
467pub unsafe trait IFixedEnvironmentOptions4: IUnknown {
468 fn GetCustomSchemeRegistrations(
469 &self,
470 count: *mut u32,
471 scheme_registrations: *mut *mut *mut c_void,
472 ) -> HRESULT;
473
474 fn SetCustomSchemeRegistrations(
475 &self,
476 count: u32,
477 scheme_registrations: *const *mut c_void,
478 ) -> HRESULT;
479}
480
481#[allow(clippy::not_unsafe_ptr_arg_deref)]
482impl IFixedEnvironmentOptions4_Impl for CoreWebView2EnvironmentOptions_Impl {
483 #[allow(clippy::crosspointer_transmute)]
484 unsafe fn GetCustomSchemeRegistrations(
485 &self,
486 count: *mut u32,
487 results: *mut *mut *mut c_void,
488 ) -> HRESULT {
489 if count.is_null() || results.is_null() {
490 E_POINTER
491 } else {
492 let scheme_registrations = &*self.scheme_registrations.get();
493 if let Ok(length) = scheme_registrations.len().try_into() {
494 *count = length;
495 if !scheme_registrations.is_empty() {
496 *results = CoTaskMemAlloc(
497 mem::size_of::<*mut c_void>() * (*scheme_registrations).len(),
498 ) as *mut *mut _;
499 let results =
500 ptr::slice_from_raw_parts_mut(*results, scheme_registrations.len());
501 for (i, scheme) in scheme_registrations.iter().enumerate() {
502 (*results)[i] = scheme
503 .clone()
504 .map_or(ptr::null_mut(), |scheme| scheme.into_raw())
505 }
506 } else {
507 *results = ptr::null_mut();
508 }
509 S_OK
510 } else {
511 E_UNEXPECTED
512 }
513 }
514 }
515
516 unsafe fn SetCustomSchemeRegistrations(
517 &self,
518 count: u32,
519 values: *const *mut c_void,
520 ) -> HRESULT {
521 if let Ok(count) = count.try_into() {
522 let scheme_registrations = &mut *self.scheme_registrations.get();
523 scheme_registrations.clear();
524 scheme_registrations.reserve_exact(count);
525 let values = &*ptr::slice_from_raw_parts(values, count);
526 for &scheme in values.iter() {
527 scheme_registrations.push(
528 ICoreWebView2CustomSchemeRegistration::from_raw_borrowed(&scheme).cloned(),
529 );
530 }
531 S_OK
532 } else {
533 E_UNEXPECTED
534 }
535 }
536}
537
538impl ICoreWebView2EnvironmentOptions5_Impl for CoreWebView2EnvironmentOptions_Impl {
539 #[allow(clippy::not_unsafe_ptr_arg_deref)]
540 fn EnableTrackingPrevention(&self, value: *mut BOOL) -> windows_core::Result<()> {
541 unsafe {
542 let value = value.as_mut().ok_or(Error::from(E_POINTER))?;
543 *value = self.enable_tracking_prevention().into()
544 };
545 Ok(())
546 }
547
548 fn SetEnableTrackingPrevention(&self, value: BOOL) -> windows_core::Result<()> {
549 unsafe {
550 self.set_enable_tracking_prevention(value.into());
551 }
552 Ok(())
553 }
554}
555
556impl ICoreWebView2EnvironmentOptions6_Impl for CoreWebView2EnvironmentOptions_Impl {
557 #[allow(clippy::not_unsafe_ptr_arg_deref)]
558 fn AreBrowserExtensionsEnabled(&self, value: *mut BOOL) -> windows_core::Result<()> {
559 unsafe {
560 let value = value.as_mut().ok_or(Error::from(E_POINTER))?;
561 *value = self.are_browser_extensions_enabled().into()
562 };
563 Ok(())
564 }
565
566 fn SetAreBrowserExtensionsEnabled(&self, value: BOOL) -> windows_core::Result<()> {
567 unsafe {
568 self.set_are_browser_extensions_enabled(value.into());
569 }
570 Ok(())
571 }
572}
573
574impl ICoreWebView2EnvironmentOptions7_Impl for CoreWebView2EnvironmentOptions_Impl {
575 #[allow(clippy::not_unsafe_ptr_arg_deref)]
576 fn ChannelSearchKind(
577 &self,
578 value: *mut COREWEBVIEW2_CHANNEL_SEARCH_KIND,
579 ) -> windows_core::Result<()> {
580 unsafe {
581 let value = value.as_mut().ok_or(Error::from(E_POINTER))?;
582 *value = self.channel_search_kind()
583 };
584 Ok(())
585 }
586
587 fn SetChannelSearchKind(
588 &self,
589 value: COREWEBVIEW2_CHANNEL_SEARCH_KIND,
590 ) -> windows_core::Result<()> {
591 unsafe {
592 self.set_channel_search_kind(value);
593 }
594 Ok(())
595 }
596
597 #[allow(clippy::not_unsafe_ptr_arg_deref)]
598 fn ReleaseChannels(
599 &self,
600 value: *mut COREWEBVIEW2_RELEASE_CHANNELS,
601 ) -> windows_core::Result<()> {
602 unsafe {
603 let value = value.as_mut().ok_or(Error::from(E_POINTER))?;
604 *value = self.release_channels()
605 };
606 Ok(())
607 }
608
609 fn SetReleaseChannels(&self, value: COREWEBVIEW2_RELEASE_CHANNELS) -> windows_core::Result<()> {
610 unsafe {
611 self.set_release_channels(value);
612 }
613 Ok(())
614 }
615}
616
617impl ICoreWebView2EnvironmentOptions8_Impl for CoreWebView2EnvironmentOptions_Impl {
618 #[allow(clippy::not_unsafe_ptr_arg_deref)]
619 fn ScrollBarStyle(&self, value: *mut COREWEBVIEW2_SCROLLBAR_STYLE) -> windows_core::Result<()> {
620 unsafe {
621 let value = value.as_mut().ok_or(Error::from(E_POINTER))?;
622 *value = self.scroll_bar_style()
623 };
624 Ok(())
625 }
626
627 fn SetScrollBarStyle(&self, value: COREWEBVIEW2_SCROLLBAR_STYLE) -> windows_core::Result<()> {
628 unsafe {
629 self.set_scroll_bar_style(value);
630 }
631 Ok(())
632 }
633}
634
635#[implement(ICoreWebView2CustomSchemeRegistration)]
636pub struct CoreWebView2CustomSchemeRegistration {
637 scheme_name: String,
638 treat_as_secure: UnsafeCell<bool>,
639 allowed_origins: UnsafeCell<Vec<String>>,
640 has_authority_component: UnsafeCell<bool>,
641}
642
643impl CoreWebView2CustomSchemeRegistration {
644 pub fn new(scheme_name: String) -> Self {
645 Self {
646 scheme_name,
647 treat_as_secure: false.into(),
648 allowed_origins: Vec::new().into(),
649 has_authority_component: false.into(),
650 }
651 }
652
653 pub fn scheme_name(&self) -> &str {
656 self.scheme_name.as_str()
657 }
658
659 pub unsafe fn treat_as_secure(&self) -> bool {
667 *self.treat_as_secure.get()
668 }
669
670 pub unsafe fn set_treat_as_secure(&self, value: bool) {
678 *self.treat_as_secure.get() = value;
679 }
680
681 pub unsafe fn allowed_origins(&self) -> Vec<String> {
689 (*self.allowed_origins.get()).clone()
690 }
691
692 pub unsafe fn set_allowed_origins(&self, value: Vec<String>) {
701 *self.allowed_origins.get() = value;
702 }
703
704 pub unsafe fn has_authority_component(&self) -> bool {
712 *self.has_authority_component.get()
713 }
714
715 pub unsafe fn set_has_authority_component(&self, value: bool) {
723 *self.has_authority_component.get() = value;
724 }
725}
726
727#[allow(clippy::not_unsafe_ptr_arg_deref)]
728impl ICoreWebView2CustomSchemeRegistration_Impl for CoreWebView2CustomSchemeRegistration_Impl {
729 fn SchemeName(&self, result: *mut PWSTR) -> Result<()> {
730 if result.is_null() {
731 E_POINTER.ok()
732 } else {
733 unsafe { *result = pwstr_from_str(&self.scheme_name) };
734 Ok(())
735 }
736 }
737
738 fn TreatAsSecure(&self, result: *mut BOOL) -> Result<()> {
739 if result.is_null() {
740 E_POINTER.ok()
741 } else {
742 unsafe { *result = self.treat_as_secure().into() };
743 Ok(())
744 }
745 }
746
747 fn SetTreatAsSecure(&self, value: BOOL) -> Result<()> {
748 unsafe {
749 self.set_treat_as_secure(value.into());
750 }
751 Ok(())
752 }
753
754 fn GetAllowedOrigins(&self, count: *mut u32, results: *mut *mut PWSTR) -> Result<()> {
755 unsafe {
756 let allowed_origins = &*self.allowed_origins.get();
757 *count = allowed_origins
758 .len()
759 .try_into()
760 .map_err(|_| Error::from(E_UNEXPECTED))?;
761 if !allowed_origins.is_empty() {
762 *results = CoTaskMemAlloc(mem::size_of::<*mut PWSTR>() * (*allowed_origins).len())
763 as *mut _;
764 let results = ptr::slice_from_raw_parts_mut(*results, allowed_origins.len());
765 for (i, scheme) in allowed_origins.iter().enumerate() {
766 (*results)[i] = pwstr_from_str(scheme);
767 }
768 } else {
769 *results = ptr::null_mut();
770 }
771 }
772 Ok(())
773 }
774
775 fn SetAllowedOrigins(&self, count: u32, values: *const PCWSTR) -> Result<()> {
776 unsafe {
777 let count = count.try_into().map_err(|_| Error::from(E_UNEXPECTED))?;
778 let allowed_origins = &mut *self.allowed_origins.get();
779 allowed_origins.clear();
780 allowed_origins.reserve_exact(count);
781 let values = &*ptr::slice_from_raw_parts(values, count);
782 for origin in values.iter() {
783 allowed_origins.push(string_from_pcwstr(origin));
784 }
785 }
786 Ok(())
787 }
788
789 fn HasAuthorityComponent(&self, result: *mut BOOL) -> Result<()> {
790 if result.is_null() {
791 E_POINTER.ok()
792 } else {
793 unsafe { *result = self.has_authority_component().into() };
794 Ok(())
795 }
796 }
797
798 fn SetHasAuthorityComponent(&self, value: BOOL) -> Result<()> {
799 unsafe {
800 self.set_has_authority_component(value.into());
801 }
802 Ok(())
803 }
804}
805
806#[cfg(test)]
807mod test {
808 use std::{collections::BTreeSet, ptr};
809
810 use regex::Regex;
811 use windows::Win32::System::Com::CoTaskMemFree;
812 use windows_core::w;
813
814 use webview2_com_sys::declared_interfaces;
815
816 use crate::{
817 pwstr::take_pwstr,
818 Microsoft::Web::WebView2::Win32::{
819 ICoreWebView2EnvironmentOptions, CORE_WEBVIEW_TARGET_PRODUCT_VERSION,
820 },
821 };
822
823 use super::*;
824
825 #[test]
826 fn all_implemented() {
827 let contents = include_str!("options.rs");
828 let pattern =
829 Regex::new(r#"(ICoreWebView2EnvironmentOptions[0-9]*)"#).expect("valid regex");
830 let implemented: BTreeSet<&str> = contents
831 .lines()
832 .filter_map(|line| pattern.captures(line))
833 .filter_map(|captures| captures.get(1))
834 .map(|match_1| match_1.as_str())
835 .collect();
836 let all_declared_options = declared_interfaces::all_declared_options();
837 let missing: Vec<_> = all_declared_options
838 .iter()
839 .filter_map(|name| {
840 if implemented.contains(name) {
841 None
842 } else {
843 Some(name.to_string())
844 }
845 })
846 .collect();
847 let extra: Vec<_> = implemented
848 .iter()
849 .filter_map(|name| {
850 if all_declared_options.contains(name) {
851 None
852 } else {
853 Some(name.to_string())
854 }
855 })
856 .collect();
857 assert!(
858 missing.is_empty() && extra.is_empty(),
859 "missing: {missing:?}\nextra: {extra:?}"
860 );
861 }
862
863 #[test]
864 fn additional_arguments() {
865 let options: ICoreWebView2EnvironmentOptions =
866 CoreWebView2EnvironmentOptions::default().into();
867 unsafe { options.SetAdditionalBrowserArguments(w!("FakeArguments")) }.unwrap();
868 let mut result = PWSTR(ptr::null_mut());
869 unsafe { options.AdditionalBrowserArguments(&mut result) }.unwrap();
870 let result = take_pwstr(result);
871 assert_eq!(&result, "FakeArguments");
872 }
873
874 #[test]
875 fn override_language() {
876 let options: ICoreWebView2EnvironmentOptions =
877 CoreWebView2EnvironmentOptions::default().into();
878 unsafe { options.SetLanguage(w!("FakeLanguage")) }.unwrap();
879 let mut result = PWSTR(ptr::null_mut::<u16>());
880 unsafe { options.Language(&mut result) }.unwrap();
881 let result = take_pwstr(result);
882 assert_eq!(&result, "FakeLanguage");
883 }
884
885 #[test]
886 fn default_version() {
887 let options: ICoreWebView2EnvironmentOptions =
888 CoreWebView2EnvironmentOptions::default().into();
889 let mut result = PWSTR(ptr::null_mut::<u16>());
890 unsafe { options.TargetCompatibleBrowserVersion(&mut result) }.unwrap();
891 let result = take_pwstr(result);
892 assert_eq!(
893 result,
894 unsafe { CORE_WEBVIEW_TARGET_PRODUCT_VERSION.to_string() }.unwrap()
895 );
896 }
897
898 #[test]
899 fn override_version() {
900 assert_ne!(
901 "FakeVersion",
902 unsafe { CORE_WEBVIEW_TARGET_PRODUCT_VERSION.to_string() }
903 .unwrap()
904 .as_str()
905 );
906 let options: ICoreWebView2EnvironmentOptions =
907 CoreWebView2EnvironmentOptions::default().into();
908 unsafe { options.SetTargetCompatibleBrowserVersion(w!("FakeVersion")) }.unwrap();
909 let mut result = PWSTR(ptr::null_mut::<u16>());
910 unsafe { options.TargetCompatibleBrowserVersion(&mut result) }.unwrap();
911 let result = take_pwstr(result);
912 assert_eq!(&result, "FakeVersion");
913 }
914
915 #[test]
916 fn default_allow_sso() {
917 let options: ICoreWebView2EnvironmentOptions =
918 CoreWebView2EnvironmentOptions::default().into();
919 let mut result = BOOL(1);
920 unsafe { options.AllowSingleSignOnUsingOSPrimaryAccount(&mut result) }.unwrap();
921 assert_eq!(result.0, 0);
922 }
923
924 #[test]
925 fn override_allow_sso() {
926 let options: ICoreWebView2EnvironmentOptions =
927 CoreWebView2EnvironmentOptions::default().into();
928 unsafe { options.SetAllowSingleSignOnUsingOSPrimaryAccount(true) }.unwrap();
929 let mut result = BOOL(0);
930 unsafe { options.AllowSingleSignOnUsingOSPrimaryAccount(&mut result) }.unwrap();
931 assert_eq!(result.0, 1);
932 }
933
934 #[test]
935 fn default_exclusive_data_folder() {
936 let options: ICoreWebView2EnvironmentOptions2 =
937 CoreWebView2EnvironmentOptions::default().into();
938 let mut result = BOOL(1);
939 unsafe { options.ExclusiveUserDataFolderAccess(&mut result) }.unwrap();
940 assert_eq!(result.0, 0);
941 }
942
943 #[test]
944 fn override_exclusive_data_folder() {
945 let options: ICoreWebView2EnvironmentOptions2 =
946 CoreWebView2EnvironmentOptions::default().into();
947 unsafe { options.SetExclusiveUserDataFolderAccess(true) }.unwrap();
948 let mut result = BOOL(0);
949 unsafe { options.ExclusiveUserDataFolderAccess(&mut result) }.unwrap();
950 assert_eq!(result.0, 1);
951 }
952
953 #[test]
954 fn default_custom_crash_reporting() {
955 let options: ICoreWebView2EnvironmentOptions3 =
956 CoreWebView2EnvironmentOptions::default().into();
957 let mut result = BOOL(1);
958 unsafe { options.IsCustomCrashReportingEnabled(&mut result) }.unwrap();
959 assert_eq!(result.0, 0);
960 }
961
962 #[test]
963 fn override_custom_crash_reporting() {
964 let options: ICoreWebView2EnvironmentOptions3 =
965 CoreWebView2EnvironmentOptions::default().into();
966 unsafe { options.SetIsCustomCrashReportingEnabled(true) }.unwrap();
967 let mut result = BOOL(0);
968 unsafe { options.IsCustomCrashReportingEnabled(&mut result) }.unwrap();
969 assert_eq!(result.0, 1);
970 }
971
972 #[test]
973 fn default_scheme_registrations() {
974 let options: IFixedEnvironmentOptions4 = CoreWebView2EnvironmentOptions::default().into();
975 let mut count = 1;
976 let mut scheme_registrations = ptr::null_mut();
977 assert!(unsafe {
978 options.GetCustomSchemeRegistrations(&mut count, &mut scheme_registrations)
979 }
980 .is_ok());
981 assert_eq!(0, count);
982 assert_eq!(ptr::null_mut(), scheme_registrations);
983 }
984
985 #[test]
986 fn override_scheme_registrations() {
987 let options: IFixedEnvironmentOptions4 = CoreWebView2EnvironmentOptions::default().into();
988 let scheme: ICoreWebView2CustomSchemeRegistration =
989 CoreWebView2CustomSchemeRegistration::new(String::new()).into();
990 assert!(
991 unsafe { options.SetCustomSchemeRegistrations(1, &[scheme.as_raw()] as *const _) }
992 .is_ok()
993 );
994 let mut count = 0;
995 let mut scheme_registrations = ptr::null_mut();
996 assert!(unsafe {
997 options.GetCustomSchemeRegistrations(&mut count, &mut scheme_registrations)
998 }
999 .is_ok());
1000 assert_eq!(1, count);
1001 unsafe {
1002 let scheme_registration =
1003 ICoreWebView2CustomSchemeRegistration::from_raw(*scheme_registrations);
1004 assert_eq!(scheme.as_raw(), scheme_registration.as_raw());
1005 CoTaskMemFree(Some(scheme_registrations as *const _));
1006 }
1007 }
1008
1009 #[test]
1010 fn scheme_name() {
1011 const SCHEME_NAME: &str = "custom";
1012 let scheme: ICoreWebView2CustomSchemeRegistration =
1013 CoreWebView2CustomSchemeRegistration::new(SCHEME_NAME.to_string()).into();
1014 let mut result = PWSTR(ptr::null_mut::<u16>());
1015 unsafe { scheme.SchemeName(&mut result) }.unwrap();
1016 let result = take_pwstr(result);
1017 assert_eq!(result, SCHEME_NAME);
1018 }
1019
1020 #[test]
1021 fn default_treat_as_secure() {
1022 let scheme: ICoreWebView2CustomSchemeRegistration =
1023 CoreWebView2CustomSchemeRegistration::new(String::new()).into();
1024 let mut result = BOOL(1);
1025 unsafe { scheme.TreatAsSecure(&mut result) }.unwrap();
1026 assert_eq!(result.0, 0);
1027 }
1028
1029 #[test]
1030 fn override_treat_as_secure() {
1031 let scheme: ICoreWebView2CustomSchemeRegistration =
1032 CoreWebView2CustomSchemeRegistration::new(String::new()).into();
1033 unsafe { scheme.SetTreatAsSecure(true) }.unwrap();
1034 let mut result = BOOL(0);
1035 unsafe { scheme.TreatAsSecure(&mut result) }.unwrap();
1036 assert_eq!(result.0, 1);
1037 }
1038
1039 #[test]
1040 fn default_allowed_origins() {
1041 let scheme: ICoreWebView2CustomSchemeRegistration =
1042 CoreWebView2CustomSchemeRegistration::new(String::new()).into();
1043 let mut count = 1_u32;
1044 let mut origin = pwstr_from_str("origin");
1045 let mut results = &mut origin as *mut _;
1046 let _ = take_pwstr(origin);
1047 unsafe { scheme.GetAllowedOrigins(&mut count, &mut results) }.unwrap();
1048 assert_eq!(count, 0);
1049 assert_eq!(results, ptr::null_mut());
1050 }
1051
1052 #[test]
1053 fn override_allowed_origins() {
1054 const ORIGIN: &str = "origin";
1055 let scheme: ICoreWebView2CustomSchemeRegistration =
1056 CoreWebView2CustomSchemeRegistration::new(String::new()).into();
1057 let origin = pwstr_from_str(ORIGIN);
1058 unsafe { scheme.SetAllowedOrigins(1, &PCWSTR(origin.0)) }.unwrap();
1059
1060 let mut count = 0_u32;
1061 let mut results = ptr::null_mut();
1062 unsafe { scheme.GetAllowedOrigins(&mut count, &mut results) }.unwrap();
1063 assert_eq!(count, 1);
1064
1065 assert_ne!(results, ptr::null_mut());
1066 let mut origin = PWSTR(ptr::null_mut());
1067 unsafe { core::ptr::swap(&mut origin, results) };
1068 let origin = take_pwstr(origin);
1069 unsafe { CoTaskMemFree(Some(results as *const _)) };
1070 assert_eq!(origin, ORIGIN);
1071 }
1072
1073 #[test]
1074 fn default_has_authority_component() {
1075 let scheme: ICoreWebView2CustomSchemeRegistration =
1076 CoreWebView2CustomSchemeRegistration::new(String::new()).into();
1077 let mut result = BOOL(1);
1078 unsafe { scheme.HasAuthorityComponent(&mut result) }.unwrap();
1079 assert_eq!(result.0, 0);
1080 }
1081
1082 #[test]
1083 fn override_has_authority_component() {
1084 let scheme: ICoreWebView2CustomSchemeRegistration =
1085 CoreWebView2CustomSchemeRegistration::new(String::new()).into();
1086 unsafe { scheme.SetHasAuthorityComponent(true) }.unwrap();
1087 let mut result = BOOL(0);
1088 unsafe { scheme.HasAuthorityComponent(&mut result) }.unwrap();
1089 assert_eq!(result.0, 1);
1090 }
1091}