返回 DeepSeek-Reasonix
env_create.go
1 //go:build windows && !native_webview2loader
2
3 package webviewloader
4
5 import (
6 "fmt"
7 "os"
8 "path/filepath"
9 "syscall"
10 "unsafe"
11
12 "github.com/wailsapp/go-webview2/pkg/combridge"
13 "golang.org/x/sys/windows"
14 )
15
16 func init() {
17 UsingGoWebview2Loader = true
18 preventEnvAndRegistryOverrides()
19 }
20
21 type webView2RunTimeType int32
22
23 const (
24 webView2RunTimeTypeInstalled webView2RunTimeType = 0x00
25 webView2RunTimeTypeRedistributable webView2RunTimeType = 0x01
26 )
27
28 // CreateCoreWebView2Environment creates an evergreen WebView2 Environment using the installed WebView2 Runtime version.
29 //
30 // This is equivalent to running CreateCoreWebView2EnvironmentWithOptions without any options.
31 // For more information, see CreateCoreWebView2EnvironmentWithOptions.
32 func CreateCoreWebView2Environment(environmentCompletedHandler ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler) error {
33 return CreateCoreWebView2EnvironmentWithOptions(environmentCompletedHandler)
34 }
35
36 // CreateCoreWebView2EnvironmentWithOptions creates an environment with a custom version of WebView2 Runtime,
37 // user data folder, and with or without additional options.
38 //
39 // See https://docs.microsoft.com/en-us/microsoft-edge/webview2/reference/win32/webview2-idl?#createcorewebview2environmentwithoptions
40 func CreateCoreWebView2EnvironmentWithOptions(environmentCompletedHandler ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler, opts ...option) error {
41 var params environmentOptions
42 for _, opt := range opts {
43 opt(&params)
44 }
45
46 var err error
47 var dllPath string
48 var runtimeType webView2RunTimeType
49 if browserExecutableFolder := params.browserExecutableFolder; browserExecutableFolder != "" {
50 runtimeType = webView2RunTimeTypeRedistributable
51 dllPath, err = findEmbeddedClientDll(browserExecutableFolder)
52 } else {
53 runtimeType = webView2RunTimeTypeInstalled
54 dllPath, _, err = findInstalledClientDll(params.preferCanary)
55 }
56
57 if err != nil {
58 return err
59 }
60
61 return createWebViewEnvironmentWithClientDll(dllPath, runtimeType, params.userDataFolder,
62 &params, environmentCompletedHandler)
63 }
64
65 func createWebViewEnvironmentWithClientDll(lpLibFileName string, runtimeType webView2RunTimeType, userDataFolder string,
66 envOptions *environmentOptions, envCompletedHandler ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler) error {
67
68 if !filepath.IsAbs(lpLibFileName) {
69 return fmt.Errorf("lpLibFileName must be absolute")
70 }
71
72 dll, err := windows.LoadDLL(lpLibFileName)
73 if err != nil {
74 return fmt.Errorf("Loading DLL failed: %w", err)
75 }
76
77 defer func() {
78 canUnloadProc, err := dll.FindProc("DllCanUnloadNow")
79 if err != nil {
80 return
81 }
82
83 if r1, _, _ := canUnloadProc.Call(); r1 != windows.NO_ERROR {
84 return
85 }
86
87 dll.Release()
88 }()
89
90 createProc, err := dll.FindProc("CreateWebViewEnvironmentWithOptionsInternal")
91 if err != nil {
92 return fmt.Errorf("Unable to find CreateWebViewEnvironmentWithOptionsInternal entrypoint: %w", err)
93 }
94
95 userDataPtr, err := windows.UTF16PtrFromString(userDataFolder)
96 if err != nil {
97 return err
98 }
99
100 envOptionsCom := combridge.New2[iCoreWebView2EnvironmentOptions, iCoreWebView2EnvironmentOptions2](
101 envOptions, envOptions)
102
103 defer envOptionsCom.Close()
104
105 envCompletedHandler = &environmentCreatedHandler{envCompletedHandler}
106 envCompletedCom := combridge.New[iCoreWebView2CreateCoreWebView2EnvironmentCompletedHandler](envCompletedHandler)
107 defer envCompletedCom.Close()
108
109 preventEnvAndRegistryOverrides()
110
111 const unknown = 1
112 hr, _, err := createProc.Call(
113 uintptr(unknown),
114 uintptr(runtimeType),
115 uintptr(unsafe.Pointer(userDataPtr)),
116 uintptr(envOptionsCom.Ref()),
117 uintptr(envCompletedCom.Ref()))
118
119 if hr != 0 {
120 if err == nil || err == windows.ERROR_SUCCESS {
121 err = syscall.Errno(hr)
122 }
123 return err
124 }
125
126 return nil
127 }
128
129 type environmentCreatedHandler struct {
130 originalHandler ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler
131 }
132
133 func (r *environmentCreatedHandler) EnvironmentCompleted(errorCode HRESULT, createdEnvironment *ICoreWebView2Environment) HRESULT {
134 // The OpenWebview2Loader has some retry logic and retries once, didn't encounter any case when this would have been
135 // needed during the development: https://github.com/jchv/OpenWebView2Loader/blob/master/Source/WebView2Loader.cpp#L202
136
137 if createdEnvironment != nil {
138 // May or may not be necessary, but the official WebView2Loader seems to do it.
139 iidICoreWebView2Environment := windows.GUID{
140 Data1: 0xb96d755e,
141 Data2: 0x0319,
142 Data3: 0x4e92,
143 Data4: [8]byte{0xa2, 0x96, 0x23, 0x43, 0x6f, 0x46, 0xa1, 0xfc},
144 }
145
146 if err := createdEnvironment.QueryInterface(&iidICoreWebView2Environment, &createdEnvironment); err != nil {
147 createdEnvironment = nil
148 errNo, ok := err.(syscall.Errno)
149 if !ok {
150 errNo = syscall.Errno(windows.E_FAIL)
151 }
152 errorCode = HRESULT(errNo)
153 }
154 }
155
156 r.originalHandler.EnvironmentCompleted(errorCode, createdEnvironment)
157
158 if createdEnvironment != nil {
159 createdEnvironment.Release()
160 }
161
162 return HRESULT(windows.S_OK)
163 }
164
165 func preventEnvAndRegistryOverrides() {
166 // Setting these env variables to empty string also prevents registry overrides because webview2
167 // checks for existence and not for empty value
168 os.Setenv("WEBVIEW2_PIPE_FOR_SCRIPT_DEBUGGER", "")
169 os.Setenv("WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS", "")
170 os.Setenv("WEBVIEW2_RELEASE_CHANNEL_PREFERENCE", "0")
171
172 // The following seems not be be required because those are only used by the webview2loader which
173 // in this case is implemented on our own. But nevertheless set them to empty to be consistent.
174 os.Setenv("WEBVIEW2_BROWSER_EXECUTABLE_FOLDER", "")
175 os.Setenv("WEBVIEW2_USER_DATA_FOLDER", "")
176 }
177
177 lines GO