winrt-Microsoft.Web.WebView2.Interop 4!1.0.4314.35.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/LICENSE +22 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/MANIFEST.in +3 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/PKG-INFO +42 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/README.md +16 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/interop.h +191 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/py.Microsoft.Web.WebView2.Interop.cpp +271 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/pyproject.toml +54 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/requirements.txt +4 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/setup.cfg +4 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/setup.py +123 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/winrt/_winrt_microsoft_web_webview2_interop.pyi +4 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/winrt/microsoft/web/webview2/interop/__init__.py +62 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/winrt/microsoft/web/webview2/interop/py.typed +0 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/winrt_Microsoft.Web.WebView2.Interop.egg-info/PKG-INFO +42 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/winrt_Microsoft.Web.WebView2.Interop.egg-info/SOURCES.txt +16 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/winrt_Microsoft.Web.WebView2.Interop.egg-info/dependency_links.txt +1 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/winrt_Microsoft.Web.WebView2.Interop.egg-info/requires.txt +2 -0
- winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/winrt_Microsoft.Web.WebView2.Interop.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
Copyright (c) 2021-2026 David Lechner <david@pybricks.com>
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: winrt-Microsoft.Web.WebView2.Interop
|
|
3
|
+
Version: 4!1.0.4314.35.1
|
|
4
|
+
Summary: Lets a visually hosted WebView2 take the files dropped on its window, as an OLE drop target.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Documentation, https://pywinrt.readthedocs.io
|
|
7
|
+
Project-URL: Repository, https://github.com/pywinrt/pywinrt
|
|
8
|
+
Project-URL: Changelog, https://github.com/pywinrt/pywinrt/blob/main/projection/webview2/CHANGELOG.md
|
|
9
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
16
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: winrt-runtime<5,>=4.0.0
|
|
24
|
+
Requires-Dist: winrt-Microsoft.Web.WebView2>=4!1.0.4314.35
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
<!-- warning: Please don't edit this file. It was automatically generated. -->
|
|
28
|
+
|
|
29
|
+
# winrt-Microsoft.Web.WebView2.Interop
|
|
30
|
+
|
|
31
|
+
Lets a visually hosted WebView2 take the files dropped on its window, as an OLE drop target.
|
|
32
|
+
|
|
33
|
+
This package provides the `winrt.microsoft.web.webview2.interop` module.
|
|
34
|
+
|
|
35
|
+
It is built against version 1.0.4314.35 of the `Microsoft.Web.WebView2`
|
|
36
|
+
NuGet package.
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
pip install winrt-Microsoft.Web.WebView2.Interop
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
installs it with `winrt-Microsoft.Web.WebView2`.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<!-- warning: Please don't edit this file. It was automatically generated. -->
|
|
2
|
+
|
|
3
|
+
# winrt-Microsoft.Web.WebView2.Interop
|
|
4
|
+
|
|
5
|
+
Lets a visually hosted WebView2 take the files dropped on its window, as an OLE drop target.
|
|
6
|
+
|
|
7
|
+
This package provides the `winrt.microsoft.web.webview2.interop` module.
|
|
8
|
+
|
|
9
|
+
It is built against version 1.0.4314.35 of the `Microsoft.Web.WebView2`
|
|
10
|
+
NuGet package.
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
pip install winrt-Microsoft.Web.WebView2.Interop
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
installs it with `winrt-Microsoft.Web.WebView2`.
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
// WARNING: Please don't edit this file. It was copied from interop/interop.h
|
|
2
|
+
// by scripts/generate-pyproject.py.
|
|
3
|
+
|
|
4
|
+
// What an interop module needs to exchange WinRT objects and errors with
|
|
5
|
+
// winrt-runtime.
|
|
6
|
+
//
|
|
7
|
+
// An interop module shares no C ABI with the runtime and includes none of its
|
|
8
|
+
// headers. A WinRT object crosses as an interface pointer capsule, which
|
|
9
|
+
// winrt.runtime.interop.as_interface() makes from a projected object and
|
|
10
|
+
// winrt.runtime.interop.wrap_interface() makes a projected object from, and a
|
|
11
|
+
// failed call raises the exception that winrt.runtime.interop.hresult_error()
|
|
12
|
+
// builds. The capsule's name and those three functions are the whole
|
|
13
|
+
// contract, so this header can change freely.
|
|
14
|
+
//
|
|
15
|
+
// scripts/generate-pyproject.py copies this file into each interop package,
|
|
16
|
+
// so that its source distribution builds on its own.
|
|
17
|
+
|
|
18
|
+
#pragma once
|
|
19
|
+
|
|
20
|
+
#include <Python.h>
|
|
21
|
+
|
|
22
|
+
#include <windows.h>
|
|
23
|
+
|
|
24
|
+
#include <oleauto.h>
|
|
25
|
+
|
|
26
|
+
#include <cstddef>
|
|
27
|
+
|
|
28
|
+
// The version of the Python C API a module is compiled against: the stable
|
|
29
|
+
// ABI's where it is built for that, and otherwise that of the Python it is
|
|
30
|
+
// built for. Nothing newer is there to call.
|
|
31
|
+
#ifdef Py_LIMITED_API
|
|
32
|
+
#define INTEROP_PY_API_VERSION Py_LIMITED_API
|
|
33
|
+
#else
|
|
34
|
+
#define INTEROP_PY_API_VERSION PY_VERSION_HEX
|
|
35
|
+
#endif
|
|
36
|
+
|
|
37
|
+
namespace interop
|
|
38
|
+
{
|
|
39
|
+
/// The name every interface pointer capsule carries, in the runtime and in
|
|
40
|
+
/// every interop module alike. One holds a reference to a COM interface,
|
|
41
|
+
/// which its destructor releases.
|
|
42
|
+
inline constexpr char interface_capsule_name[] = "winrt.interface";
|
|
43
|
+
|
|
44
|
+
/// Releases the GIL for as long as it is in scope.
|
|
45
|
+
///
|
|
46
|
+
/// A call into an object in another apartment, or one that sends a window
|
|
47
|
+
/// on another thread a message, waits for that thread, which may itself
|
|
48
|
+
/// be waiting for the GIL to run a Python handler.
|
|
49
|
+
class gil_released
|
|
50
|
+
{
|
|
51
|
+
public:
|
|
52
|
+
gil_released() noexcept : state{PyEval_SaveThread()}
|
|
53
|
+
{
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
gil_released(gil_released const&) = delete;
|
|
57
|
+
gil_released& operator=(gil_released const&) = delete;
|
|
58
|
+
|
|
59
|
+
~gil_released() noexcept
|
|
60
|
+
{
|
|
61
|
+
PyEval_RestoreThread(state);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private:
|
|
65
|
+
PyThreadState* state;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
/// The destructor of an interface pointer capsule this module made, which
|
|
69
|
+
/// may hold the last reference to the object.
|
|
70
|
+
inline void release_interface(PyObject* capsule) noexcept
|
|
71
|
+
{
|
|
72
|
+
auto const abi = PyCapsule_GetPointer(capsule, interface_capsule_name);
|
|
73
|
+
if (!abi)
|
|
74
|
+
{
|
|
75
|
+
PyErr_WriteUnraisable(capsule);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
gil_released const guard;
|
|
80
|
+
static_cast<IUnknown*>(abi)->Release();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/// Hands @p abi, and the reference that comes with it, to a new interface
|
|
84
|
+
/// pointer capsule. The reference is released if that fails.
|
|
85
|
+
inline PyObject* new_interface_capsule(IUnknown* abi) noexcept
|
|
86
|
+
{
|
|
87
|
+
auto const capsule
|
|
88
|
+
= PyCapsule_New(abi, interface_capsule_name, release_interface);
|
|
89
|
+
if (!capsule)
|
|
90
|
+
{
|
|
91
|
+
abi->Release();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return capsule;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/// Raises what winrt.runtime.interop.hresult_error() makes of @p hr and
|
|
98
|
+
/// @p info, the error info of the call that failed with it, which may be
|
|
99
|
+
/// @c nullptr. The reference to @p info moves in.
|
|
100
|
+
/// @returns nullptr, for the caller to return.
|
|
101
|
+
inline PyObject* set_hresult_error(HRESULT hr, IErrorInfo* info) noexcept
|
|
102
|
+
{
|
|
103
|
+
auto const capsule = info ? new_interface_capsule(info) : Py_NewRef(Py_None);
|
|
104
|
+
if (!capsule)
|
|
105
|
+
{
|
|
106
|
+
return nullptr;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
auto const runtime = PyImport_ImportModule("winrt.runtime.interop");
|
|
110
|
+
if (!runtime)
|
|
111
|
+
{
|
|
112
|
+
Py_DECREF(capsule);
|
|
113
|
+
return nullptr;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
auto const error = PyObject_CallMethod(
|
|
117
|
+
runtime, "hresult_error", "lO", static_cast<long>(hr), capsule);
|
|
118
|
+
Py_DECREF(runtime);
|
|
119
|
+
Py_DECREF(capsule);
|
|
120
|
+
if (!error)
|
|
121
|
+
{
|
|
122
|
+
return nullptr;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
PyErr_SetObject(reinterpret_cast<PyObject*>(Py_TYPE(error)), error);
|
|
126
|
+
Py_DECREF(error);
|
|
127
|
+
|
|
128
|
+
return nullptr;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/// Raises what winrt.runtime.interop.hresult_error() makes of @p hr and of
|
|
132
|
+
/// the error info that the call that just failed with it left on this
|
|
133
|
+
/// thread.
|
|
134
|
+
/// @returns nullptr, for the caller to return.
|
|
135
|
+
inline PyObject* set_hresult_error(HRESULT hr) noexcept
|
|
136
|
+
{
|
|
137
|
+
// The error info belongs to the thread and the next failure replaces
|
|
138
|
+
// it, so it is taken before anything else can fail.
|
|
139
|
+
IErrorInfo* info{};
|
|
140
|
+
if (GetErrorInfo(0, &info) != S_OK)
|
|
141
|
+
{
|
|
142
|
+
info = nullptr;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return set_hresult_error(hr, info);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/// The @p I interface of what the interface pointer capsule @p capsule
|
|
149
|
+
/// holds, which the caller owns a reference to.
|
|
150
|
+
/// @returns false with a Python exception set when @p capsule is not one
|
|
151
|
+
/// or what it holds does not implement @p I.
|
|
152
|
+
template<typename I>
|
|
153
|
+
bool query_capsule(PyObject* capsule, I** result) noexcept
|
|
154
|
+
{
|
|
155
|
+
auto const abi = PyCapsule_GetPointer(capsule, interface_capsule_name);
|
|
156
|
+
if (!abi)
|
|
157
|
+
{
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
auto const hr = static_cast<IUnknown*>(abi)->QueryInterface(
|
|
162
|
+
__uuidof(I), reinterpret_cast<void**>(result));
|
|
163
|
+
if (FAILED(hr))
|
|
164
|
+
{
|
|
165
|
+
set_hresult_error(hr);
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return true;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/// The slots of an interop module that has nothing to set up when it is
|
|
173
|
+
/// executed. It keeps no state, but it exchanges objects and errors with
|
|
174
|
+
/// winrt-runtime, which refuses any interpreter but the main one, so it
|
|
175
|
+
/// says the same where it can. The stable ABI of Python 3.11, which its
|
|
176
|
+
/// wheels are built for, has neither slot: there CPython refuses the
|
|
177
|
+
/// module in an interpreter with a GIL of its own anyway, winrt-runtime
|
|
178
|
+
/// refuses the rest, and a free-threaded build, which is what Py_mod_gil
|
|
179
|
+
/// is for, is never a stable ABI one.
|
|
180
|
+
///
|
|
181
|
+
/// Each slot is looked for by its value: from 3.15 the headers name every
|
|
182
|
+
/// slot whatever the API, but give the values only to an API that has it.
|
|
183
|
+
inline PyModuleDef_Slot module_slots[]{
|
|
184
|
+
#ifdef Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED
|
|
185
|
+
{Py_mod_multiple_interpreters, Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED},
|
|
186
|
+
#endif
|
|
187
|
+
#ifdef Py_MOD_GIL_NOT_USED
|
|
188
|
+
{Py_mod_gil, Py_MOD_GIL_NOT_USED},
|
|
189
|
+
#endif
|
|
190
|
+
{}};
|
|
191
|
+
} // namespace interop
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
#include "interop.h"
|
|
2
|
+
|
|
3
|
+
#include <ole2.h>
|
|
4
|
+
|
|
5
|
+
#include <WebView2Interop.h>
|
|
6
|
+
|
|
7
|
+
#include <atomic>
|
|
8
|
+
#include <new>
|
|
9
|
+
|
|
10
|
+
// The WebView2 headers are made by MIDL, whose MIDL_INTERFACE names the IID
|
|
11
|
+
// with __declspec(uuid), which GCC does not have.
|
|
12
|
+
#ifdef __CRT_UUID_DECL
|
|
13
|
+
__CRT_UUID_DECL(
|
|
14
|
+
ICoreWebView2CompositionControllerInterop2,
|
|
15
|
+
// clang-format off
|
|
16
|
+
0x6b47bbe1, 0x2480, 0x4ff8, 0xa5, 0xba, 0x69, 0xc2, 0xf0, 0xb8, 0x68, 0xb3
|
|
17
|
+
// clang-format on
|
|
18
|
+
)
|
|
19
|
+
#endif
|
|
20
|
+
|
|
21
|
+
// https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/interop/
|
|
22
|
+
|
|
23
|
+
namespace
|
|
24
|
+
{
|
|
25
|
+
/// An OLE drop target for a window that shows a visually hosted WebView2.
|
|
26
|
+
/// It hands each call to the WebView's composition controller, with the
|
|
27
|
+
/// point in the window's client coordinates, which is where the WebView
|
|
28
|
+
/// is drawn from.
|
|
29
|
+
///
|
|
30
|
+
/// OLE calls it on the thread that registered it, from that thread's
|
|
31
|
+
/// message loop, and it calls nothing but the controller, so it needs no
|
|
32
|
+
/// GIL.
|
|
33
|
+
class drop_target final : public IDropTarget
|
|
34
|
+
{
|
|
35
|
+
public:
|
|
36
|
+
/// The reference to @p controller moves in.
|
|
37
|
+
drop_target(
|
|
38
|
+
ICoreWebView2CompositionControllerInterop2* controller, HWND hwnd) noexcept
|
|
39
|
+
: controller{controller}, hwnd{hwnd}
|
|
40
|
+
{
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
drop_target(drop_target const&) = delete;
|
|
44
|
+
drop_target& operator=(drop_target const&) = delete;
|
|
45
|
+
|
|
46
|
+
HRESULT STDMETHODCALLTYPE
|
|
47
|
+
QueryInterface(REFIID iid, void** result) noexcept override
|
|
48
|
+
{
|
|
49
|
+
if (!result)
|
|
50
|
+
{
|
|
51
|
+
return E_POINTER;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (iid != __uuidof(IUnknown) && iid != __uuidof(IDropTarget))
|
|
55
|
+
{
|
|
56
|
+
*result = nullptr;
|
|
57
|
+
return E_NOINTERFACE;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
AddRef();
|
|
61
|
+
*result = static_cast<IDropTarget*>(this);
|
|
62
|
+
|
|
63
|
+
return S_OK;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
ULONG STDMETHODCALLTYPE AddRef() noexcept override
|
|
67
|
+
{
|
|
68
|
+
return ++references;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
ULONG STDMETHODCALLTYPE Release() noexcept override
|
|
72
|
+
{
|
|
73
|
+
auto const remaining = --references;
|
|
74
|
+
if (remaining == 0)
|
|
75
|
+
{
|
|
76
|
+
delete this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return remaining;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
HRESULT STDMETHODCALLTYPE DragEnter(
|
|
83
|
+
IDataObject* data_object,
|
|
84
|
+
DWORD key_state,
|
|
85
|
+
POINTL point,
|
|
86
|
+
DWORD* effect) noexcept override
|
|
87
|
+
{
|
|
88
|
+
return controller->DragEnter(
|
|
89
|
+
data_object, key_state, to_client(point), effect);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
HRESULT STDMETHODCALLTYPE
|
|
93
|
+
DragOver(DWORD key_state, POINTL point, DWORD* effect) noexcept override
|
|
94
|
+
{
|
|
95
|
+
return controller->DragOver(key_state, to_client(point), effect);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
HRESULT STDMETHODCALLTYPE DragLeave() noexcept override
|
|
99
|
+
{
|
|
100
|
+
return controller->DragLeave();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
HRESULT STDMETHODCALLTYPE Drop(
|
|
104
|
+
IDataObject* data_object,
|
|
105
|
+
DWORD key_state,
|
|
106
|
+
POINTL point,
|
|
107
|
+
DWORD* effect) noexcept override
|
|
108
|
+
{
|
|
109
|
+
return controller->Drop(data_object, key_state, to_client(point), effect);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private:
|
|
113
|
+
~drop_target()
|
|
114
|
+
{
|
|
115
|
+
controller->Release();
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/// OLE gives the point in screen coordinates.
|
|
119
|
+
POINT to_client(POINTL point) const noexcept
|
|
120
|
+
{
|
|
121
|
+
POINT client{point.x, point.y};
|
|
122
|
+
ScreenToClient(hwnd, &client);
|
|
123
|
+
|
|
124
|
+
return client;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
std::atomic<ULONG> references{1};
|
|
128
|
+
ICoreWebView2CompositionControllerInterop2* const controller;
|
|
129
|
+
HWND const hwnd;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
/// Parses a window handle.
|
|
133
|
+
/// @returns false with a Python exception set when @p obj is not one.
|
|
134
|
+
bool parse_hwnd(PyObject* obj, HWND* hwnd) noexcept
|
|
135
|
+
{
|
|
136
|
+
auto const handle = PyLong_AsVoidPtr(obj);
|
|
137
|
+
if (!handle && PyErr_Occurred())
|
|
138
|
+
{
|
|
139
|
+
return false;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
*hwnd = static_cast<HWND>(handle);
|
|
143
|
+
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/// OLE registers and revokes a window's drop target on the thread that
|
|
148
|
+
/// owns the window, and calls it there.
|
|
149
|
+
/// @returns false with a Python exception set when @p hwnd is not a
|
|
150
|
+
/// window of the calling thread.
|
|
151
|
+
bool check_window_thread(HWND hwnd) noexcept
|
|
152
|
+
{
|
|
153
|
+
if (GetWindowThreadProcessId(hwnd, nullptr) != GetCurrentThreadId())
|
|
154
|
+
{
|
|
155
|
+
PyErr_SetString(PyExc_ValueError, "hwnd is not a window of this thread");
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
PyObject* register_drop_target(PyObject* /*unused*/, PyObject* args) noexcept
|
|
163
|
+
{
|
|
164
|
+
PyObject* controller_capsule;
|
|
165
|
+
PyObject* hwnd_obj;
|
|
166
|
+
|
|
167
|
+
if (!PyArg_ParseTuple(args, "OO", &controller_capsule, &hwnd_obj))
|
|
168
|
+
{
|
|
169
|
+
return nullptr;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
HWND hwnd;
|
|
173
|
+
if (!parse_hwnd(hwnd_obj, &hwnd))
|
|
174
|
+
{
|
|
175
|
+
return nullptr;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (!check_window_thread(hwnd))
|
|
179
|
+
{
|
|
180
|
+
return nullptr;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
ICoreWebView2CompositionControllerInterop2* controller{};
|
|
184
|
+
if (!interop::query_capsule(controller_capsule, &controller))
|
|
185
|
+
{
|
|
186
|
+
return nullptr;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// RegisterDragDrop needs OLE, not only COM, and revoke_drop_target()
|
|
190
|
+
// balances this.
|
|
191
|
+
auto hr = OleInitialize(nullptr);
|
|
192
|
+
if (FAILED(hr))
|
|
193
|
+
{
|
|
194
|
+
controller->Release();
|
|
195
|
+
return interop::set_hresult_error(hr);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
auto const target = new (std::nothrow) drop_target{controller, hwnd};
|
|
199
|
+
if (!target)
|
|
200
|
+
{
|
|
201
|
+
controller->Release();
|
|
202
|
+
OleUninitialize();
|
|
203
|
+
return PyErr_NoMemory();
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// On success, OLE holds a reference of its own until the window's
|
|
207
|
+
// drop target is revoked.
|
|
208
|
+
hr = RegisterDragDrop(hwnd, target);
|
|
209
|
+
target->Release();
|
|
210
|
+
if (FAILED(hr))
|
|
211
|
+
{
|
|
212
|
+
auto const error = interop::set_hresult_error(hr);
|
|
213
|
+
OleUninitialize();
|
|
214
|
+
return error;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
Py_RETURN_NONE;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
PyObject* revoke_drop_target(PyObject* /*unused*/, PyObject* hwnd_obj) noexcept
|
|
221
|
+
{
|
|
222
|
+
HWND hwnd;
|
|
223
|
+
if (!parse_hwnd(hwnd_obj, &hwnd))
|
|
224
|
+
{
|
|
225
|
+
return nullptr;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (!check_window_thread(hwnd))
|
|
229
|
+
{
|
|
230
|
+
return nullptr;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
HRESULT hr;
|
|
234
|
+
{
|
|
235
|
+
// OLE's reference may be the last one to the drop target, which
|
|
236
|
+
// holds the controller.
|
|
237
|
+
interop::gil_released const guard;
|
|
238
|
+
hr = RevokeDragDrop(hwnd);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (FAILED(hr))
|
|
242
|
+
{
|
|
243
|
+
return interop::set_hresult_error(hr);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
OleUninitialize();
|
|
247
|
+
|
|
248
|
+
Py_RETURN_NONE;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
PyMethodDef module_methods[]{
|
|
252
|
+
{"register_drop_target", register_drop_target, METH_VARARGS, nullptr},
|
|
253
|
+
{"revoke_drop_target", revoke_drop_target, METH_O, nullptr},
|
|
254
|
+
{}};
|
|
255
|
+
|
|
256
|
+
PyModuleDef module_def
|
|
257
|
+
= {PyModuleDef_HEAD_INIT,
|
|
258
|
+
"_winrt_microsoft_web_webview2_interop",
|
|
259
|
+
nullptr,
|
|
260
|
+
0,
|
|
261
|
+
module_methods,
|
|
262
|
+
interop::module_slots,
|
|
263
|
+
nullptr,
|
|
264
|
+
nullptr,
|
|
265
|
+
nullptr};
|
|
266
|
+
} // namespace
|
|
267
|
+
|
|
268
|
+
PyMODINIT_FUNC PyInit__winrt_microsoft_web_webview2_interop(void) noexcept
|
|
269
|
+
{
|
|
270
|
+
return PyModuleDef_Init(&module_def);
|
|
271
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# WARNING: Please don't edit this file. It was automatically generated.
|
|
2
|
+
|
|
3
|
+
[build-system]
|
|
4
|
+
requires = ["setuptools>=78"]
|
|
5
|
+
build-backend = "setuptools.build_meta"
|
|
6
|
+
|
|
7
|
+
[project]
|
|
8
|
+
name = "winrt-Microsoft.Web.WebView2.Interop"
|
|
9
|
+
version = "4!1.0.4314.35.1"
|
|
10
|
+
description = "Lets a visually hosted WebView2 take the files dropped on its window, as an OLE drop target."
|
|
11
|
+
readme = "README.md"
|
|
12
|
+
license = "MIT"
|
|
13
|
+
license-files = ["LICENSE"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Operating System :: Microsoft :: Windows",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.11",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Programming Language :: Python :: 3.14",
|
|
21
|
+
"Programming Language :: Python :: 3.15",
|
|
22
|
+
"Programming Language :: Python :: Implementation :: CPython",
|
|
23
|
+
"Intended Audience :: Developers",
|
|
24
|
+
"Programming Language :: Python :: Free Threading :: 2 - Beta",
|
|
25
|
+
"Typing :: Typed",
|
|
26
|
+
]
|
|
27
|
+
dynamic = ["dependencies"]
|
|
28
|
+
requires-python = ">=3.11"
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Documentation = "https://pywinrt.readthedocs.io"
|
|
32
|
+
Repository = "https://github.com/pywinrt/pywinrt"
|
|
33
|
+
Changelog = "https://github.com/pywinrt/pywinrt/blob/main/projection/webview2/CHANGELOG.md"
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.dynamic]
|
|
36
|
+
dependencies = { file = "requirements.txt" }
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.packages.find]
|
|
39
|
+
include = ["winrt*"]
|
|
40
|
+
|
|
41
|
+
[tool.setuptools.package-data]
|
|
42
|
+
"*" = ["*.pyi", "py.typed"]
|
|
43
|
+
|
|
44
|
+
[tool.cibuildwheel]
|
|
45
|
+
# don't build for PyPy
|
|
46
|
+
skip = "pp*"
|
|
47
|
+
# suppress warnings about ARM64 testing
|
|
48
|
+
test-skip = "*-win_arm64"
|
|
49
|
+
test-command = "python -c \"import winrt._winrt_microsoft_web_webview2_interop\""
|
|
50
|
+
|
|
51
|
+
[tool.cibuildwheel.windows]
|
|
52
|
+
archs = ["x86", "AMD64", "ARM64"]
|
|
53
|
+
# nothing here is copied in after the build, so there is no repair step
|
|
54
|
+
repair-wheel-command = ""
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# WARNING: Please don't edit this file. It was automatically generated.
|
|
2
|
+
# setuptools does not annotate the build_ext methods this file overrides.
|
|
3
|
+
# pyright: reportUnknownMemberType=false
|
|
4
|
+
|
|
5
|
+
import hashlib
|
|
6
|
+
import io
|
|
7
|
+
import os
|
|
8
|
+
import pathlib
|
|
9
|
+
import shutil
|
|
10
|
+
import sysconfig
|
|
11
|
+
import urllib.request
|
|
12
|
+
import zipfile
|
|
13
|
+
|
|
14
|
+
from setuptools import Extension, setup
|
|
15
|
+
from setuptools.command.build_ext import build_ext
|
|
16
|
+
|
|
17
|
+
INCLUDE_DIRS: list[str] = []
|
|
18
|
+
|
|
19
|
+
# Each NuGet package the module compiles against, named by the environment
|
|
20
|
+
# variable that points at an unpacked copy of it: what it is unpacked as, where
|
|
21
|
+
# nuget.org serves it, what it has to hash to and where in it the headers are.
|
|
22
|
+
NUGET_PACKAGES = {
|
|
23
|
+
"WEBVIEW2_PATH": (
|
|
24
|
+
"Microsoft.Web.WebView2.1.0.4314.35",
|
|
25
|
+
"https://api.nuget.org/v3-flatcontainer/microsoft.web.webview2/1.0.4314.35/microsoft.web.webview2.1.0.4314.35.nupkg",
|
|
26
|
+
"90778deb1b77e36292828b4b5833c9255c27533f40e0ddd55891ae718944edc4",
|
|
27
|
+
["build/native/include", "build/native/include-winrt"],
|
|
28
|
+
),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def unpack_nuget_package(env: str) -> pathlib.Path:
|
|
33
|
+
"""
|
|
34
|
+
Where the package named by @p env is unpacked: the copy the environment
|
|
35
|
+
variable points at, or else one downloaded from nuget.org into build/.
|
|
36
|
+
"""
|
|
37
|
+
if env in os.environ:
|
|
38
|
+
return pathlib.Path(os.environ[env]).resolve()
|
|
39
|
+
|
|
40
|
+
name, url, sha256, _ = NUGET_PACKAGES[env]
|
|
41
|
+
path = pathlib.Path(__file__).parent.resolve() / "build" / "nuget" / name
|
|
42
|
+
|
|
43
|
+
if path.is_dir():
|
|
44
|
+
return path
|
|
45
|
+
|
|
46
|
+
try:
|
|
47
|
+
with urllib.request.urlopen(url, timeout=120) as response:
|
|
48
|
+
data = response.read()
|
|
49
|
+
except OSError as error:
|
|
50
|
+
raise RuntimeError(
|
|
51
|
+
f"could not download {url}: {error}. Set {env} to an unpacked"
|
|
52
|
+
f" copy of {name} to build without reaching the network."
|
|
53
|
+
) from error
|
|
54
|
+
|
|
55
|
+
digest = hashlib.sha256(data).hexdigest()
|
|
56
|
+
|
|
57
|
+
if digest != sha256:
|
|
58
|
+
raise RuntimeError(f"{url} hashes to {digest} and not to {sha256}")
|
|
59
|
+
|
|
60
|
+
# Unpacked beside where it goes and then moved there, so that a build
|
|
61
|
+
# stopped halfway leaves nothing the next one would take for unpacked.
|
|
62
|
+
partial = path.with_name(path.name + ".partial")
|
|
63
|
+
shutil.rmtree(partial, ignore_errors=True)
|
|
64
|
+
|
|
65
|
+
with zipfile.ZipFile(io.BytesIO(data)) as package:
|
|
66
|
+
package.extractall(partial)
|
|
67
|
+
|
|
68
|
+
partial.rename(path)
|
|
69
|
+
|
|
70
|
+
return path
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
NUGET_PATHS: dict[str, pathlib.Path] = {}
|
|
74
|
+
|
|
75
|
+
for name, (_, _, _, include_dirs) in NUGET_PACKAGES.items():
|
|
76
|
+
NUGET_PATHS[name] = unpack_nuget_package(name)
|
|
77
|
+
print(f"Using {name} from {NUGET_PATHS[name]}")
|
|
78
|
+
INCLUDE_DIRS.extend(os.fspath(NUGET_PATHS[name] / d) for d in include_dirs)
|
|
79
|
+
|
|
80
|
+
# compiled against the stable ABI of Python 3.11, except where the interpreter
|
|
81
|
+
# is free-threaded, which has none, or MSYS2's, whose modules link against the
|
|
82
|
+
# version's own DLL
|
|
83
|
+
STABLE_ABI = not (
|
|
84
|
+
sysconfig.get_config_var("Py_GIL_DISABLED")
|
|
85
|
+
or sysconfig.get_platform().startswith("mingw")
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class build_ext_ex(build_ext):
|
|
90
|
+
def build_extension(self, ext: Extension) -> None:
|
|
91
|
+
# nothing in the projection uses dynamic_cast or typeid, so disabling
|
|
92
|
+
# RTTI costs nothing and makes the module about 15% smaller
|
|
93
|
+
if self.compiler.compiler_type == "msvc":
|
|
94
|
+
ext.extra_compile_args = ["/std:c++20", "/permissive-", "/GR-"]
|
|
95
|
+
elif self.compiler.compiler_type == "mingw32":
|
|
96
|
+
ext.extra_compile_args = [
|
|
97
|
+
"-std=c++20",
|
|
98
|
+
"-fno-rtti",
|
|
99
|
+
"-D_WIN32_WINNT=_WIN32_WINNT_WIN10",
|
|
100
|
+
]
|
|
101
|
+
# GCC 15 complains about some things that it didn't in the past
|
|
102
|
+
ext.extra_compile_args += ["-Wno-strict-aliasing", "-Wno-template-body"]
|
|
103
|
+
ext.extra_link_args = ["-loleaut32"]
|
|
104
|
+
else:
|
|
105
|
+
raise ValueError(f"Unsupported compiler: {self.compiler.compiler_type}")
|
|
106
|
+
|
|
107
|
+
build_ext.build_extension(self, ext)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
setup(
|
|
111
|
+
cmdclass={"build_ext": build_ext_ex},
|
|
112
|
+
ext_modules=[
|
|
113
|
+
Extension(
|
|
114
|
+
"winrt._winrt_microsoft_web_webview2_interop",
|
|
115
|
+
sources=["py.Microsoft.Web.WebView2.Interop.cpp"],
|
|
116
|
+
include_dirs=INCLUDE_DIRS,
|
|
117
|
+
libraries=["windowsapp", "ole32", "user32"],
|
|
118
|
+
define_macros=[("Py_LIMITED_API", "0x030B0000")] if STABLE_ABI else [],
|
|
119
|
+
py_limited_api=STABLE_ABI,
|
|
120
|
+
)
|
|
121
|
+
],
|
|
122
|
+
options={"bdist_wheel": {"py_limited_api": "cp311"}} if STABLE_ABI else {},
|
|
123
|
+
)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import typing as _typing
|
|
2
|
+
|
|
3
|
+
import winrt.runtime.interop as _runtime
|
|
4
|
+
import winrt._winrt_microsoft_web_webview2_interop as _native
|
|
5
|
+
import winrt.microsoft.web.webview2.core as _core
|
|
6
|
+
|
|
7
|
+
__all__ = ["DropTarget", "register_drop_target"]
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@_typing.final
|
|
11
|
+
class DropTarget:
|
|
12
|
+
"""
|
|
13
|
+
A window registered as the OLE drop target of a visually hosted WebView2,
|
|
14
|
+
which register_drop_target() returns.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
__slots__ = ("_hwnd",)
|
|
18
|
+
|
|
19
|
+
_hwnd: int | None
|
|
20
|
+
|
|
21
|
+
def __init__(self) -> None:
|
|
22
|
+
raise TypeError("DropTarget is made by register_drop_target()")
|
|
23
|
+
|
|
24
|
+
def close(self) -> None:
|
|
25
|
+
"""
|
|
26
|
+
Revokes the registration, on the thread that owns the window and before
|
|
27
|
+
the window is destroyed. Calling it again does nothing.
|
|
28
|
+
"""
|
|
29
|
+
if self._hwnd is None:
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
_native.revoke_drop_target(self._hwnd)
|
|
33
|
+
self._hwnd = None
|
|
34
|
+
|
|
35
|
+
def __enter__(self) -> _typing.Self:
|
|
36
|
+
return self
|
|
37
|
+
|
|
38
|
+
def __exit__(self, *args: object) -> None:
|
|
39
|
+
self.close()
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def register_drop_target(
|
|
43
|
+
controller: _core.CoreWebView2CompositionController, hwnd: int, /
|
|
44
|
+
) -> DropTarget:
|
|
45
|
+
"""
|
|
46
|
+
Registers the window hwnd as an OLE drop target that hands what is dragged
|
|
47
|
+
over it to the WebView that controller controls, which is drawn from the
|
|
48
|
+
top left corner of the window's client area.
|
|
49
|
+
|
|
50
|
+
It has to be called on the thread that owns the window, which it
|
|
51
|
+
initializes OLE on. The WebView takes a drop only while the controller's
|
|
52
|
+
allow_external_drop is true.
|
|
53
|
+
"""
|
|
54
|
+
_native.register_drop_target(
|
|
55
|
+
_runtime.as_interface(controller, _core.CoreWebView2CompositionController),
|
|
56
|
+
hwnd,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
target = object.__new__(DropTarget)
|
|
60
|
+
target._hwnd = hwnd # pyright: ignore[reportPrivateUsage]
|
|
61
|
+
|
|
62
|
+
return target
|
winrt_microsoft_web_webview2_interop-4!1.0.4314.35.1/winrt/microsoft/web/webview2/interop/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: winrt-Microsoft.Web.WebView2.Interop
|
|
3
|
+
Version: 4!1.0.4314.35.1
|
|
4
|
+
Summary: Lets a visually hosted WebView2 take the files dropped on its window, as an OLE drop target.
|
|
5
|
+
License-Expression: MIT
|
|
6
|
+
Project-URL: Documentation, https://pywinrt.readthedocs.io
|
|
7
|
+
Project-URL: Repository, https://github.com/pywinrt/pywinrt
|
|
8
|
+
Project-URL: Changelog, https://github.com/pywinrt/pywinrt/blob/main/projection/webview2/CHANGELOG.md
|
|
9
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.15
|
|
16
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: Programming Language :: Python :: Free Threading :: 2 - Beta
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: winrt-runtime<5,>=4.0.0
|
|
24
|
+
Requires-Dist: winrt-Microsoft.Web.WebView2>=4!1.0.4314.35
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
<!-- warning: Please don't edit this file. It was automatically generated. -->
|
|
28
|
+
|
|
29
|
+
# winrt-Microsoft.Web.WebView2.Interop
|
|
30
|
+
|
|
31
|
+
Lets a visually hosted WebView2 take the files dropped on its window, as an OLE drop target.
|
|
32
|
+
|
|
33
|
+
This package provides the `winrt.microsoft.web.webview2.interop` module.
|
|
34
|
+
|
|
35
|
+
It is built against version 1.0.4314.35 of the `Microsoft.Web.WebView2`
|
|
36
|
+
NuGet package.
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
pip install winrt-Microsoft.Web.WebView2.Interop
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
installs it with `winrt-Microsoft.Web.WebView2`.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
interop.h
|
|
5
|
+
py.Microsoft.Web.WebView2.Interop.cpp
|
|
6
|
+
pyproject.toml
|
|
7
|
+
requirements.txt
|
|
8
|
+
setup.py
|
|
9
|
+
winrt/_winrt_microsoft_web_webview2_interop.pyi
|
|
10
|
+
winrt/microsoft/web/webview2/interop/__init__.py
|
|
11
|
+
winrt/microsoft/web/webview2/interop/py.typed
|
|
12
|
+
winrt_Microsoft.Web.WebView2.Interop.egg-info/PKG-INFO
|
|
13
|
+
winrt_Microsoft.Web.WebView2.Interop.egg-info/SOURCES.txt
|
|
14
|
+
winrt_Microsoft.Web.WebView2.Interop.egg-info/dependency_links.txt
|
|
15
|
+
winrt_Microsoft.Web.WebView2.Interop.egg-info/requires.txt
|
|
16
|
+
winrt_Microsoft.Web.WebView2.Interop.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
winrt
|