1#![allow(non_snake_case, clippy::missing_safety_doc)]
6
7use windows::Win32::{
8 Foundation::{E_INVALIDARG, E_POINTER},
9 System::Com::CoTaskMemAlloc,
10};
11use windows_core::{Error, HSTRING, PCWSTR, PWSTR, Param, Result};
12
13use crate::*;
14
15mod load;
16mod r#override;
17
18#[inline]
19pub unsafe fn CreateCoreWebView2Environment<P0>(handler: P0) -> Result<()>
20where
21 P0: Param<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>,
22{
23 unsafe { CreateCoreWebView2EnvironmentWithOptions(None, None, None, handler) }
24}
25
26#[inline]
27pub unsafe fn CreateCoreWebView2EnvironmentWithOptions<P0, P1, P2, P3>(
28 browser_executable_folder: P0,
29 user_data_folder: P1,
30 options: P2,
31 handler: P3,
32) -> Result<()>
33where
34 P0: Param<PCWSTR>,
35 P1: Param<PCWSTR>,
36 P2: Param<ICoreWebView2EnvironmentOptions>,
37 P3: Param<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>,
38{
39 unsafe {
40 let handler = handler.param();
41 let handler = handler.borrow();
42 let handler = handler.ok()?;
43
44 let options = options.param();
45 let options = options.borrow();
46 let mut params = WebView2EnvironmentParams {
47 embedded_edge_sub_folder: browser_executable_folder.param().abi().into(),
48 user_data_dir: user_data_folder.param().abi().into(),
49 environment_options: options.as_ref(),
50 release_channel_preference: WebView2ReleaseChannelPreference::Stable,
51 };
52 r#override::update(&mut params);
53 load::create_env_impl(params, handler)
54 }
55}
56
57struct WebView2EnvironmentParams<'a> {
58 embedded_edge_sub_folder: CowPCWSTR,
59 user_data_dir: CowPCWSTR,
60 environment_options: Option<&'a ICoreWebView2EnvironmentOptions>,
61 release_channel_preference: WebView2ReleaseChannelPreference,
62}
63
64enum CowPCWSTR {
65 Pointer(PCWSTR),
66 Owned(HSTRING),
67}
68
69impl CowPCWSTR {
70 pub fn as_ptr(&self) -> PCWSTR {
71 match self {
72 CowPCWSTR::Pointer(ptr) => *ptr,
73 CowPCWSTR::Owned(s) => PCWSTR(s.as_ptr()),
74 }
75 }
76}
77
78impl From<PCWSTR> for CowPCWSTR {
79 fn from(value: PCWSTR) -> Self {
80 Self::Pointer(value)
81 }
82}
83
84impl From<HSTRING> for CowPCWSTR {
85 fn from(value: HSTRING) -> Self {
86 Self::Owned(value)
87 }
88}
89
90#[derive(Clone, Copy, PartialEq, Eq)]
91enum WebView2ReleaseChannelPreference {
92 Stable = 0,
93 Canary = 1,
94}
95
96#[inline]
97pub unsafe fn GetAvailableCoreWebView2BrowserVersionString<P0>(
98 browser_executable_folder: P0,
99 version_info: *mut PWSTR,
100) -> Result<()>
101where
102 P0: Param<PCWSTR>,
103{
104 if version_info.is_null() || !version_info.is_aligned() {
105 return Err(Error::from_hresult(E_POINTER));
106 }
107
108 unsafe {
109 let mut params = WebView2EnvironmentParams {
110 embedded_edge_sub_folder: browser_executable_folder.param().abi().into(),
111 user_data_dir: CowPCWSTR::Pointer(PCWSTR::null()),
112 environment_options: None,
113 release_channel_preference: WebView2ReleaseChannelPreference::Stable,
114 };
115 r#override::update(&mut params);
116 let s = load::get_version_string(params)?;
117 let byte_len = s.len() * 2 + 2;
118 let mem = CoTaskMemAlloc(byte_len).cast::<u16>();
119 if !mem.is_null() {
120 mem.copy_from_nonoverlapping(s.as_ptr(), s.len() + 1);
121 }
122 *version_info = PWSTR(mem);
123 Ok(())
124 }
125}
126
127#[inline]
128pub unsafe fn CompareBrowserVersions<P0, P1>(
129 version1: P0,
130 version2: P1,
131 result: *mut i32,
132) -> Result<()>
133where
134 P0: Param<PCWSTR>,
135 P1: Param<PCWSTR>,
136{
137 if result.is_null() || !result.is_aligned() {
138 return Err(Error::from_hresult(E_POINTER));
139 }
140
141 unsafe {
142 let version1 = version1.param().abi();
143 let version2 = version2.param().abi();
144
145 if version1.is_null() || version2.is_null() {
146 return Err(Error::from_hresult(E_INVALIDARG));
147 }
148
149 let v1 = version1.to_string()?;
150 let v1 = load::parse_version(&v1).ok_or_else(|| Error::from_hresult(E_INVALIDARG))?;
151 let v2 = version2.to_string()?;
152 let v2 = load::parse_version(&v2).ok_or_else(|| Error::from_hresult(E_INVALIDARG))?;
153
154 *result = match v1.cmp(&v2) {
155 std::cmp::Ordering::Less => -1,
156 std::cmp::Ordering::Equal => 0,
157 std::cmp::Ordering::Greater => 1,
158 };
159 }
160
161 Ok(())
162}