Bug 1910150: Update windows-rs to 0.58. r=glandium,supply-chain-reviewers
Update the `windows` Microsoft Windows binding crate to 0.58.
- Update `taskcluster/kinds/fetch/toolchains.yml` to request version
0.58 of the `windows` crate.
- Update `build/rust/windows/Cargo.toml` to present itself as 0.58.
- Vendor the following new crates into `third_party/rust`:
- windows-core
- windows-implement
- windows-interface
- windows-result
- windows-strings
- Update `supply-chain/imports.lock` as necessary.
Differential Revision: https://phabricator.services.mozilla.com/D218694
This commit is contained in:
51
Cargo.lock
generated
51
Cargo.lock
generated
@@ -6903,7 +6903,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.52.0"
|
||||
version = "0.58.0"
|
||||
dependencies = [
|
||||
"mozbuild",
|
||||
"windows-core",
|
||||
@@ -6912,10 +6912,55 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
|
||||
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
|
||||
dependencies = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-result",
|
||||
"windows-strings",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.58.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
|
||||
dependencies = [
|
||||
"windows-result",
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
|
||||
@@ -11,10 +11,16 @@
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
rust-version = "1.70"
|
||||
name = "windows"
|
||||
version = "0.52.0"
|
||||
version = "0.58.0"
|
||||
authors = ["Microsoft"]
|
||||
build = false
|
||||
exclude = ["features.json"]
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "Rust for Windows"
|
||||
documentation = "https://microsoft.github.io/windows-docs-rs/"
|
||||
readme = "readme.md"
|
||||
@@ -30,24 +36,22 @@ rustdoc-args = [
|
||||
]
|
||||
targets = []
|
||||
|
||||
[lib]
|
||||
name = "windows"
|
||||
path = "src/lib.rs"
|
||||
test = false
|
||||
doctest = false
|
||||
|
||||
[dependencies.windows-core]
|
||||
version = "0.52.0"
|
||||
|
||||
[dependencies.windows-implement]
|
||||
version = "0.52.0"
|
||||
optional = true
|
||||
|
||||
[dependencies.windows-interface]
|
||||
version = "0.52.0"
|
||||
optional = true
|
||||
version = "0.58.0"
|
||||
|
||||
[dependencies.windows-targets]
|
||||
version = "0.52.0"
|
||||
version = "0.52.6"
|
||||
|
||||
[features]
|
||||
AI = []
|
||||
AI = ["Foundation"]
|
||||
AI_MachineLearning = ["AI"]
|
||||
ApplicationModel = []
|
||||
ApplicationModel = ["Foundation"]
|
||||
ApplicationModel_Activation = ["ApplicationModel"]
|
||||
ApplicationModel_AppExtensions = ["ApplicationModel"]
|
||||
ApplicationModel_AppService = ["ApplicationModel"]
|
||||
@@ -75,6 +79,7 @@ ApplicationModel_ExtendedExecution = ["ApplicationModel"]
|
||||
ApplicationModel_ExtendedExecution_Foreground = ["ApplicationModel_ExtendedExecution"]
|
||||
ApplicationModel_Holographic = ["ApplicationModel"]
|
||||
ApplicationModel_LockScreen = ["ApplicationModel"]
|
||||
ApplicationModel_PackageExtensions = ["ApplicationModel"]
|
||||
ApplicationModel_Payments = ["ApplicationModel"]
|
||||
ApplicationModel_Payments_Provider = ["ApplicationModel_Payments"]
|
||||
ApplicationModel_Preview = ["ApplicationModel"]
|
||||
@@ -86,10 +91,6 @@ ApplicationModel_Resources_Core = ["ApplicationModel_Resources"]
|
||||
ApplicationModel_Resources_Management = ["ApplicationModel_Resources"]
|
||||
ApplicationModel_Search = ["ApplicationModel"]
|
||||
ApplicationModel_Search_Core = ["ApplicationModel_Search"]
|
||||
ApplicationModel_Store = ["ApplicationModel"]
|
||||
ApplicationModel_Store_LicenseManagement = ["ApplicationModel_Store"]
|
||||
ApplicationModel_Store_Preview = ["ApplicationModel_Store"]
|
||||
ApplicationModel_Store_Preview_InstallControl = ["ApplicationModel_Store_Preview"]
|
||||
ApplicationModel_UserActivities = ["ApplicationModel"]
|
||||
ApplicationModel_UserActivities_Core = ["ApplicationModel_UserActivities"]
|
||||
ApplicationModel_UserDataAccounts = ["ApplicationModel"]
|
||||
@@ -100,7 +101,7 @@ ApplicationModel_UserDataTasks_DataProvider = ["ApplicationModel_UserDataTasks"]
|
||||
ApplicationModel_VoiceCommands = ["ApplicationModel"]
|
||||
ApplicationModel_Wallet = ["ApplicationModel"]
|
||||
ApplicationModel_Wallet_System = ["ApplicationModel_Wallet"]
|
||||
Data = []
|
||||
Data = ["Foundation"]
|
||||
Data_Html = ["Data"]
|
||||
Data_Json = ["Data"]
|
||||
Data_Pdf = ["Data"]
|
||||
@@ -108,7 +109,7 @@ Data_Text = ["Data"]
|
||||
Data_Xml = ["Data"]
|
||||
Data_Xml_Dom = ["Data_Xml"]
|
||||
Data_Xml_Xsl = ["Data_Xml"]
|
||||
Devices = []
|
||||
Devices = ["Foundation"]
|
||||
Devices_Adc = ["Devices"]
|
||||
Devices_Adc_Provider = ["Devices_Adc"]
|
||||
Devices_Background = ["Devices"]
|
||||
@@ -157,14 +158,14 @@ Devices_Usb = ["Devices"]
|
||||
Devices_WiFi = ["Devices"]
|
||||
Devices_WiFiDirect = ["Devices"]
|
||||
Devices_WiFiDirect_Services = ["Devices_WiFiDirect"]
|
||||
Embedded = []
|
||||
Embedded = ["Foundation"]
|
||||
Embedded_DeviceLockdown = ["Embedded"]
|
||||
Foundation = []
|
||||
Foundation_Collections = ["Foundation"]
|
||||
Foundation_Diagnostics = ["Foundation"]
|
||||
Foundation_Metadata = ["Foundation"]
|
||||
Foundation_Numerics = ["Foundation"]
|
||||
Gaming = []
|
||||
Gaming = ["Foundation"]
|
||||
Gaming_Input = ["Gaming"]
|
||||
Gaming_Input_Custom = ["Gaming_Input"]
|
||||
Gaming_Input_ForceFeedback = ["Gaming_Input"]
|
||||
@@ -174,13 +175,13 @@ Gaming_Preview_GamesEnumeration = ["Gaming_Preview"]
|
||||
Gaming_UI = ["Gaming"]
|
||||
Gaming_XboxLive = ["Gaming"]
|
||||
Gaming_XboxLive_Storage = ["Gaming_XboxLive"]
|
||||
Globalization = []
|
||||
Globalization = ["Foundation"]
|
||||
Globalization_Collation = ["Globalization"]
|
||||
Globalization_DateTimeFormatting = ["Globalization"]
|
||||
Globalization_Fonts = ["Globalization"]
|
||||
Globalization_NumberFormatting = ["Globalization"]
|
||||
Globalization_PhoneNumberFormatting = ["Globalization"]
|
||||
Graphics = []
|
||||
Graphics = ["Foundation"]
|
||||
Graphics_Capture = ["Graphics"]
|
||||
Graphics_DirectX = ["Graphics"]
|
||||
Graphics_DirectX_Direct3D11 = ["Graphics_DirectX"]
|
||||
@@ -195,14 +196,15 @@ Graphics_Printing_OptionDetails = ["Graphics_Printing"]
|
||||
Graphics_Printing_PrintSupport = ["Graphics_Printing"]
|
||||
Graphics_Printing_PrintTicket = ["Graphics_Printing"]
|
||||
Graphics_Printing_Workflow = ["Graphics_Printing"]
|
||||
Management = []
|
||||
Management = ["Foundation"]
|
||||
Management_Core = ["Management"]
|
||||
Management_Deployment = ["Management"]
|
||||
Management_Deployment_Preview = ["Management_Deployment"]
|
||||
Management_Policies = ["Management"]
|
||||
Management_Setup = ["Management"]
|
||||
Management_Update = ["Management"]
|
||||
Management_Workplace = ["Management"]
|
||||
Media = []
|
||||
Media = ["Foundation"]
|
||||
Media_AppBroadcasting = ["Media"]
|
||||
Media_AppRecording = ["Media"]
|
||||
Media_Audio = ["Media"]
|
||||
@@ -236,7 +238,7 @@ Media_SpeechSynthesis = ["Media"]
|
||||
Media_Streaming = ["Media"]
|
||||
Media_Streaming_Adaptive = ["Media_Streaming"]
|
||||
Media_Transcoding = ["Media"]
|
||||
Networking = []
|
||||
Networking = ["Foundation"]
|
||||
Networking_BackgroundTransfer = ["Networking"]
|
||||
Networking_Connectivity = ["Networking"]
|
||||
Networking_NetworkOperators = ["Networking"]
|
||||
@@ -247,14 +249,14 @@ Networking_ServiceDiscovery_Dnssd = ["Networking_ServiceDiscovery"]
|
||||
Networking_Sockets = ["Networking"]
|
||||
Networking_Vpn = ["Networking"]
|
||||
Networking_XboxLive = ["Networking"]
|
||||
Perception = []
|
||||
Perception = ["Foundation"]
|
||||
Perception_Automation = ["Perception"]
|
||||
Perception_Automation_Core = ["Perception_Automation"]
|
||||
Perception_People = ["Perception"]
|
||||
Perception_Spatial = ["Perception"]
|
||||
Perception_Spatial_Preview = ["Perception_Spatial"]
|
||||
Perception_Spatial_Surfaces = ["Perception_Spatial"]
|
||||
Phone = []
|
||||
Phone = ["Foundation"]
|
||||
Phone_ApplicationModel = ["Phone"]
|
||||
Phone_Devices = ["Phone"]
|
||||
Phone_Devices_Notification = ["Phone_Devices"]
|
||||
@@ -278,7 +280,7 @@ Phone_System_UserProfile_GameServices = ["Phone_System_UserProfile"]
|
||||
Phone_System_UserProfile_GameServices_Core = ["Phone_System_UserProfile_GameServices"]
|
||||
Phone_UI = ["Phone"]
|
||||
Phone_UI_Input = ["Phone_UI"]
|
||||
Security = []
|
||||
Security = ["Foundation"]
|
||||
Security_Authentication = ["Security"]
|
||||
Security_Authentication_Identity = ["Security_Authentication"]
|
||||
Security_Authentication_Identity_Core = ["Security_Authentication_Identity"]
|
||||
@@ -298,14 +300,14 @@ Security_DataProtection = ["Security"]
|
||||
Security_EnterpriseData = ["Security"]
|
||||
Security_ExchangeActiveSyncProvisioning = ["Security"]
|
||||
Security_Isolation = ["Security"]
|
||||
Services = []
|
||||
Services = ["Foundation"]
|
||||
Services_Maps = ["Services"]
|
||||
Services_Maps_Guidance = ["Services_Maps"]
|
||||
Services_Maps_LocalSearch = ["Services_Maps"]
|
||||
Services_Maps_OfflineMaps = ["Services_Maps"]
|
||||
Services_Store = ["Services"]
|
||||
Services_TargetedContent = ["Services"]
|
||||
Storage = []
|
||||
Storage = ["Foundation"]
|
||||
Storage_AccessCache = ["Storage"]
|
||||
Storage_BulkAccess = ["Storage"]
|
||||
Storage_Compression = ["Storage"]
|
||||
@@ -315,7 +317,7 @@ Storage_Pickers_Provider = ["Storage_Pickers"]
|
||||
Storage_Provider = ["Storage"]
|
||||
Storage_Search = ["Storage"]
|
||||
Storage_Streams = ["Storage"]
|
||||
System = []
|
||||
System = ["Foundation"]
|
||||
System_Diagnostics = ["System"]
|
||||
System_Diagnostics_DevicePortal = ["System_Diagnostics"]
|
||||
System_Diagnostics_Telemetry = ["System_Diagnostics"]
|
||||
@@ -329,12 +331,13 @@ System_Profile = ["System"]
|
||||
System_Profile_SystemManufacturers = ["System_Profile"]
|
||||
System_RemoteDesktop = ["System"]
|
||||
System_RemoteDesktop_Input = ["System_RemoteDesktop"]
|
||||
System_RemoteDesktop_Provider = ["System_RemoteDesktop"]
|
||||
System_RemoteSystems = ["System"]
|
||||
System_Threading = ["System"]
|
||||
System_Threading_Core = ["System_Threading"]
|
||||
System_Update = ["System"]
|
||||
System_UserProfile = ["System"]
|
||||
UI = []
|
||||
UI = ["Foundation"]
|
||||
UI_Accessibility = ["UI"]
|
||||
UI_ApplicationSettings = ["UI"]
|
||||
UI_Composition = ["UI"]
|
||||
@@ -358,6 +361,7 @@ UI_Input_Preview_Injection = ["UI_Input_Preview"]
|
||||
UI_Input_Spatial = ["UI_Input"]
|
||||
UI_Notifications = ["UI"]
|
||||
UI_Notifications_Management = ["UI_Notifications"]
|
||||
UI_Notifications_Preview = ["UI_Notifications"]
|
||||
UI_Popups = ["UI"]
|
||||
UI_Shell = ["UI"]
|
||||
UI_StartScreen = ["UI"]
|
||||
@@ -371,21 +375,28 @@ UI_WebUI = ["UI"]
|
||||
UI_WebUI_Core = ["UI_WebUI"]
|
||||
UI_WindowManagement = ["UI"]
|
||||
UI_WindowManagement_Preview = ["UI_WindowManagement"]
|
||||
Wdk = []
|
||||
Wdk = ["Win32_Foundation"]
|
||||
Wdk_Devices = ["Wdk"]
|
||||
Wdk_Devices_Bluetooth = ["Wdk_Devices"]
|
||||
Wdk_Devices_HumanInterfaceDevice = ["Wdk_Devices"]
|
||||
Wdk_Foundation = ["Wdk"]
|
||||
Wdk_Graphics = ["Wdk"]
|
||||
Wdk_Graphics_Direct3D = ["Wdk_Graphics"]
|
||||
Wdk_NetworkManagement = ["Wdk"]
|
||||
Wdk_NetworkManagement_Ndis = ["Wdk_NetworkManagement"]
|
||||
Wdk_NetworkManagement_WindowsFilteringPlatform = ["Wdk_NetworkManagement"]
|
||||
Wdk_Storage = ["Wdk"]
|
||||
Wdk_Storage_FileSystem = ["Wdk_Storage"]
|
||||
Wdk_Storage_FileSystem_Minifilters = ["Wdk_Storage_FileSystem"]
|
||||
Wdk_System = ["Wdk"]
|
||||
Wdk_System_IO = ["Wdk_System"]
|
||||
Wdk_System_Memory = ["Wdk_System"]
|
||||
Wdk_System_OfflineRegistry = ["Wdk_System"]
|
||||
Wdk_System_Registry = ["Wdk_System"]
|
||||
Wdk_System_SystemInformation = ["Wdk_System"]
|
||||
Wdk_System_SystemServices = ["Wdk_System"]
|
||||
Wdk_System_Threading = ["Wdk_System"]
|
||||
Web = []
|
||||
Web = ["Foundation"]
|
||||
Web_AtomPub = ["Web"]
|
||||
Web_Http = ["Web"]
|
||||
Web_Http_Diagnostics = ["Web_Http"]
|
||||
@@ -394,7 +405,7 @@ Web_Http_Headers = ["Web_Http"]
|
||||
Web_Syndication = ["Web"]
|
||||
Web_UI = ["Web"]
|
||||
Web_UI_Interop = ["Web_UI"]
|
||||
Win32 = []
|
||||
Win32 = ["Win32_Foundation"]
|
||||
Win32_AI = ["Win32"]
|
||||
Win32_AI_MachineLearning = ["Win32_AI"]
|
||||
Win32_AI_MachineLearning_DirectML = ["Win32_AI_MachineLearning"]
|
||||
@@ -606,6 +617,7 @@ Win32_System_Diagnostics_Debug_Extensions = ["Win32_System_Diagnostics_Debug"]
|
||||
Win32_System_Diagnostics_Etw = ["Win32_System_Diagnostics"]
|
||||
Win32_System_Diagnostics_ProcessSnapshotting = ["Win32_System_Diagnostics"]
|
||||
Win32_System_Diagnostics_ToolHelp = ["Win32_System_Diagnostics"]
|
||||
Win32_System_Diagnostics_TraceLogging = ["Win32_System_Diagnostics"]
|
||||
Win32_System_DistributedTransactionCoordinator = ["Win32_System"]
|
||||
Win32_System_Environment = ["Win32_System"]
|
||||
Win32_System_ErrorReporting = ["Win32_System"]
|
||||
@@ -723,14 +735,23 @@ Win32_UI_WindowsAndMessaging = ["Win32_UI"]
|
||||
Win32_UI_Wpf = ["Win32_UI"]
|
||||
Win32_Web = ["Win32"]
|
||||
Win32_Web_InternetExplorer = ["Win32_Web"]
|
||||
default = []
|
||||
default = ["std"]
|
||||
deprecated = []
|
||||
docs = []
|
||||
implement = [
|
||||
"windows-implement",
|
||||
"windows-interface",
|
||||
"windows-core/implement",
|
||||
]
|
||||
implement = []
|
||||
std = ["windows-core/std"]
|
||||
|
||||
[lints.rust]
|
||||
missing_docs = "warn"
|
||||
|
||||
[lints.rust.rust_2018_idioms]
|
||||
level = "warn"
|
||||
priority = -1
|
||||
|
||||
[lints.rust.unexpected_cfgs]
|
||||
level = "warn"
|
||||
priority = 0
|
||||
check-cfg = ["cfg(windows_raw_dylib, windows_debugger_visualizer, windows_slim_errors)"]
|
||||
|
||||
[dependencies.mozbuild]
|
||||
version = "0.1"
|
||||
|
||||
@@ -809,6 +809,34 @@ user-id = 64539
|
||||
user-login = "kennykerr"
|
||||
user-name = "Kenny Kerr"
|
||||
|
||||
[[publisher.windows-implement]]
|
||||
version = "0.58.0"
|
||||
when = "2024-07-03"
|
||||
user-id = 64539
|
||||
user-login = "kennykerr"
|
||||
user-name = "Kenny Kerr"
|
||||
|
||||
[[publisher.windows-interface]]
|
||||
version = "0.58.0"
|
||||
when = "2024-07-03"
|
||||
user-id = 64539
|
||||
user-login = "kennykerr"
|
||||
user-name = "Kenny Kerr"
|
||||
|
||||
[[publisher.windows-result]]
|
||||
version = "0.2.0"
|
||||
when = "2024-07-03"
|
||||
user-id = 64539
|
||||
user-login = "kennykerr"
|
||||
user-name = "Kenny Kerr"
|
||||
|
||||
[[publisher.windows-strings]]
|
||||
version = "0.1.0"
|
||||
when = "2024-07-03"
|
||||
user-id = 64539
|
||||
user-login = "kennykerr"
|
||||
user-name = "Kenny Kerr"
|
||||
|
||||
[[publisher.windows-sys]]
|
||||
version = "0.52.0"
|
||||
when = "2023-11-15"
|
||||
|
||||
@@ -652,9 +652,9 @@ windows-rs:
|
||||
description: Source of the windows rust crate
|
||||
fetch:
|
||||
type: static-url
|
||||
url: https://crates.io/api/v1/crates/windows/0.52.0/download
|
||||
sha256: e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be
|
||||
size: 11843715
|
||||
url: https://crates.io/api/v1/crates/windows/0.58.0/download
|
||||
sha256: dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6
|
||||
size: 9744521
|
||||
artifact-name: windows-rs.tar.zst
|
||||
strip-components: 1
|
||||
add-prefix: windows-rs/
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"files":{"Cargo.toml":"483877d1a465dc6a4c190fdc206eb83293e6102d548dcf0f2e2093fa075694f5","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"3bcfa95b17c7748ff6139e7482ebad2d24645ac3606e4b4f88318c72122d1386","src/agile_reference.rs":"801b3bbe3674e2665bdcb12a08f06f7782be60a14c3a033289f32aa35db1fce1","src/array.rs":"c9975db941876ce329ed851b5e6ad989a660f9da0f91e8dece7333fda2274e01","src/as_impl.rs":"018954b44fe4c16d62a959f5578c5a26b968d0f9a3f156f1bac10492b934d949","src/com_interface.rs":"afc47510e80e829b5ebb2a801840104725dfcea3c5920a424b089948a14f8d15","src/error.rs":"c9115facaaa7369e91e3d959e9278770d727e52bb0108df099ae5c90feb52fdf","src/event.rs":"cc3502add9db70efb2627ddc5c709853a56ccbfee37923d67b56ed338b9d8f44","src/guid.rs":"dd82af578fef2519173614600a15ada073d5e7c973fd2e951eb5abef9b1553d0","src/hresult.rs":"00155798c154614c4c9a0a2da20814dddb537a1e21c88bc3dff65598fdf7ee03","src/imp/bindings.rs":"805fe0012f5bbf639f6d66cfdbe21f4f855c4ec3eee2610f457dbf3b80defad7","src/imp/com_bindings.rs":"3f88e91dd17daf657c9e29e82628fc84fa02b942bca1ae5ca682e4a2a89ccb6e","src/imp/delay_load.rs":"26492b2ef34f4a3ac35f41050a9088ee15603caf0a59c6e74fdf423bfcb96829","src/imp/factory_cache.rs":"fcec72750d06a262878720a13f82b7365075c6b038b28426532b233aae8baa84","src/imp/generic_factory.rs":"cbf8b251e2758d98bf6bbd7c73b20a2e31e60e0d006b2febc51e247c039fab85","src/imp/heap.rs":"646e31462f37f96a9d6928997c2bbacc333eabb3989e9999e89ff95e9565e4ba","src/imp/mod.rs":"503ab66c7911e5ad6dfd2311f81674798c84e41d3c023b4868f80ad3a3593b8f","src/imp/ref_count.rs":"ded51b50923eb1d542432d216b56604b6cef564f664740a3ad8290ad8d88b8e6","src/imp/sha1.rs":"0ff2ba4d1f77b5ec3859567fec1a3d75175a844914c5f7ec068c8581dc2b7f4a","src/imp/waiter.rs":"575cfdbe9befc22b1e8fa91e15f303d830b23673d07a5361992229e0440081b2","src/imp/weak_ref_count.rs":"5d58f4bdcb4b6fbb55be672b7bd885307c9cac17ee4f212c899a54e76a039ded","src/inspectable.rs":"32c4881d567d90254556a4185cd0dd5b984c932183db7c8b4c51bcbac53e41ac","src/interface.rs":"4a4588085d5401585aabc62a131d2601134f4fb80ba2199fe066e6df6c84ead3","src/lib.rs":"9673f8d82af0325a5924b9afe07af39e7ea82731c3caca126e39cd9596dd4e63","src/param.rs":"cb62f173048e84f6355662223d34be482449393fc049fc45980d1bf087dc8e77","src/runtime_name.rs":"b330db95b0ce32c963d6b43a0b152cd96e136e5b38b92c02223fb53b30f83ecf","src/runtime_type.rs":"cf3697b442b2bc77e1a8981128eb5f4c282603a01f7081399f1e11587670d0bc","src/scoped_interface.rs":"c11be14a0c95c3c9b055741e4b9c353d6bb6efe88075ceb05fd606b6ac34a2a6","src/strings/bstr.rs":"569ff0cf6157cb869ec14f773261fe95ee1d065cade7b04d3ee44f0dfbdec149","src/strings/hstring.rs":"ea3913393e655b6c48270df04fbb82eb9fc4b1d3f1d673bd04872a33d160f38d","src/strings/literals.rs":"5b998ebd3a750a7f42c2013b354a58f6c289f5f433f154a9ac34b47e23ec9429","src/strings/mod.rs":"4aaf6d2efe2396e541bd5d9ddff859d3374bfda4914b67daf645ee3b48cc3852","src/strings/pcstr.rs":"3c29064d22e632dc9f30c8d6933e41d5c755d2c82462c6570318bebe12a5c1a3","src/strings/pcwstr.rs":"86a36da73bdcd12af9a6e1be09470443b42017a0613c432ac3e559cfdc7f3ff2","src/strings/pstr.rs":"151d29125932d874aefcda01975913f87e8561b3d240e84c9db39e891b78a484","src/strings/pwstr.rs":"de99eb08f1f3c351854d1ed1f978460669b53ae39dc118e788a9f66a562d2c7c","src/type.rs":"fc263c265f799c7d5b326cebbbc20a8f96ee438b1cc444d9925caab22db8e488","src/unknown.rs":"5a1888c35ad9db383216bbe1c15dde3ea316d40ba2783392067060706f7ec812","src/weak.rs":"b1d1740d65ad0b9f296342afbac0c6994eb2fa0ea7dba4882b64b246e309d9da","windows.natvis":"f9bd327a207011f85debdd3d67828668f71b56e7e429a7172dab1286738ca238"},"package":"33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"}
|
||||
{"files":{"Cargo.toml":"6a0eed9b6df5e3fbdd4fb636fdf0778f0182dfe81fee1427de89088c31dfb299","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"a3280bab4a34e02f616e9c55459182ed93df0cf06ae6d69743140746366679d5","src/agile_reference.rs":"aeca8437136c09a51ef45cface5ae8e6720f67d23681faa12a84b14a79cfeed2","src/array.rs":"50afdb247feb5e0b575a9cfeda2359719fe0db7bd4b12c687d699f3821d15eee","src/as_impl.rs":"b9d36d6634de33928cc78b8e0824483c5b6561ca3872d5a9b267fb196db3d07e","src/com_object.rs":"c02e31da9d2d8efd7074bf3e44afe3279ca727c6ec3b840ae4d71a8c98bc55e6","src/event.rs":"d0e528b73744e31a3c46e2a69b441ba83970e3576cd5099c66792328f8dca34a","src/guid.rs":"27f3e764fb5787cf8dbf2e284e643e1555a3bd1ae5d0d70b76a9193cd051792f","src/handles.rs":"c5f53785605cc14059c4ad0272e310b435ed2f48405e8e4052fb1d5e40ee4d78","src/imp/bindings.rs":"949bd0444b102df0b63fcbc1451171c1e13400044303fd6aa50a00b1f191c198","src/imp/can_into.rs":"d06228653f20c07dcfd8a4004cd6be7a19a8da0a79226d42653ab2f3bf290816","src/imp/com_bindings.rs":"b0e5f877f7e2db25dd680ae5c75197e9ff4cb0efb2d14083f17866a20aa5440c","src/imp/factory_cache.rs":"64f00976c5e6392de7a2c4d161f58874c7dfdbecab2c983d20d16fd1acb26826","src/imp/generic_factory.rs":"340e2a75a5c4ec36bc7ea442c7211b3be4f8d3a537fda99316f9ce15bde02555","src/imp/mod.rs":"e16decb788da9edf33b7706c1ae21c2c610f0b96b4b1b505fd4c57a6e0a11193","src/imp/ref_count.rs":"57ed3694b12509b05a140c84eab931b69d4c93c446b2842aed708a9ee6a0c862","src/imp/sha1.rs":"bf8707becd6f32e13d23da0b5ecad906858f42af9626b130a3a88bf8b4f0975e","src/imp/waiter.rs":"eae739b667fcdf290cdeb533bd1254d423e1165fa697cba7a522caa5ca66f89b","src/imp/weak_ref_count.rs":"8a69cfce27500ccc0b511de3183c0d19ad260fbffc48a8bf05275b9fc02c7118","src/imp/windows.rs":"6bf14613157d1cb1d0a376fc20fb9ee5dc2d40a64535c528bff526c4e0a895b7","src/inspectable.rs":"d6767bb4796f4e2fd1c03a2cf9fddd97d7b395ca4d56dd6a443333ce92a7865b","src/interface.rs":"c3bcbdcef95f91742215f29d57ee9920fae7923914eb635054e81ad34bd06a12","src/lib.rs":"cb46d0844bcf4ae7a2d3477e206d1623c861e68b3ec0fa8821c87df27eba36e5","src/out_param.rs":"d91dd1a88201c2dbb395d371ba42270bc19191861758496fccba30ad5f8d52e9","src/out_ref.rs":"e12010828943df8c4aa40c9b53316a96f14c208fdb0e860b5206ddc5eedce1d2","src/param.rs":"88f2de2f038e3f8776872c8f9db456a9f012329800b75e001624cdf9671cf97c","src/param_value.rs":"b1d29ec7589cc7eebba1faf01aaae39f9d401dff13d2a6a5ec382f94b1becce0","src/ref.rs":"9cdceb34ad726190459bef5ec8d2a030b0dbf164b5cd969d215a3d09622897f6","src/runtime_name.rs":"b330db95b0ce32c963d6b43a0b152cd96e136e5b38b92c02223fb53b30f83ecf","src/runtime_type.rs":"4f504a1ee3525003d4376d259c5e195a08617bd5aff1789fd9027d51b354eb63","src/scoped_interface.rs":"57d9dcd0284659e2bf465c08d6c857c2c985e90f0316e5677ebd2a656edb6737","src/type.rs":"caf4d12aa96f3204148c33f6853b7f31699fde13b2b4ada3ba2a01faab89647a","src/unknown.rs":"9b6117025d4d18600ef682aa0bacb904c020b0b6bfe6c1ab6d236c716a3abea1","src/variant.rs":"2708f9ba47369879b222f19c8bc29705d03140b254d0c09ab7557a0f71dd006e","src/weak.rs":"0363f44452b6d363431f5b4d83c83be74d6c5eb419a3d5d9a3eb35b611d3c2a6","src/windows.rs":"6cd563c982c98c18f98753b210df17c71a728532392b88d11a1fc8cef9d01397"},"package":"6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"}
|
||||
43
third_party/rust/windows-core/Cargo.toml
vendored
43
third_party/rust/windows-core/Cargo.toml
vendored
@@ -11,10 +11,15 @@
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.56"
|
||||
rust-version = "1.70"
|
||||
name = "windows-core"
|
||||
version = "0.52.0"
|
||||
version = "0.58.0"
|
||||
authors = ["Microsoft"]
|
||||
build = false
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "Rust for Windows"
|
||||
readme = "readme.md"
|
||||
categories = ["os::windows-apis"]
|
||||
@@ -25,9 +30,37 @@ repository = "https://github.com/microsoft/windows-rs"
|
||||
default-target = "x86_64-pc-windows-msvc"
|
||||
targets = []
|
||||
|
||||
[lib]
|
||||
name = "windows_core"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies.windows-implement]
|
||||
version = "0.58.0"
|
||||
|
||||
[dependencies.windows-interface]
|
||||
version = "0.58.0"
|
||||
|
||||
[dependencies.windows-result]
|
||||
version = "0.2.0"
|
||||
|
||||
[dependencies.windows-strings]
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies.windows-targets]
|
||||
version = "0.52.0"
|
||||
version = "0.52.6"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
implement = []
|
||||
default = ["std"]
|
||||
std = []
|
||||
|
||||
[lints.rust]
|
||||
missing_docs = "warn"
|
||||
|
||||
[lints.rust.rust_2018_idioms]
|
||||
level = "warn"
|
||||
priority = -1
|
||||
|
||||
[lints.rust.unexpected_cfgs]
|
||||
level = "warn"
|
||||
priority = 0
|
||||
check-cfg = ["cfg(windows_raw_dylib, windows_debugger_visualizer, windows_slim_errors)"]
|
||||
|
||||
8
third_party/rust/windows-core/readme.md
vendored
8
third_party/rust/windows-core/readme.md
vendored
@@ -3,14 +3,14 @@
|
||||
The [windows](https://crates.io/crates/windows) and [windows-sys](https://crates.io/crates/windows-sys) crates let you call any Windows API past, present, and future using code generated on the fly directly from the [metadata describing the API](https://github.com/microsoft/windows-rs/tree/master/crates/libs/bindgen/default) and right into your Rust package where you can call them as if they were just another Rust module. The Rust language projection follows in the tradition established by [C++/WinRT](https://github.com/microsoft/cppwinrt) of building language projections for Windows using standard languages and compilers, providing a natural and idiomatic way for Rust developers to call Windows APIs.
|
||||
|
||||
* [Getting started](https://kennykerr.ca/rust-getting-started/)
|
||||
* [Samples](https://github.com/microsoft/windows-rs/tree/0.52.0/crates/samples) <!-- link to samples for upcoming release -->
|
||||
* [Samples](https://github.com/microsoft/windows-rs/tree/0.58.0/crates/samples)
|
||||
* [Releases](https://github.com/microsoft/windows-rs/releases)
|
||||
|
||||
Start by adding the following to your Cargo.toml file:
|
||||
|
||||
```toml
|
||||
[dependencies.windows]
|
||||
version = "0.52"
|
||||
version = "0.58"
|
||||
features = [
|
||||
"Data_Xml_Dom",
|
||||
"Win32_Foundation",
|
||||
@@ -81,8 +81,8 @@ fn main() {
|
||||
WaitForSingleObject(event, 0);
|
||||
CloseHandle(event);
|
||||
|
||||
MessageBoxA(0, s!("Ansi"), s!("Caption"), MB_OK);
|
||||
MessageBoxW(0, w!("Wide"), w!("Caption"), MB_OK);
|
||||
MessageBoxA(0 as _, s!("Ansi"), s!("Caption"), MB_OK);
|
||||
MessageBoxW(0 as _, w!("Wide"), w!("Caption"), MB_OK);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
use super::*;
|
||||
use std::marker::PhantomData;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
/// A type representing an agile reference to a COM/WinRT object.
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct AgileReference<T>(crate::imp::IAgileReference, PhantomData<T>);
|
||||
pub struct AgileReference<T>(imp::IAgileReference, PhantomData<T>);
|
||||
|
||||
impl<T: ComInterface> AgileReference<T> {
|
||||
impl<T: Interface> AgileReference<T> {
|
||||
/// Creates an agile reference to the object.
|
||||
pub fn new(object: &T) -> Result<Self> {
|
||||
unsafe { crate::imp::RoGetAgileReference(crate::imp::AGILEREFERENCE_DEFAULT, &T::IID, object.as_unknown()).map(|reference| Self(reference, Default::default())) }
|
||||
// TODO: this assert is required until we can catch this at compile time using an "associated const equality" constraint.
|
||||
// For example, <T: Interface<UNKNOWN = true>>
|
||||
// https://github.com/rust-lang/rust/issues/92827
|
||||
assert!(T::UNKNOWN);
|
||||
unsafe {
|
||||
imp::RoGetAgileReference(
|
||||
imp::AGILEREFERENCE_DEFAULT,
|
||||
&T::IID,
|
||||
core::mem::transmute::<&T, &IUnknown>(object),
|
||||
)
|
||||
.map(|reference| Self(reference, Default::default()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Retrieves a proxy to the target of the `AgileReference` object that may safely be used within any thread context in which get is called.
|
||||
@@ -18,11 +29,11 @@ impl<T: ComInterface> AgileReference<T> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ComInterface> Send for AgileReference<T> {}
|
||||
unsafe impl<T: ComInterface> Sync for AgileReference<T> {}
|
||||
unsafe impl<T: Interface> Send for AgileReference<T> {}
|
||||
unsafe impl<T: Interface> Sync for AgileReference<T> {}
|
||||
|
||||
impl<T> std::fmt::Debug for AgileReference<T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
impl<T> core::fmt::Debug for AgileReference<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "AgileReference({:?})", &self.0)
|
||||
}
|
||||
}
|
||||
|
||||
43
third_party/rust/windows-core/src/array.rs
vendored
43
third_party/rust/windows-core/src/array.rs
vendored
@@ -8,7 +8,10 @@ pub struct Array<T: Type<T>> {
|
||||
|
||||
impl<T: Type<T>> Default for Array<T> {
|
||||
fn default() -> Self {
|
||||
Array { data: std::ptr::null_mut(), len: 0 }
|
||||
Array {
|
||||
data: core::ptr::null_mut(),
|
||||
len: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,14 +23,16 @@ impl<T: Type<T>> Array<T> {
|
||||
|
||||
/// Creates an array of the given length with default values.
|
||||
pub fn with_len(len: usize) -> Self {
|
||||
assert!(len < std::u32::MAX as usize);
|
||||
let bytes_amount = len.checked_mul(std::mem::size_of::<T>()).expect("Attempted to allocate too large an Array");
|
||||
assert!(len < u32::MAX as usize);
|
||||
let bytes_amount = len
|
||||
.checked_mul(core::mem::size_of::<T>())
|
||||
.expect("Attempted to allocate too large an Array");
|
||||
|
||||
// WinRT arrays must be allocated with CoTaskMemAlloc.
|
||||
// SAFETY: the call to CoTaskMemAlloc is safe to perform
|
||||
// if len is zero and overflow was checked above.
|
||||
// We ensured we alloc enough space by multiplying len * size_of::<T>
|
||||
let data = unsafe { crate::imp::CoTaskMemAlloc(bytes_amount) as *mut T::Default };
|
||||
let data = unsafe { imp::CoTaskMemAlloc(bytes_amount) as *mut T::Default };
|
||||
|
||||
assert!(!data.is_null(), "Could not successfully allocate for Array");
|
||||
|
||||
@@ -36,7 +41,7 @@ impl<T: Type<T>> Array<T> {
|
||||
// bytes making the entire array zero initialized. We have assured
|
||||
// above that the data ptr is not null.
|
||||
unsafe {
|
||||
std::ptr::write_bytes(data, 0, len);
|
||||
core::ptr::write_bytes(data, 0, len);
|
||||
}
|
||||
|
||||
let len = len as u32;
|
||||
@@ -81,22 +86,22 @@ impl<T: Type<T>> Array<T> {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut data = std::ptr::null_mut();
|
||||
let mut data = core::ptr::null_mut();
|
||||
let mut len = 0;
|
||||
|
||||
std::mem::swap(&mut data, &mut self.data);
|
||||
std::mem::swap(&mut len, &mut self.len);
|
||||
core::mem::swap(&mut data, &mut self.data);
|
||||
core::mem::swap(&mut len, &mut self.len);
|
||||
|
||||
// SAFETY: At this point, self has been reset to zero so any panics in T's destructor would
|
||||
// only leak data not leave the array in bad state.
|
||||
unsafe {
|
||||
// Call the destructors of all the elements of the old array
|
||||
// SAFETY: the slice cannot be used after the call to `drop_in_place`
|
||||
std::ptr::drop_in_place(std::slice::from_raw_parts_mut(data, len as usize));
|
||||
core::ptr::drop_in_place(core::slice::from_raw_parts_mut(data, len as usize));
|
||||
// Free the data memory where the elements were
|
||||
// SAFETY: we have unique access to the data pointer at this point
|
||||
// so freeing it is the right thing to do
|
||||
crate::imp::CoTaskMemFree(data as _);
|
||||
imp::CoTaskMemFree(data as _);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,12 +120,12 @@ impl<T: Type<T>> Array<T> {
|
||||
/// Turn the array into a pointer to its data and its length
|
||||
pub fn into_abi(self) -> (*mut T::Abi, u32) {
|
||||
let abi = (self.data as *mut _, self.len);
|
||||
std::mem::forget(self);
|
||||
core::mem::forget(self);
|
||||
abi
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type<T>> std::ops::Deref for Array<T> {
|
||||
impl<T: Type<T>> core::ops::Deref for Array<T> {
|
||||
type Target = [T::Default];
|
||||
|
||||
fn deref(&self) -> &[T::Default] {
|
||||
@@ -129,18 +134,18 @@ impl<T: Type<T>> std::ops::Deref for Array<T> {
|
||||
}
|
||||
|
||||
// SAFETY: data must not be null if the array is not empty
|
||||
unsafe { std::slice::from_raw_parts(self.data, self.len as usize) }
|
||||
unsafe { core::slice::from_raw_parts(self.data, self.len as usize) }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Type<T>> std::ops::DerefMut for Array<T> {
|
||||
impl<T: Type<T>> core::ops::DerefMut for Array<T> {
|
||||
fn deref_mut(&mut self) -> &mut [T::Default] {
|
||||
if self.is_empty() {
|
||||
return &mut [];
|
||||
}
|
||||
|
||||
// SAFETY: data must not be null if the array is not empty
|
||||
unsafe { std::slice::from_raw_parts_mut(self.data, self.len as usize) }
|
||||
unsafe { core::slice::from_raw_parts_mut(self.data, self.len as usize) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,12 +159,16 @@ impl<T: Type<T>> Drop for Array<T> {
|
||||
pub struct ArrayProxy<T: Type<T>> {
|
||||
data: *mut *mut T::Default,
|
||||
len: *mut u32,
|
||||
temp: std::mem::ManuallyDrop<Array<T>>,
|
||||
temp: core::mem::ManuallyDrop<Array<T>>,
|
||||
}
|
||||
|
||||
impl<T: Type<T>> ArrayProxy<T> {
|
||||
pub fn from_raw_parts(data: *mut *mut T::Default, len: *mut u32) -> Self {
|
||||
Self { data, len, temp: std::mem::ManuallyDrop::new(Array::new()) }
|
||||
Self {
|
||||
data,
|
||||
len,
|
||||
temp: core::mem::ManuallyDrop::new(Array::new()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_array(&mut self) -> &mut Array<T> {
|
||||
|
||||
12
third_party/rust/windows-core/src/as_impl.rs
vendored
12
third_party/rust/windows-core/src/as_impl.rs
vendored
@@ -6,5 +6,15 @@ pub trait AsImpl<T> {
|
||||
///
|
||||
/// The caller needs to ensure that `self` is actually implemented by the
|
||||
/// implementation `T`.
|
||||
unsafe fn as_impl(&self) -> &T;
|
||||
unsafe fn as_impl(&self) -> &T {
|
||||
self.as_impl_ptr().as_ref()
|
||||
}
|
||||
|
||||
/// Returns a pointer to the implementation object.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller needs to ensure that `self` is actually implemented by the
|
||||
/// implementation `T`.
|
||||
unsafe fn as_impl_ptr(&self) -> core::ptr::NonNull<T>;
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
use super::*;
|
||||
|
||||
/// Provides low-level access to a COM interface.
|
||||
///
|
||||
/// This trait is automatically implemented by the generated bindings and should not be
|
||||
/// implemented manually.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is only safe to implement this trait if the implementing type is a valid COM interface pointer meaning
|
||||
/// the following criteria are met:
|
||||
/// * its in-memory representation is equal to `NonNull<NonNull<Self::VTable>>`
|
||||
/// * the vtable is correctly structured beginning with the `IUnknown` function pointers
|
||||
/// * the vtable must be the correct vtable for the supplied IID
|
||||
pub unsafe trait ComInterface: Interface + Clone {
|
||||
/// A unique identifier representing this interface.
|
||||
const IID: GUID;
|
||||
|
||||
// Casts the `ComInterface` to a `IUnknown`.
|
||||
fn as_unknown(&self) -> &IUnknown {
|
||||
// SAFETY: it is always safe to treat a `ComInterface` as an `IUnknown`.
|
||||
unsafe { std::mem::transmute(self) }
|
||||
}
|
||||
|
||||
/// Attempts to cast the current interface to another interface using `QueryInterface`.
|
||||
///
|
||||
/// The name `cast` is preferred to `query` because there is a WinRT method named query but not one
|
||||
/// named cast.
|
||||
fn cast<T: ComInterface>(&self) -> Result<T> {
|
||||
let mut result = None;
|
||||
// SAFETY: `result` is valid for writing an interface pointer and it is safe
|
||||
// to cast the `result` pointer as `T` on success because we are using the `IID` tied
|
||||
// to `T` which the implementor of `ComInterface` has guaranteed is correct
|
||||
unsafe { self.query(&T::IID, &mut result as *mut _ as _).and_some(result) }
|
||||
}
|
||||
|
||||
/// Attempts to create a [`Weak`] reference to this object.
|
||||
fn downgrade(&self) -> Result<Weak<Self>> {
|
||||
self.cast::<crate::imp::IWeakReferenceSource>().and_then(|source| Weak::downgrade(&source))
|
||||
}
|
||||
|
||||
/// Call `QueryInterface` on this interface
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `interface` must be a non-null, valid pointer for writing an interface pointer.
|
||||
unsafe fn query(&self, iid: *const GUID, interface: *mut *mut std::ffi::c_void) -> HRESULT {
|
||||
(self.assume_vtable::<IUnknown>().QueryInterface)(self.as_raw(), iid, interface)
|
||||
}
|
||||
}
|
||||
332
third_party/rust/windows-core/src/com_object.rs
vendored
Normal file
332
third_party/rust/windows-core/src/com_object.rs
vendored
Normal file
@@ -0,0 +1,332 @@
|
||||
use crate::imp::Box;
|
||||
use crate::{AsImpl, IUnknown, IUnknownImpl, Interface, InterfaceRef};
|
||||
use core::any::Any;
|
||||
use core::borrow::Borrow;
|
||||
use core::ops::Deref;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
/// Identifies types that can be placed in [`ComObject`].
|
||||
///
|
||||
/// This trait links types that can be placed in `ComObject` with the types generated by the
|
||||
/// `#[implement]` macro. The `#[implement]` macro generates implementations of this trait.
|
||||
/// The generated types contain the vtable layouts and refcount-related fields for the COM
|
||||
/// object implementation.
|
||||
///
|
||||
/// This trait is an implementation detail of the Windows crates.
|
||||
/// User code should not deal directly with this trait.
|
||||
///
|
||||
/// This trait is sort of the reverse of [`IUnknownImpl`]. This trait allows user code to use
|
||||
/// [`ComObject<T>`] instead of `ComObject<T_Impl>`.
|
||||
pub trait ComObjectInner: Sized {
|
||||
/// The generated `<foo>_Impl` type (aka the "boxed" type or "outer" type).
|
||||
type Outer: IUnknownImpl<Impl = Self>;
|
||||
|
||||
/// Moves an instance of this type into a new ComObject box and returns it.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// It is important that safe Rust code never be able to acquire an owned instance of a
|
||||
/// generated "outer" COM object type, e.g. `<foo>_Impl`. This would be unsafe because the
|
||||
/// `<foo>_Impl` object contains a reference count field and provides methods that adjust
|
||||
/// the reference count, and destroy the object when the reference count reaches zero.
|
||||
///
|
||||
/// Safe Rust code must only be able to interact with these values by accessing them via a
|
||||
/// `ComObject` reference. `ComObject` handles adjusting reference counts and associates the
|
||||
/// lifetime of a `&<foo>_Impl` with the lifetime of the related `ComObject`.
|
||||
///
|
||||
/// The `#[implement]` macro generates the implementation of this `into_object` method.
|
||||
/// The generated `into_object` method encapsulates the construction of the `<foo>_Impl`
|
||||
/// object and immediately places it into the heap and returns a `ComObject` reference to it.
|
||||
/// This ensures that our requirement -- that safe Rust code never own a `<foo>_Impl` value
|
||||
/// directly -- is met.
|
||||
fn into_object(self) -> ComObject<Self>;
|
||||
}
|
||||
|
||||
/// Describes the COM interfaces implemented by a specific COM object.
|
||||
///
|
||||
/// The `#[implement]` macro generates implementations of this trait. Implementations are attached
|
||||
/// to the "outer" types generated by `#[implement]`, e.g. the `MyApp_Impl` type. Each
|
||||
/// implementation knows how to locate the interface-specific field within `MyApp_Impl`.
|
||||
///
|
||||
/// This trait is an implementation detail of the Windows crates.
|
||||
/// User code should not deal directly with this trait.
|
||||
pub trait ComObjectInterface<I: Interface> {
|
||||
/// Gets a borrowed interface that is implemented by `T`.
|
||||
fn as_interface_ref(&self) -> InterfaceRef<'_, I>;
|
||||
}
|
||||
|
||||
/// A counted pointer to a type that implements COM interfaces, where the object has been
|
||||
/// placed in the heap (boxed).
|
||||
///
|
||||
/// This type exists so that you can place an object into the heap and query for COM interfaces,
|
||||
/// without losing the safe reference to the implementation object.
|
||||
///
|
||||
/// Because the pointer inside this type is known to be non-null, `Option<ComObject<T>>` should
|
||||
/// always have the same size as a single pointer.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The contained `ptr` field is an owned, reference-counted pointer to a _pinned_ `Pin<Box<T::Outer>>`.
|
||||
/// Although this code does not currently use `Pin<T>`, it takes care not to expose any unsafe semantics
|
||||
/// to safe code. However, code that calls unsafe functions on [`ComObject`] must, like all unsafe code,
|
||||
/// understand and preserve invariants.
|
||||
#[repr(transparent)]
|
||||
pub struct ComObject<T: ComObjectInner> {
|
||||
ptr: NonNull<T::Outer>,
|
||||
}
|
||||
|
||||
impl<T: ComObjectInner> ComObject<T> {
|
||||
/// Allocates a heap cell (box) and moves `value` into it. Returns a counted pointer to `value`.
|
||||
pub fn new(value: T) -> Self {
|
||||
T::into_object(value)
|
||||
}
|
||||
|
||||
/// Creates a new `ComObject` that points to an existing boxed instance.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure that `ptr` points to a valid, heap-allocated instance of `T::Outer`.
|
||||
/// Normally, this pointer comes from using `Box::into_raw(Box::new(...))`.
|
||||
///
|
||||
/// The pointed-to box must have a reference count that is greater than zero.
|
||||
///
|
||||
/// This function takes ownership of the existing pointer; it does not call `AddRef`.
|
||||
/// The reference count must accurately reflect all outstanding references to the box,
|
||||
/// including `ptr` in the count.
|
||||
pub unsafe fn from_raw(ptr: NonNull<T::Outer>) -> Self {
|
||||
Self { ptr }
|
||||
}
|
||||
|
||||
/// Gets a reference to the shared object stored in the box.
|
||||
///
|
||||
/// [`ComObject`] also implements [`Deref`], so you can often deref directly into the object.
|
||||
/// For those situations where using the [`Deref`] impl is inconvenient, you can use
|
||||
/// this method to explicitly get a reference to the contents.
|
||||
#[inline(always)]
|
||||
pub fn get(&self) -> &T {
|
||||
self.get_box().get_impl()
|
||||
}
|
||||
|
||||
/// Gets a reference to the shared object's heap box.
|
||||
#[inline(always)]
|
||||
fn get_box(&self) -> &T::Outer {
|
||||
unsafe { self.ptr.as_ref() }
|
||||
}
|
||||
|
||||
// Note that we _do not_ provide a way to get a mutable reference to the outer box.
|
||||
// It's ok to return `&mut T`, but not `&mut T::Outer`. That would allow someone to replace the
|
||||
// contents of the entire object (box and reference count), which could lead to UB.
|
||||
// This could maybe be solved by returning `Pin<&mut T::Outer>`, but that requires some
|
||||
// additional thinking.
|
||||
|
||||
/// Gets a mutable reference to the object stored in the box, if the reference count
|
||||
/// is exactly 1. If there are multiple references to this object then this returns `None`.
|
||||
#[inline(always)]
|
||||
pub fn get_mut(&mut self) -> Option<&mut T> {
|
||||
if self.is_reference_count_one() {
|
||||
// SAFETY: We must only return &mut T, *NOT* &mut T::Outer.
|
||||
// Returning T::Outer would allow swapping the contents of the object, which would
|
||||
// allow (incorrectly) modifying the reference count.
|
||||
unsafe { Some(self.ptr.as_mut().get_impl_mut()) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// If this object has only a single object reference (i.e. this [`ComObject`] is the only
|
||||
/// reference to the heap allocation), then this method will extract the inner `T`
|
||||
/// (and return it in an `Ok`) and then free the heap allocation.
|
||||
///
|
||||
/// If there is more than one reference to this object, then this returns `Err(self)`.
|
||||
#[inline(always)]
|
||||
pub fn take(self) -> Result<T, Self> {
|
||||
if self.is_reference_count_one() {
|
||||
let outer_box: Box<T::Outer> = unsafe { core::mem::transmute(self) };
|
||||
Ok(outer_box.into_inner())
|
||||
} else {
|
||||
Err(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// Casts to a given interface type.
|
||||
///
|
||||
/// This always performs a `QueryInterface`, even if `T` is known to implement `I`.
|
||||
/// If you know that `T` implements `I`, then use [`Self::as_interface`] or [`Self::to_interface`] because
|
||||
/// those functions do not require a dynamic `QueryInterface` call.
|
||||
#[inline(always)]
|
||||
pub fn cast<I: Interface>(&self) -> windows_core::Result<I>
|
||||
where
|
||||
T::Outer: ComObjectInterface<IUnknown>,
|
||||
{
|
||||
let unknown = self.as_interface::<IUnknown>();
|
||||
unknown.cast()
|
||||
}
|
||||
|
||||
/// Gets a borrowed reference to an interface that is implemented by `T`.
|
||||
///
|
||||
/// The returned reference does not have an additional reference count.
|
||||
/// You can AddRef it by calling [`InterfaceRef::to_owned`].
|
||||
#[inline(always)]
|
||||
pub fn as_interface<I: Interface>(&self) -> InterfaceRef<'_, I>
|
||||
where
|
||||
T::Outer: ComObjectInterface<I>,
|
||||
{
|
||||
self.get_box().as_interface_ref()
|
||||
}
|
||||
|
||||
/// Gets an owned (counted) reference to an interface that is implemented by this [`ComObject`].
|
||||
#[inline(always)]
|
||||
pub fn to_interface<I: Interface>(&self) -> I
|
||||
where
|
||||
T::Outer: ComObjectInterface<I>,
|
||||
{
|
||||
self.as_interface::<I>().to_owned()
|
||||
}
|
||||
|
||||
/// Converts `self` into an interface that it implements.
|
||||
///
|
||||
/// This does not need to adjust reference counts because `self` is consumed.
|
||||
#[inline(always)]
|
||||
pub fn into_interface<I: Interface>(self) -> I
|
||||
where
|
||||
T::Outer: ComObjectInterface<I>,
|
||||
{
|
||||
unsafe {
|
||||
let raw = self.get_box().as_interface_ref().as_raw();
|
||||
core::mem::forget(self);
|
||||
I::from_raw(raw)
|
||||
}
|
||||
}
|
||||
|
||||
/// This casts the given COM interface to [`&dyn Any`]. It returns a reference to the "outer"
|
||||
/// object, e.g. `MyApp_Impl`, not the inner `MyApp` object.
|
||||
///
|
||||
/// `T` must be a type that has been annotated with `#[implement]`; this is checked at
|
||||
/// compile-time by the generic constraints of this method. However, note that the
|
||||
/// returned `&dyn Any` refers to the _outer_ implementation object that was generated by
|
||||
/// `#[implement]`, i.e. the `MyApp_Impl` type, not the inner `MyApp` type.
|
||||
///
|
||||
/// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust
|
||||
/// object that contains non-static lifetimes, then this function will return `Err(E_NOINTERFACE)`.
|
||||
///
|
||||
/// The returned value is an owned (counted) reference; this function calls `AddRef` on the
|
||||
/// underlying COM object. If you do not need an owned reference, then you can use the
|
||||
/// [`Interface::cast_object_ref`] method instead, and avoid the cost of `AddRef` / `Release`.
|
||||
pub fn cast_from<I>(interface: &I) -> crate::Result<Self>
|
||||
where
|
||||
I: Interface,
|
||||
T::Outer: Any + 'static + IUnknownImpl<Impl = T>,
|
||||
{
|
||||
interface.cast_object()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ComObjectInner + Default> Default for ComObject<T> {
|
||||
fn default() -> Self {
|
||||
Self::new(T::default())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ComObjectInner> Drop for ComObject<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
T::Outer::Release(self.ptr.as_ptr());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ComObjectInner> Clone for ComObject<T> {
|
||||
#[inline(always)]
|
||||
fn clone(&self) -> Self {
|
||||
unsafe {
|
||||
self.ptr.as_ref().AddRef();
|
||||
Self { ptr: self.ptr }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ComObjectInner> AsRef<T> for ComObject<T>
|
||||
where
|
||||
IUnknown: From<T> + AsImpl<T>,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &T {
|
||||
self.get()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ComObjectInner> Deref for ComObject<T> {
|
||||
type Target = T::Outer;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.get_box()
|
||||
}
|
||||
}
|
||||
|
||||
// There is no DerefMut implementation because we cannot statically guarantee
|
||||
// that the reference count is 1, which is a requirement for getting exclusive
|
||||
// access to the contents of the object. Use get_mut() for dynamically-checked
|
||||
// exclusive access.
|
||||
|
||||
impl<T: ComObjectInner> From<T> for ComObject<T> {
|
||||
fn from(value: T) -> ComObject<T> {
|
||||
ComObject::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
// Delegate hashing, if implemented.
|
||||
impl<T: ComObjectInner + core::hash::Hash> core::hash::Hash for ComObject<T> {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.get().hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
// If T is Send (or Sync) then the ComObject<T> is also Send (or Sync).
|
||||
// Since the actual object storage is in the heap, the object is never moved.
|
||||
unsafe impl<T: ComObjectInner + Send> Send for ComObject<T> {}
|
||||
unsafe impl<T: ComObjectInner + Sync> Sync for ComObject<T> {}
|
||||
|
||||
impl<T: ComObjectInner + PartialEq> PartialEq for ComObject<T> {
|
||||
fn eq(&self, other: &ComObject<T>) -> bool {
|
||||
let inner_self: &T = self.get();
|
||||
let other_self: &T = other.get();
|
||||
inner_self == other_self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ComObjectInner + Eq> Eq for ComObject<T> {}
|
||||
|
||||
impl<T: ComObjectInner + PartialOrd> PartialOrd for ComObject<T> {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
||||
let inner_self: &T = self.get();
|
||||
let other_self: &T = other.get();
|
||||
<T as PartialOrd>::partial_cmp(inner_self, other_self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ComObjectInner + Ord> Ord for ComObject<T> {
|
||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
|
||||
let inner_self: &T = self.get();
|
||||
let other_self: &T = other.get();
|
||||
<T as Ord>::cmp(inner_self, other_self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ComObjectInner + core::fmt::Debug> core::fmt::Debug for ComObject<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
<T as core::fmt::Debug>::fmt(self.get(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ComObjectInner + core::fmt::Display> core::fmt::Display for ComObject<T> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
<T as core::fmt::Display>::fmt(self.get(), f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ComObjectInner> Borrow<T> for ComObject<T> {
|
||||
fn borrow(&self) -> &T {
|
||||
self.get()
|
||||
}
|
||||
}
|
||||
159
third_party/rust/windows-core/src/error.rs
vendored
159
third_party/rust/windows-core/src/error.rs
vendored
@@ -1,159 +0,0 @@
|
||||
use super::*;
|
||||
|
||||
/// An error object consists of both an error code as well as detailed error information for debugging.
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct Error {
|
||||
pub(crate) code: HRESULT,
|
||||
pub(crate) info: Option<crate::imp::IRestrictedErrorInfo>,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// An error object without any failure information.
|
||||
pub const OK: Self = Self { code: HRESULT(0), info: None };
|
||||
|
||||
/// This creates a new WinRT error object, capturing the stack and other information about the
|
||||
/// point of failure.
|
||||
pub fn new(code: HRESULT, message: HSTRING) -> Self {
|
||||
unsafe {
|
||||
if let Some(function) = crate::imp::delay_load::<RoOriginateError>(s!("combase.dll"), s!("RoOriginateError")) {
|
||||
function(code, std::mem::transmute_copy(&message));
|
||||
}
|
||||
let info = GetErrorInfo().and_then(|e| e.cast()).ok();
|
||||
Self { code, info }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_win32() -> Self {
|
||||
unsafe { Self { code: HRESULT::from_win32(crate::imp::GetLastError()), info: None } }
|
||||
}
|
||||
|
||||
/// The error code describing the error.
|
||||
pub const fn code(&self) -> HRESULT {
|
||||
self.code
|
||||
}
|
||||
|
||||
/// The error information describing the error.
|
||||
pub const fn info(&self) -> &Option<crate::imp::IRestrictedErrorInfo> {
|
||||
&self.info
|
||||
}
|
||||
|
||||
/// The error message describing the error.
|
||||
pub fn message(&self) -> HSTRING {
|
||||
// First attempt to retrieve the restricted error information.
|
||||
if let Some(info) = &self.info {
|
||||
let mut fallback = BSTR::default();
|
||||
let mut message = BSTR::default();
|
||||
let mut code = HRESULT(0);
|
||||
|
||||
unsafe {
|
||||
let _ = info.GetErrorDetails(&mut fallback, &mut code, &mut message, &mut BSTR::default());
|
||||
}
|
||||
|
||||
if self.code == code {
|
||||
let message = if !message.is_empty() { message } else { fallback };
|
||||
return HSTRING::from_wide(crate::imp::wide_trim_end(message.as_wide())).unwrap_or_default();
|
||||
}
|
||||
}
|
||||
|
||||
self.code.message()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<Error> for HRESULT {
|
||||
fn from(error: Error) -> Self {
|
||||
let code = error.code;
|
||||
let info: Option<crate::imp::IErrorInfo> = error.info.and_then(|info| info.cast().ok());
|
||||
|
||||
unsafe {
|
||||
let _ = crate::imp::SetErrorInfo(0, info.as_ref());
|
||||
}
|
||||
|
||||
code
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<Error> for std::io::Error {
|
||||
fn from(from: Error) -> Self {
|
||||
Self::from_raw_os_error(from.code.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::string::FromUtf16Error> for Error {
|
||||
fn from(_: std::string::FromUtf16Error) -> Self {
|
||||
Self { code: HRESULT::from_win32(crate::imp::ERROR_NO_UNICODE_TRANSLATION), info: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::string::FromUtf8Error> for Error {
|
||||
fn from(_: std::string::FromUtf8Error) -> Self {
|
||||
Self { code: HRESULT::from_win32(crate::imp::ERROR_NO_UNICODE_TRANSLATION), info: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::num::TryFromIntError> for Error {
|
||||
fn from(_: std::num::TryFromIntError) -> Self {
|
||||
Self { code: HRESULT(crate::imp::E_INVALIDARG), info: None }
|
||||
}
|
||||
}
|
||||
|
||||
// Unfortunately this is needed to make types line up. The Rust type system does
|
||||
// not know the `Infallible` can never be constructed. This code needs to be here
|
||||
// to satesify the type checker but it will never be run. Once `!` is stabilizied
|
||||
// this can be removed.
|
||||
impl std::convert::From<std::convert::Infallible> for Error {
|
||||
fn from(_: std::convert::Infallible) -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<HRESULT> for Error {
|
||||
fn from(code: HRESULT) -> Self {
|
||||
let info: Option<crate::imp::IRestrictedErrorInfo> = GetErrorInfo().and_then(|e| e.cast()).ok();
|
||||
|
||||
if let Some(info) = info {
|
||||
// If it does (and therefore running on a recent version of Windows)
|
||||
// then capture_propagation_context adds a breadcrumb to the error
|
||||
// info to make debugging easier.
|
||||
if let Ok(capture) = info.cast::<crate::imp::ILanguageExceptionErrorInfo2>() {
|
||||
unsafe {
|
||||
let _ = capture.CapturePropagationContext(None);
|
||||
}
|
||||
}
|
||||
|
||||
return Self { code, info: Some(info) };
|
||||
}
|
||||
|
||||
if let Ok(info) = GetErrorInfo() {
|
||||
let message = unsafe { info.GetDescription().unwrap_or_default() };
|
||||
Self::new(code, HSTRING::from_wide(message.as_wide()).unwrap_or_default())
|
||||
} else {
|
||||
Self { code, info: None }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Error {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut debug = fmt.debug_struct("Error");
|
||||
debug.field("code", &self.code).field("message", &self.message()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let message = self.message();
|
||||
if message.is_empty() {
|
||||
std::write!(fmt, "{}", self.code())
|
||||
} else {
|
||||
std::write!(fmt, "{} ({})", self.message(), self.code())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
type RoOriginateError = extern "system" fn(code: HRESULT, message: *mut std::ffi::c_void) -> i32;
|
||||
|
||||
fn GetErrorInfo() -> Result<crate::imp::IErrorInfo> {
|
||||
unsafe { crate::imp::GetErrorInfo(0) }
|
||||
}
|
||||
115
third_party/rust/windows-core/src/event.rs
vendored
115
third_party/rust/windows-core/src/event.rs
vendored
@@ -1,26 +1,34 @@
|
||||
use super::*;
|
||||
use std::sync::*;
|
||||
use core::ffi::c_void;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::{size_of, transmute_copy};
|
||||
use core::ptr::null_mut;
|
||||
use std::sync::Mutex;
|
||||
|
||||
/// A type that you can use to declare and implement an event of a specified delegate type.
|
||||
///
|
||||
/// The implementation is thread-safe and designed to avoid contention between events being
|
||||
/// raised and delegates being added or removed.
|
||||
pub struct Event<T: ComInterface> {
|
||||
pub struct Event<T: Interface> {
|
||||
swap: Mutex<()>,
|
||||
change: Mutex<()>,
|
||||
delegates: Array<T>,
|
||||
}
|
||||
|
||||
impl<T: ComInterface> Default for Event<T> {
|
||||
impl<T: Interface> Default for Event<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ComInterface> Event<T> {
|
||||
impl<T: Interface> Event<T> {
|
||||
/// Creates a new, empty `Event<T>`.
|
||||
pub fn new() -> Self {
|
||||
Self { delegates: Array::new(), swap: Mutex::default(), change: Mutex::default() }
|
||||
Self {
|
||||
delegates: Array::new(),
|
||||
swap: Mutex::default(),
|
||||
change: Mutex::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Registers a delegate with the event object.
|
||||
@@ -99,7 +107,10 @@ impl<T: ComInterface> Event<T> {
|
||||
for delegate in lock_free_calls.as_slice() {
|
||||
if let Err(error) = delegate.call(&mut callback) {
|
||||
const RPC_E_SERVER_UNAVAILABLE: HRESULT = HRESULT(-2147023174); // HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)
|
||||
if matches!(error.code(), crate::imp::RPC_E_DISCONNECTED | crate::imp::JSCRIPT_E_CANTEXECUTE | RPC_E_SERVER_UNAVAILABLE) {
|
||||
if matches!(
|
||||
error.code(),
|
||||
imp::RPC_E_DISCONNECTED | imp::JSCRIPT_E_CANTEXECUTE | RPC_E_SERVER_UNAVAILABLE
|
||||
) {
|
||||
self.remove(delegate.to_token())?;
|
||||
}
|
||||
}
|
||||
@@ -109,33 +120,41 @@ impl<T: ComInterface> Event<T> {
|
||||
}
|
||||
|
||||
/// A thread-safe reference-counted array of delegates.
|
||||
struct Array<T: ComInterface> {
|
||||
struct Array<T: Interface> {
|
||||
buffer: *mut Buffer<T>,
|
||||
len: usize,
|
||||
_phantom: std::marker::PhantomData<T>,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T: ComInterface> Default for Array<T> {
|
||||
impl<T: Interface> Default for Array<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ComInterface> Array<T> {
|
||||
impl<T: Interface> Array<T> {
|
||||
/// Creates a new, empty `Array<T>` with no capacity.
|
||||
fn new() -> Self {
|
||||
Self { buffer: std::ptr::null_mut(), len: 0, _phantom: std::marker::PhantomData }
|
||||
Self {
|
||||
buffer: null_mut(),
|
||||
len: 0,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new, empty `Array<T>` with the specified capacity.
|
||||
fn with_capacity(capacity: usize) -> Result<Self> {
|
||||
Ok(Self { buffer: Buffer::new(capacity)?, len: 0, _phantom: std::marker::PhantomData })
|
||||
Ok(Self {
|
||||
buffer: Buffer::new(capacity)?,
|
||||
len: 0,
|
||||
_phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// Swaps the contents of two `Array<T>` objects.
|
||||
fn swap(&mut self, mut other: Self) -> Self {
|
||||
unsafe { std::ptr::swap(&mut self.buffer, &mut other.buffer) };
|
||||
std::mem::swap(&mut self.len, &mut other.len);
|
||||
unsafe { core::ptr::swap(&mut self.buffer, &mut other.buffer) };
|
||||
core::mem::swap(&mut self.len, &mut other.len);
|
||||
other
|
||||
}
|
||||
|
||||
@@ -152,7 +171,7 @@ impl<T: ComInterface> Array<T> {
|
||||
/// Appends a delegate to the back of the array.
|
||||
fn push(&mut self, delegate: Delegate<T>) {
|
||||
unsafe {
|
||||
std::ptr::write((*self.buffer).as_mut_ptr().add(self.len), delegate);
|
||||
(*self.buffer).as_mut_ptr().add(self.len).write(delegate);
|
||||
self.len += 1;
|
||||
}
|
||||
}
|
||||
@@ -162,7 +181,7 @@ impl<T: ComInterface> Array<T> {
|
||||
if self.is_empty() {
|
||||
&[]
|
||||
} else {
|
||||
unsafe { std::slice::from_raw_parts((*self.buffer).as_ptr(), self.len) }
|
||||
unsafe { core::slice::from_raw_parts((*self.buffer).as_ptr(), self.len) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,26 +190,30 @@ impl<T: ComInterface> Array<T> {
|
||||
if self.is_empty() {
|
||||
&mut []
|
||||
} else {
|
||||
unsafe { std::slice::from_raw_parts_mut((*self.buffer).as_mut_ptr(), self.len) }
|
||||
unsafe { core::slice::from_raw_parts_mut((*self.buffer).as_mut_ptr(), self.len) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ComInterface> Clone for Array<T> {
|
||||
impl<T: Interface> Clone for Array<T> {
|
||||
fn clone(&self) -> Self {
|
||||
if !self.is_empty() {
|
||||
unsafe { (*self.buffer).0.add_ref() };
|
||||
}
|
||||
Self { buffer: self.buffer, len: self.len, _phantom: std::marker::PhantomData }
|
||||
Self {
|
||||
buffer: self.buffer,
|
||||
len: self.len,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ComInterface> Drop for Array<T> {
|
||||
impl<T: Interface> Drop for Array<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if !self.is_empty() && (*self.buffer).0.release() == 0 {
|
||||
std::ptr::drop_in_place(self.as_mut_slice());
|
||||
crate::imp::heap_free(self.buffer as _)
|
||||
core::ptr::drop_in_place(self.as_mut_slice());
|
||||
heap_free(self.buffer as _)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -198,18 +221,19 @@ impl<T: ComInterface> Drop for Array<T> {
|
||||
|
||||
/// A reference-counted buffer.
|
||||
#[repr(C)]
|
||||
struct Buffer<T>(crate::imp::RefCount, std::marker::PhantomData<T>);
|
||||
#[repr(align(8))]
|
||||
struct Buffer<T>(imp::RefCount, PhantomData<T>);
|
||||
|
||||
impl<T: ComInterface> Buffer<T> {
|
||||
impl<T: Interface> Buffer<T> {
|
||||
/// Creates a new `Buffer` with the specified size in bytes.
|
||||
fn new(len: usize) -> Result<*mut Self> {
|
||||
if len == 0 {
|
||||
Ok(std::ptr::null_mut())
|
||||
Ok(null_mut())
|
||||
} else {
|
||||
let alloc_size = std::mem::size_of::<Self>() + len * std::mem::size_of::<Delegate<T>>();
|
||||
let header = crate::imp::heap_alloc(alloc_size)? as *mut Self;
|
||||
let alloc_size = size_of::<Self>() + len * size_of::<Delegate<T>>();
|
||||
let header = heap_alloc(alloc_size)? as *mut Self;
|
||||
unsafe {
|
||||
header.write(Self(crate::imp::RefCount::new(1), std::marker::PhantomData));
|
||||
header.write(Self(imp::RefCount::new(1), PhantomData));
|
||||
}
|
||||
Ok(header)
|
||||
}
|
||||
@@ -234,10 +258,10 @@ enum Delegate<T> {
|
||||
Indirect(AgileReference<T>),
|
||||
}
|
||||
|
||||
impl<T: ComInterface> Delegate<T> {
|
||||
impl<T: Interface> Delegate<T> {
|
||||
/// Creates a new `Delegate<T>`, containing a suitable reference to the specified delegate.
|
||||
fn new(delegate: &T) -> Result<Self> {
|
||||
if delegate.cast::<crate::imp::IAgileObject>().is_ok() {
|
||||
if delegate.cast::<imp::IAgileObject>().is_ok() {
|
||||
Ok(Self::Direct(delegate.clone()))
|
||||
} else {
|
||||
Ok(Self::Indirect(AgileReference::new(delegate)?))
|
||||
@@ -248,8 +272,8 @@ impl<T: ComInterface> Delegate<T> {
|
||||
fn to_token(&self) -> i64 {
|
||||
unsafe {
|
||||
match self {
|
||||
Self::Direct(delegate) => crate::imp::EncodePointer(std::mem::transmute_copy(delegate)) as i64,
|
||||
Self::Indirect(delegate) => crate::imp::EncodePointer(std::mem::transmute_copy(delegate)) as i64,
|
||||
Self::Direct(delegate) => imp::EncodePointer(transmute_copy(delegate)) as i64,
|
||||
Self::Indirect(delegate) => imp::EncodePointer(transmute_copy(delegate)) as i64,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,3 +286,30 @@ impl<T: ComInterface> Delegate<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Allocate memory of size `bytes` using `malloc` - the `Event` implementation does not
|
||||
/// need to use any particular allocator so `HeapAlloc` need not be used.
|
||||
fn heap_alloc(bytes: usize) -> crate::Result<*mut c_void> {
|
||||
let ptr: *mut c_void = unsafe {
|
||||
extern "C" {
|
||||
fn malloc(bytes: usize) -> *mut c_void;
|
||||
}
|
||||
|
||||
malloc(bytes)
|
||||
};
|
||||
|
||||
if ptr.is_null() {
|
||||
Err(Error::from_hresult(imp::E_OUTOFMEMORY))
|
||||
} else {
|
||||
Ok(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
/// Free memory allocated by `heap_alloc`.
|
||||
unsafe fn heap_free(ptr: *mut c_void) {
|
||||
extern "C" {
|
||||
fn free(ptr: *mut c_void);
|
||||
}
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
89
third_party/rust/windows-core/src/guid.rs
vendored
89
third_party/rust/windows-core/src/guid.rs
vendored
@@ -7,9 +7,16 @@ use super::*;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Default, PartialEq, Eq, Hash)]
|
||||
pub struct GUID {
|
||||
/// Specifies the first 8 hexadecimal digits.
|
||||
pub data1: u32,
|
||||
|
||||
/// Specifies the first group of 4 hexadecimal digits.
|
||||
pub data2: u16,
|
||||
|
||||
/// Specifies the second group of 4 hexadecimal digits.
|
||||
pub data3: u16,
|
||||
|
||||
/// The first 2 bytes contain the third group of 4 hexadecimal digits. The remaining 6 bytes contain the final 12 hexadecimal digits.
|
||||
pub data4: [u8; 8],
|
||||
}
|
||||
|
||||
@@ -21,27 +28,48 @@ impl GUID {
|
||||
|
||||
/// Creates a `GUID` represented by the all-zero byte-pattern.
|
||||
pub const fn zeroed() -> Self {
|
||||
Self { data1: 0, data2: 0, data3: 0, data4: [0, 0, 0, 0, 0, 0, 0, 0] }
|
||||
Self {
|
||||
data1: 0,
|
||||
data2: 0,
|
||||
data3: 0,
|
||||
data4: [0, 0, 0, 0, 0, 0, 0, 0],
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a `GUID` with the given constant values.
|
||||
pub const fn from_values(data1: u32, data2: u16, data3: u16, data4: [u8; 8]) -> Self {
|
||||
Self { data1, data2, data3, data4 }
|
||||
Self {
|
||||
data1,
|
||||
data2,
|
||||
data3,
|
||||
data4,
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a `GUID` from a `u128` value.
|
||||
pub const fn from_u128(uuid: u128) -> Self {
|
||||
Self { data1: (uuid >> 96) as u32, data2: (uuid >> 80 & 0xffff) as u16, data3: (uuid >> 64 & 0xffff) as u16, data4: (uuid as u64).to_be_bytes() }
|
||||
Self {
|
||||
data1: (uuid >> 96) as u32,
|
||||
data2: (uuid >> 80 & 0xffff) as u16,
|
||||
data3: (uuid >> 64 & 0xffff) as u16,
|
||||
data4: (uuid as u64).to_be_bytes(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a `GUID` to a `u128` value.
|
||||
pub const fn to_u128(&self) -> u128 {
|
||||
((self.data1 as u128) << 96) + ((self.data2 as u128) << 80) + ((self.data3 as u128) << 64) + u64::from_be_bytes(self.data4) as u128
|
||||
((self.data1 as u128) << 96)
|
||||
+ ((self.data2 as u128) << 80)
|
||||
+ ((self.data3 as u128) << 64)
|
||||
+ u64::from_be_bytes(self.data4) as u128
|
||||
}
|
||||
|
||||
/// Creates a `GUID` for a "generic" WinRT type.
|
||||
pub const fn from_signature(signature: imp::ConstBuffer) -> Self {
|
||||
let data = imp::ConstBuffer::from_slice(&[0x11, 0xf4, 0x7a, 0xd5, 0x7b, 0x73, 0x42, 0xc0, 0xab, 0xae, 0x87, 0x8b, 0x1e, 0x16, 0xad, 0xee]);
|
||||
let data = imp::ConstBuffer::from_slice(&[
|
||||
0x11, 0xf4, 0x7a, 0xd5, 0x7b, 0x73, 0x42, 0xc0, 0xab, 0xae, 0x87, 0x8b, 0x1e, 0x16,
|
||||
0xad, 0xee,
|
||||
]);
|
||||
|
||||
let data = data.push_other(signature);
|
||||
|
||||
@@ -53,7 +81,14 @@ impl GUID {
|
||||
third = (third & 0x0fff) | (5 << 12);
|
||||
let fourth = (bytes[8] & 0x3f) | 0x80;
|
||||
|
||||
Self::from_values(first, second, third, [fourth, bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]])
|
||||
Self::from_values(
|
||||
first,
|
||||
second,
|
||||
third,
|
||||
[
|
||||
fourth, bytes[9], bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15],
|
||||
],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,22 +100,44 @@ impl TypeKind for GUID {
|
||||
type TypeKind = CopyType;
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for GUID {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:08X?}-{:04X?}-{:04X?}-{:02X?}{:02X?}-{:02X?}{:02X?}{:02X?}{:02X?}{:02X?}{:02X?}", self.data1, self.data2, self.data3, self.data4[0], self.data4[1], self.data4[2], self.data4[3], self.data4[4], self.data4[5], self.data4[6], self.data4[7])
|
||||
impl core::fmt::Debug for GUID {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{:08X?}-{:04X?}-{:04X?}-{:02X?}{:02X?}-{:02X?}{:02X?}{:02X?}{:02X?}{:02X?}{:02X?}",
|
||||
self.data1,
|
||||
self.data2,
|
||||
self.data3,
|
||||
self.data4[0],
|
||||
self.data4[1],
|
||||
self.data4[2],
|
||||
self.data4[3],
|
||||
self.data4[4],
|
||||
self.data4[5],
|
||||
self.data4[6],
|
||||
self.data4[7]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&str> for GUID {
|
||||
impl From<&str> for GUID {
|
||||
fn from(value: &str) -> Self {
|
||||
assert!(value.len() == 36, "Invalid GUID string");
|
||||
let mut bytes = value.bytes();
|
||||
|
||||
let a = ((bytes.next_u32() * 16 + bytes.next_u32()) << 24) + ((bytes.next_u32() * 16 + bytes.next_u32()) << 16) + ((bytes.next_u32() * 16 + bytes.next_u32()) << 8) + bytes.next_u32() * 16 + bytes.next_u32();
|
||||
let a = ((bytes.next_u32() * 16 + bytes.next_u32()) << 24)
|
||||
+ ((bytes.next_u32() * 16 + bytes.next_u32()) << 16)
|
||||
+ ((bytes.next_u32() * 16 + bytes.next_u32()) << 8)
|
||||
+ bytes.next_u32() * 16
|
||||
+ bytes.next_u32();
|
||||
assert!(bytes.next().unwrap() == b'-', "Invalid GUID string");
|
||||
let b = ((bytes.next_u16() * 16 + (bytes.next_u16())) << 8) + bytes.next_u16() * 16 + bytes.next_u16();
|
||||
let b = ((bytes.next_u16() * 16 + (bytes.next_u16())) << 8)
|
||||
+ bytes.next_u16() * 16
|
||||
+ bytes.next_u16();
|
||||
assert!(bytes.next().unwrap() == b'-', "Invalid GUID string");
|
||||
let c = ((bytes.next_u16() * 16 + bytes.next_u16()) << 8) + bytes.next_u16() * 16 + bytes.next_u16();
|
||||
let c = ((bytes.next_u16() * 16 + bytes.next_u16()) << 8)
|
||||
+ bytes.next_u16() * 16
|
||||
+ bytes.next_u16();
|
||||
assert!(bytes.next().unwrap() == b'-', "Invalid GUID string");
|
||||
let d = bytes.next_u8() * 16 + bytes.next_u8();
|
||||
let e = bytes.next_u8() * 16 + bytes.next_u8();
|
||||
@@ -97,13 +154,13 @@ impl std::convert::From<&str> for GUID {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<u128> for GUID {
|
||||
impl From<u128> for GUID {
|
||||
fn from(value: u128) -> Self {
|
||||
Self::from_u128(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<GUID> for u128 {
|
||||
impl From<GUID> for u128 {
|
||||
fn from(value: GUID) -> Self {
|
||||
value.to_u128()
|
||||
}
|
||||
@@ -115,7 +172,7 @@ trait HexReader {
|
||||
fn next_u32(&mut self) -> u32;
|
||||
}
|
||||
|
||||
impl HexReader for std::str::Bytes<'_> {
|
||||
impl HexReader for core::str::Bytes<'_> {
|
||||
fn next_u8(&mut self) -> u8 {
|
||||
let value = self.next().unwrap();
|
||||
match value {
|
||||
|
||||
46
third_party/rust/windows-core/src/handles.rs
vendored
Normal file
46
third_party/rust/windows-core/src/handles.rs
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
/// Custom code to free a handle.
|
||||
///
|
||||
/// This is similar to the [`Drop`] trait, and may be used to implement [`Drop`], but allows handles
|
||||
/// to be dropped depending on context.
|
||||
pub trait Free {
|
||||
/// Calls the handle's free function.
|
||||
///
|
||||
/// # Safety
|
||||
/// The handle must be owned by the caller and safe to free.
|
||||
unsafe fn free(&mut self);
|
||||
}
|
||||
|
||||
/// A wrapper to provide ownership for handles to automatically drop via the handle's [`Free`] trait.
|
||||
#[repr(transparent)]
|
||||
#[derive(PartialEq, Eq, Default, Debug)]
|
||||
pub struct Owned<T: Free>(T);
|
||||
|
||||
impl<T: Free> Owned<T> {
|
||||
/// Takes ownership of the handle.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The handle must be owned by the caller and safe to free.
|
||||
pub unsafe fn new(x: T) -> Self {
|
||||
Self(x)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Free> Drop for Owned<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { self.0.free() };
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Free> core::ops::Deref for Owned<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Free> core::ops::DerefMut for Owned<T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.0
|
||||
}
|
||||
}
|
||||
140
third_party/rust/windows-core/src/hresult.rs
vendored
140
third_party/rust/windows-core/src/hresult.rs
vendored
@@ -1,140 +0,0 @@
|
||||
use super::*;
|
||||
|
||||
/// An error code value returned by most COM functions.
|
||||
#[repr(transparent)]
|
||||
#[derive(Copy, Clone, Default, Eq, PartialEq)]
|
||||
#[must_use]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct HRESULT(pub i32);
|
||||
|
||||
impl HRESULT {
|
||||
/// Returns [`true`] if `self` is a success code.
|
||||
#[inline]
|
||||
pub const fn is_ok(self) -> bool {
|
||||
self.0 >= 0
|
||||
}
|
||||
|
||||
/// Returns [`true`] if `self` is a failure code.
|
||||
#[inline]
|
||||
pub const fn is_err(self) -> bool {
|
||||
!self.is_ok()
|
||||
}
|
||||
|
||||
/// Asserts that `self` is a success code.
|
||||
///
|
||||
/// This will invoke the [`panic!`] macro if `self` is a failure code and display
|
||||
/// the [`HRESULT`] value for diagnostics.
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn unwrap(self) {
|
||||
assert!(self.is_ok(), "HRESULT 0x{:X}", self.0);
|
||||
}
|
||||
|
||||
/// Converts the [`HRESULT`] to [`Result<()>`][Result<_>].
|
||||
#[inline]
|
||||
pub fn ok(self) -> Result<()> {
|
||||
if self.is_ok() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::from(self))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the [`Option`] as a [`Result`] if the option is a [`Some`] value, returning
|
||||
/// a suitable error if not.
|
||||
pub fn and_some<T: Interface>(self, some: Option<T>) -> Result<T> {
|
||||
if self.is_ok() {
|
||||
if let Some(result) = some {
|
||||
Ok(result)
|
||||
} else {
|
||||
Err(Error::OK)
|
||||
}
|
||||
} else {
|
||||
Err(Error::from(self))
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls `op` if `self` is a success code, otherwise returns [`HRESULT`]
|
||||
/// converted to [`Result<T>`].
|
||||
#[inline]
|
||||
pub fn and_then<F, T>(self, op: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
{
|
||||
self.ok()?;
|
||||
Ok(op())
|
||||
}
|
||||
|
||||
/// If the [`Result`] is [`Ok`] converts the `T::Abi` into `T`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Safe to call if
|
||||
/// * `abi` is initialized if `self` is `Ok`
|
||||
/// * `abi` can be safely transmuted to `T`
|
||||
pub unsafe fn from_abi<T: Type<T>>(self, abi: T::Abi) -> Result<T> {
|
||||
if self.is_ok() {
|
||||
T::from_abi(abi)
|
||||
} else {
|
||||
Err(Error::from(self))
|
||||
}
|
||||
}
|
||||
|
||||
/// The error message describing the error.
|
||||
pub fn message(&self) -> HSTRING {
|
||||
let mut message = HeapString(std::ptr::null_mut());
|
||||
|
||||
unsafe {
|
||||
let size = crate::imp::FormatMessageW(crate::imp::FORMAT_MESSAGE_ALLOCATE_BUFFER | crate::imp::FORMAT_MESSAGE_FROM_SYSTEM | crate::imp::FORMAT_MESSAGE_IGNORE_INSERTS, std::ptr::null(), self.0 as u32, 0, &mut message.0 as *mut _ as *mut _, 0, std::ptr::null());
|
||||
|
||||
HSTRING::from_wide(crate::imp::wide_trim_end(std::slice::from_raw_parts(message.0 as *const u16, size as usize))).unwrap_or_default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps a Win32 error code to an HRESULT value.
|
||||
pub const fn from_win32(error: u32) -> Self {
|
||||
Self(if error as i32 <= 0 { error } else { (error & 0x0000_FFFF) | (7 << 16) | 0x8000_0000 } as i32)
|
||||
}
|
||||
}
|
||||
|
||||
impl RuntimeType for HRESULT {
|
||||
const SIGNATURE: crate::imp::ConstBuffer = crate::imp::ConstBuffer::from_slice(b"struct(Windows.Foundation.HResult;i32)");
|
||||
}
|
||||
|
||||
impl TypeKind for HRESULT {
|
||||
type TypeKind = CopyType;
|
||||
}
|
||||
|
||||
impl<T> std::convert::From<Result<T>> for HRESULT {
|
||||
fn from(result: Result<T>) -> Self {
|
||||
if let Err(error) = result {
|
||||
return error.into();
|
||||
}
|
||||
|
||||
HRESULT(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for HRESULT {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!("{:#010X}", self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for HRESULT {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!("HRESULT({})", self))
|
||||
}
|
||||
}
|
||||
|
||||
struct HeapString(*mut u16);
|
||||
|
||||
impl Drop for HeapString {
|
||||
fn drop(&mut self) {
|
||||
if !self.0.is_null() {
|
||||
unsafe {
|
||||
crate::imp::heap_free(self.0 as _);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
710
third_party/rust/windows-core/src/imp/bindings.rs
vendored
710
third_party/rust/windows-core/src/imp/bindings.rs
vendored
@@ -1,53 +1,671 @@
|
||||
// Bindings generated by `windows-bindgen` 0.52.0
|
||||
|
||||
#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
|
||||
::windows_targets::link!("kernel32.dll" "system" fn CloseHandle(hobject : HANDLE) -> BOOL);
|
||||
::windows_targets::link!("kernel32.dll" "system" fn CreateEventW(lpeventattributes : *const SECURITY_ATTRIBUTES, bmanualreset : BOOL, binitialstate : BOOL, lpname : PCWSTR) -> HANDLE);
|
||||
::windows_targets::link!("kernel32.dll" "system" fn EncodePointer(ptr : *const ::core::ffi::c_void) -> *mut ::core::ffi::c_void);
|
||||
::windows_targets::link!("kernel32.dll" "system" fn FormatMessageW(dwflags : FORMAT_MESSAGE_OPTIONS, lpsource : *const ::core::ffi::c_void, dwmessageid : u32, dwlanguageid : u32, lpbuffer : PWSTR, nsize : u32, arguments : *const *const i8) -> u32);
|
||||
::windows_targets::link!("kernel32.dll" "system" fn FreeLibrary(hlibmodule : HMODULE) -> BOOL);
|
||||
::windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> WIN32_ERROR);
|
||||
::windows_targets::link!("kernel32.dll" "system" fn GetProcAddress(hmodule : HMODULE, lpprocname : PCSTR) -> FARPROC);
|
||||
::windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> HANDLE);
|
||||
::windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap : HANDLE, dwflags : HEAP_FLAGS, dwbytes : usize) -> *mut ::core::ffi::c_void);
|
||||
::windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap : HANDLE, dwflags : HEAP_FLAGS, lpmem : *const ::core::ffi::c_void) -> BOOL);
|
||||
::windows_targets::link!("kernel32.dll" "system" fn LoadLibraryExA(lplibfilename : PCSTR, hfile : HANDLE, dwflags : LOAD_LIBRARY_FLAGS) -> HMODULE);
|
||||
::windows_targets::link!("kernel32.dll" "system" fn SetEvent(hevent : HANDLE) -> BOOL);
|
||||
::windows_targets::link!("kernel32.dll" "system" fn WaitForSingleObject(hhandle : HANDLE, dwmilliseconds : u32) -> WAIT_EVENT);
|
||||
::windows_targets::link!("ole32.dll" "system" fn CoTaskMemAlloc(cb : usize) -> *mut ::core::ffi::c_void);
|
||||
::windows_targets::link!("ole32.dll" "system" fn CoTaskMemFree(pv : *const ::core::ffi::c_void) -> ());
|
||||
::windows_targets::link!("oleaut32.dll" "system" fn SysAllocStringLen(strin : PCWSTR, ui : u32) -> BSTR);
|
||||
::windows_targets::link!("oleaut32.dll" "system" fn SysFreeString(bstrstring : BSTR) -> ());
|
||||
::windows_targets::link!("oleaut32.dll" "system" fn SysStringLen(pbstr : BSTR) -> u32);
|
||||
#![allow(
|
||||
non_snake_case,
|
||||
non_upper_case_globals,
|
||||
non_camel_case_types,
|
||||
dead_code,
|
||||
clippy::all
|
||||
)]
|
||||
windows_targets::link!("api-ms-win-core-winrt-l1-1-0.dll" "system" fn RoGetActivationFactory(activatableclassid : * mut core::ffi::c_void, iid : *const GUID, factory : *mut *mut core::ffi::c_void) -> HRESULT);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CloseHandle(hobject : HANDLE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn CreateEventW(lpeventattributes : *const SECURITY_ATTRIBUTES, bmanualreset : BOOL, binitialstate : BOOL, lpname : PCWSTR) -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn EncodePointer(ptr : *const core::ffi::c_void) -> *mut core::ffi::c_void);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FreeLibrary(hlibmodule : HMODULE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetProcAddress(hmodule : HMODULE, lpprocname : PCSTR) -> FARPROC);
|
||||
windows_targets::link!("kernel32.dll" "system" fn LoadLibraryExA(lplibfilename : PCSTR, hfile : HANDLE, dwflags : LOAD_LIBRARY_FLAGS) -> HMODULE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn SetEvent(hevent : HANDLE) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn WaitForSingleObject(hhandle : HANDLE, dwmilliseconds : u32) -> WAIT_EVENT);
|
||||
windows_targets::link!("ole32.dll" "system" fn CoIncrementMTAUsage(pcookie : *mut CO_MTA_USAGE_COOKIE) -> HRESULT);
|
||||
windows_targets::link!("ole32.dll" "system" fn CoTaskMemAlloc(cb : usize) -> *mut core::ffi::c_void);
|
||||
windows_targets::link!("ole32.dll" "system" fn CoTaskMemFree(pv : *const core::ffi::c_void));
|
||||
windows_targets::link!("ole32.dll" "system" fn PropVariantClear(pvar : *mut PROPVARIANT) -> HRESULT);
|
||||
windows_targets::link!("ole32.dll" "system" fn PropVariantCopy(pvardest : *mut PROPVARIANT, pvarsrc : *const PROPVARIANT) -> HRESULT);
|
||||
windows_targets::link!("oleaut32.dll" "system" fn VariantClear(pvarg : *mut VARIANT) -> HRESULT);
|
||||
windows_targets::link!("oleaut32.dll" "system" fn VariantCopy(pvargdest : *mut VARIANT, pvargsrc : *const VARIANT) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn PropVariantCompareEx(propvar1 : *const PROPVARIANT, propvar2 : *const PROPVARIANT, unit : PROPVAR_COMPARE_UNIT, flags : PROPVAR_COMPARE_FLAGS) -> i32);
|
||||
windows_targets::link!("propsys.dll" "system" fn PropVariantToBSTR(propvar : *const PROPVARIANT, pbstrout : *mut BSTR) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn PropVariantToBoolean(propvarin : *const PROPVARIANT, pfret : *mut BOOL) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn PropVariantToDouble(propvarin : *const PROPVARIANT, pdblret : *mut f64) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn PropVariantToInt16(propvarin : *const PROPVARIANT, piret : *mut i16) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn PropVariantToInt32(propvarin : *const PROPVARIANT, plret : *mut i32) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn PropVariantToInt64(propvarin : *const PROPVARIANT, pllret : *mut i64) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn PropVariantToUInt16(propvarin : *const PROPVARIANT, puiret : *mut u16) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn PropVariantToUInt32(propvarin : *const PROPVARIANT, pulret : *mut u32) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn PropVariantToUInt64(propvarin : *const PROPVARIANT, pullret : *mut u64) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn PropVariantToVariant(ppropvar : *const PROPVARIANT, pvar : *mut VARIANT) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn VariantToBoolean(varin : *const VARIANT, pfret : *mut BOOL) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn VariantToDouble(varin : *const VARIANT, pdblret : *mut f64) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn VariantToInt16(varin : *const VARIANT, piret : *mut i16) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn VariantToInt32(varin : *const VARIANT, plret : *mut i32) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn VariantToInt64(varin : *const VARIANT, pllret : *mut i64) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn VariantToPropVariant(pvar : *const VARIANT, ppropvar : *mut PROPVARIANT) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn VariantToUInt16(varin : *const VARIANT, puiret : *mut u16) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn VariantToUInt32(varin : *const VARIANT, pulret : *mut u32) -> HRESULT);
|
||||
windows_targets::link!("propsys.dll" "system" fn VariantToUInt64(varin : *const VARIANT, pullret : *mut u64) -> HRESULT);
|
||||
pub type ADVANCED_FEATURE_FLAGS = u16;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ARRAYDESC {
|
||||
pub tdescElem: TYPEDESC,
|
||||
pub cDims: u16,
|
||||
pub rgbounds: [SAFEARRAYBOUND; 1],
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union BINDPTR {
|
||||
pub lpfuncdesc: *mut FUNCDESC,
|
||||
pub lpvardesc: *mut VARDESC,
|
||||
pub lptcomp: *mut core::ffi::c_void,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct BLOB {
|
||||
pub cbSize: u32,
|
||||
pub pBlobData: *mut u8,
|
||||
}
|
||||
pub type BOOL = i32;
|
||||
pub type BSTR = *const u16;
|
||||
pub const ERROR_NO_UNICODE_TRANSLATION: WIN32_ERROR = 1113u32;
|
||||
pub const E_INVALIDARG: HRESULT = -2147024809i32;
|
||||
pub type FARPROC = ::core::option::Option<unsafe extern "system" fn() -> isize>;
|
||||
pub const FORMAT_MESSAGE_ALLOCATE_BUFFER: FORMAT_MESSAGE_OPTIONS = 256u32;
|
||||
pub const FORMAT_MESSAGE_FROM_SYSTEM: FORMAT_MESSAGE_OPTIONS = 4096u32;
|
||||
pub const FORMAT_MESSAGE_IGNORE_INSERTS: FORMAT_MESSAGE_OPTIONS = 512u32;
|
||||
pub type FORMAT_MESSAGE_OPTIONS = u32;
|
||||
pub type HANDLE = isize;
|
||||
pub type HEAP_FLAGS = u32;
|
||||
pub type HMODULE = isize;
|
||||
pub type HRESULT = i32;
|
||||
pub type LOAD_LIBRARY_FLAGS = u32;
|
||||
pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = 4096u32;
|
||||
pub type PCSTR = *const u8;
|
||||
pub type PCWSTR = *const u16;
|
||||
pub type PWSTR = *mut u16;
|
||||
#[repr(C)]
|
||||
pub struct SECURITY_ATTRIBUTES {
|
||||
pub nLength: u32,
|
||||
pub lpSecurityDescriptor: *mut ::core::ffi::c_void,
|
||||
pub bInheritHandle: BOOL,
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct BSTRBLOB {
|
||||
pub cbSize: u32,
|
||||
pub pData: *mut u8,
|
||||
}
|
||||
impl ::core::marker::Copy for SECURITY_ATTRIBUTES {}
|
||||
impl ::core::clone::Clone for SECURITY_ATTRIBUTES {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CABOOL {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut VARIANT_BOOL,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CABSTR {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut BSTR,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CABSTRBLOB {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut BSTRBLOB,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CAC {
|
||||
pub cElems: u32,
|
||||
pub pElems: PSTR,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CACLIPDATA {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut CLIPDATA,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CACLSID {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut GUID,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CACY {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut CY,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CADATE {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut f64,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CADBL {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut f64,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CAFILETIME {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut FILETIME,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CAFLT {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut f32,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CAH {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut i64,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CAI {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut i16,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CAL {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut i32,
|
||||
}
|
||||
pub type CALLCONV = i32;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CALPSTR {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut PSTR,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CALPWSTR {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut PWSTR,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CAPROPVARIANT {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut PROPVARIANT,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CASCODE {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut i32,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CAUB {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut u8,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CAUH {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut u64,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CAUI {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut u16,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CAUL {
|
||||
pub cElems: u32,
|
||||
pub pElems: *mut u32,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CLIPDATA {
|
||||
pub cbSize: u32,
|
||||
pub ulClipFmt: i32,
|
||||
pub pClipData: *mut u8,
|
||||
}
|
||||
pub type CO_MTA_USAGE_COOKIE = *mut core::ffi::c_void;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union CY {
|
||||
pub Anonymous: CY_0,
|
||||
pub int64: i64,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct CY_0 {
|
||||
pub Lo: u32,
|
||||
pub Hi: i32,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct DECIMAL {
|
||||
pub wReserved: u16,
|
||||
pub Anonymous1: DECIMAL_0,
|
||||
pub Hi32: u32,
|
||||
pub Anonymous2: DECIMAL_1,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union DECIMAL_0 {
|
||||
pub Anonymous: DECIMAL_0_0,
|
||||
pub signscale: u16,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct DECIMAL_0_0 {
|
||||
pub scale: u8,
|
||||
pub sign: u8,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union DECIMAL_1 {
|
||||
pub Anonymous: DECIMAL_1_0,
|
||||
pub Lo64: u64,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct DECIMAL_1_0 {
|
||||
pub Lo32: u32,
|
||||
pub Mid32: u32,
|
||||
}
|
||||
pub type DESCKIND = i32;
|
||||
pub type DISPATCH_FLAGS = u16;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct DISPPARAMS {
|
||||
pub rgvarg: *mut VARIANT,
|
||||
pub rgdispidNamedArgs: *mut i32,
|
||||
pub cArgs: u32,
|
||||
pub cNamedArgs: u32,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct ELEMDESC {
|
||||
pub tdesc: TYPEDESC,
|
||||
pub Anonymous: ELEMDESC_0,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union ELEMDESC_0 {
|
||||
pub idldesc: IDLDESC,
|
||||
pub paramdesc: PARAMDESC,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct EXCEPINFO {
|
||||
pub wCode: u16,
|
||||
pub wReserved: u16,
|
||||
pub bstrSource: BSTR,
|
||||
pub bstrDescription: BSTR,
|
||||
pub bstrHelpFile: BSTR,
|
||||
pub dwHelpContext: u32,
|
||||
pub pvReserved: *mut core::ffi::c_void,
|
||||
pub pfnDeferredFillIn: LPEXCEPFINO_DEFERRED_FILLIN,
|
||||
pub scode: i32,
|
||||
}
|
||||
pub type FARPROC = Option<unsafe extern "system" fn() -> isize>;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FILETIME {
|
||||
pub dwLowDateTime: u32,
|
||||
pub dwHighDateTime: u32,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FUNCDESC {
|
||||
pub memid: i32,
|
||||
pub lprgscode: *mut i32,
|
||||
pub lprgelemdescParam: *mut ELEMDESC,
|
||||
pub funckind: FUNCKIND,
|
||||
pub invkind: INVOKEKIND,
|
||||
pub callconv: CALLCONV,
|
||||
pub cParams: i16,
|
||||
pub cParamsOpt: i16,
|
||||
pub oVft: i16,
|
||||
pub cScodes: i16,
|
||||
pub elemdescFunc: ELEMDESC,
|
||||
pub wFuncFlags: FUNCFLAGS,
|
||||
}
|
||||
pub type FUNCFLAGS = u16;
|
||||
pub type FUNCKIND = i32;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct GUID {
|
||||
pub data1: u32,
|
||||
pub data2: u16,
|
||||
pub data3: u16,
|
||||
pub data4: [u8; 8],
|
||||
}
|
||||
impl GUID {
|
||||
pub const fn from_u128(uuid: u128) -> Self {
|
||||
Self {
|
||||
data1: (uuid >> 96) as u32,
|
||||
data2: (uuid >> 80 & 0xffff) as u16,
|
||||
data3: (uuid >> 64 & 0xffff) as u16,
|
||||
data4: (uuid as u64).to_be_bytes(),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type HANDLE = *mut core::ffi::c_void;
|
||||
pub type HMODULE = *mut core::ffi::c_void;
|
||||
pub type HRESULT = i32;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct IDLDESC {
|
||||
pub dwReserved: usize,
|
||||
pub wIDLFlags: IDLFLAGS,
|
||||
}
|
||||
pub type IDLFLAGS = u16;
|
||||
pub type IMPLTYPEFLAGS = i32;
|
||||
pub type INVOKEKIND = i32;
|
||||
pub type LOAD_LIBRARY_FLAGS = u32;
|
||||
pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = 4096u32;
|
||||
pub type LPEXCEPFINO_DEFERRED_FILLIN =
|
||||
Option<unsafe extern "system" fn(pexcepinfo: *mut EXCEPINFO) -> HRESULT>;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct PARAMDESC {
|
||||
pub pparamdescex: *mut PARAMDESCEX,
|
||||
pub wParamFlags: PARAMFLAGS,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct PARAMDESCEX {
|
||||
pub cBytes: u32,
|
||||
pub varDefaultValue: VARIANT,
|
||||
}
|
||||
pub type PARAMFLAGS = u16;
|
||||
pub type PCSTR = *const u8;
|
||||
pub type PCWSTR = *const u16;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct PROPVARIANT {
|
||||
pub Anonymous: PROPVARIANT_0,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union PROPVARIANT_0 {
|
||||
pub Anonymous: PROPVARIANT_0_0,
|
||||
pub decVal: DECIMAL,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct PROPVARIANT_0_0 {
|
||||
pub vt: VARENUM,
|
||||
pub wReserved1: u16,
|
||||
pub wReserved2: u16,
|
||||
pub wReserved3: u16,
|
||||
pub Anonymous: PROPVARIANT_0_0_0,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union PROPVARIANT_0_0_0 {
|
||||
pub cVal: i8,
|
||||
pub bVal: u8,
|
||||
pub iVal: i16,
|
||||
pub uiVal: u16,
|
||||
pub lVal: i32,
|
||||
pub ulVal: u32,
|
||||
pub intVal: i32,
|
||||
pub uintVal: u32,
|
||||
pub hVal: i64,
|
||||
pub uhVal: u64,
|
||||
pub fltVal: f32,
|
||||
pub dblVal: f64,
|
||||
pub boolVal: VARIANT_BOOL,
|
||||
pub __OBSOLETE__VARIANT_BOOL: VARIANT_BOOL,
|
||||
pub scode: i32,
|
||||
pub cyVal: CY,
|
||||
pub date: f64,
|
||||
pub filetime: FILETIME,
|
||||
pub puuid: *mut GUID,
|
||||
pub pclipdata: *mut CLIPDATA,
|
||||
pub bstrVal: BSTR,
|
||||
pub bstrblobVal: BSTRBLOB,
|
||||
pub blob: BLOB,
|
||||
pub pszVal: PSTR,
|
||||
pub pwszVal: PWSTR,
|
||||
pub punkVal: *mut core::ffi::c_void,
|
||||
pub pdispVal: *mut core::ffi::c_void,
|
||||
pub pStream: *mut core::ffi::c_void,
|
||||
pub pStorage: *mut core::ffi::c_void,
|
||||
pub pVersionedStream: *mut VERSIONEDSTREAM,
|
||||
pub parray: *mut SAFEARRAY,
|
||||
pub cac: CAC,
|
||||
pub caub: CAUB,
|
||||
pub cai: CAI,
|
||||
pub caui: CAUI,
|
||||
pub cal: CAL,
|
||||
pub caul: CAUL,
|
||||
pub cah: CAH,
|
||||
pub cauh: CAUH,
|
||||
pub caflt: CAFLT,
|
||||
pub cadbl: CADBL,
|
||||
pub cabool: CABOOL,
|
||||
pub cascode: CASCODE,
|
||||
pub cacy: CACY,
|
||||
pub cadate: CADATE,
|
||||
pub cafiletime: CAFILETIME,
|
||||
pub cauuid: CACLSID,
|
||||
pub caclipdata: CACLIPDATA,
|
||||
pub cabstr: CABSTR,
|
||||
pub cabstrblob: CABSTRBLOB,
|
||||
pub calpstr: CALPSTR,
|
||||
pub calpwstr: CALPWSTR,
|
||||
pub capropvar: CAPROPVARIANT,
|
||||
pub pcVal: PSTR,
|
||||
pub pbVal: *mut u8,
|
||||
pub piVal: *mut i16,
|
||||
pub puiVal: *mut u16,
|
||||
pub plVal: *mut i32,
|
||||
pub pulVal: *mut u32,
|
||||
pub pintVal: *mut i32,
|
||||
pub puintVal: *mut u32,
|
||||
pub pfltVal: *mut f32,
|
||||
pub pdblVal: *mut f64,
|
||||
pub pboolVal: *mut VARIANT_BOOL,
|
||||
pub pdecVal: *mut DECIMAL,
|
||||
pub pscode: *mut i32,
|
||||
pub pcyVal: *mut CY,
|
||||
pub pdate: *mut f64,
|
||||
pub pbstrVal: *mut BSTR,
|
||||
pub ppunkVal: *mut *mut core::ffi::c_void,
|
||||
pub ppdispVal: *mut *mut core::ffi::c_void,
|
||||
pub pparray: *mut *mut SAFEARRAY,
|
||||
pub pvarVal: *mut PROPVARIANT,
|
||||
}
|
||||
pub type PROPVAR_COMPARE_FLAGS = i32;
|
||||
pub type PROPVAR_COMPARE_UNIT = i32;
|
||||
pub type PSTR = *mut u8;
|
||||
pub type PWSTR = *mut u16;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SAFEARRAY {
|
||||
pub cDims: u16,
|
||||
pub fFeatures: ADVANCED_FEATURE_FLAGS,
|
||||
pub cbElements: u32,
|
||||
pub cLocks: u32,
|
||||
pub pvData: *mut core::ffi::c_void,
|
||||
pub rgsabound: [SAFEARRAYBOUND; 1],
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SAFEARRAYBOUND {
|
||||
pub cElements: u32,
|
||||
pub lLbound: i32,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SECURITY_ATTRIBUTES {
|
||||
pub nLength: u32,
|
||||
pub lpSecurityDescriptor: *mut core::ffi::c_void,
|
||||
pub bInheritHandle: BOOL,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct STATSTG {
|
||||
pub pwcsName: PWSTR,
|
||||
pub r#type: u32,
|
||||
pub cbSize: u64,
|
||||
pub mtime: FILETIME,
|
||||
pub ctime: FILETIME,
|
||||
pub atime: FILETIME,
|
||||
pub grfMode: STGM,
|
||||
pub grfLocksSupported: u32,
|
||||
pub clsid: GUID,
|
||||
pub grfStateBits: u32,
|
||||
pub reserved: u32,
|
||||
}
|
||||
pub type STGM = u32;
|
||||
pub type STREAM_SEEK = u32;
|
||||
pub type SYSKIND = i32;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct TLIBATTR {
|
||||
pub guid: GUID,
|
||||
pub lcid: u32,
|
||||
pub syskind: SYSKIND,
|
||||
pub wMajorVerNum: u16,
|
||||
pub wMinorVerNum: u16,
|
||||
pub wLibFlags: u16,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct TYPEATTR {
|
||||
pub guid: GUID,
|
||||
pub lcid: u32,
|
||||
pub dwReserved: u32,
|
||||
pub memidConstructor: i32,
|
||||
pub memidDestructor: i32,
|
||||
pub lpstrSchema: PWSTR,
|
||||
pub cbSizeInstance: u32,
|
||||
pub typekind: TYPEKIND,
|
||||
pub cFuncs: u16,
|
||||
pub cVars: u16,
|
||||
pub cImplTypes: u16,
|
||||
pub cbSizeVft: u16,
|
||||
pub cbAlignment: u16,
|
||||
pub wTypeFlags: u16,
|
||||
pub wMajorVerNum: u16,
|
||||
pub wMinorVerNum: u16,
|
||||
pub tdescAlias: TYPEDESC,
|
||||
pub idldescType: IDLDESC,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct TYPEDESC {
|
||||
pub Anonymous: TYPEDESC_0,
|
||||
pub vt: VARENUM,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union TYPEDESC_0 {
|
||||
pub lptdesc: *mut TYPEDESC,
|
||||
pub lpadesc: *mut ARRAYDESC,
|
||||
pub hreftype: u32,
|
||||
}
|
||||
pub type TYPEKIND = i32;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct VARDESC {
|
||||
pub memid: i32,
|
||||
pub lpstrSchema: PWSTR,
|
||||
pub Anonymous: VARDESC_0,
|
||||
pub elemdescVar: ELEMDESC,
|
||||
pub wVarFlags: VARFLAGS,
|
||||
pub varkind: VARKIND,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union VARDESC_0 {
|
||||
pub oInst: u32,
|
||||
pub lpvarValue: *mut VARIANT,
|
||||
}
|
||||
pub type VARENUM = u16;
|
||||
pub type VARFLAGS = u16;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct VARIANT {
|
||||
pub Anonymous: VARIANT_0,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union VARIANT_0 {
|
||||
pub Anonymous: VARIANT_0_0,
|
||||
pub decVal: DECIMAL,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct VARIANT_0_0 {
|
||||
pub vt: VARENUM,
|
||||
pub wReserved1: u16,
|
||||
pub wReserved2: u16,
|
||||
pub wReserved3: u16,
|
||||
pub Anonymous: VARIANT_0_0_0,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub union VARIANT_0_0_0 {
|
||||
pub llVal: i64,
|
||||
pub lVal: i32,
|
||||
pub bVal: u8,
|
||||
pub iVal: i16,
|
||||
pub fltVal: f32,
|
||||
pub dblVal: f64,
|
||||
pub boolVal: VARIANT_BOOL,
|
||||
pub __OBSOLETE__VARIANT_BOOL: VARIANT_BOOL,
|
||||
pub scode: i32,
|
||||
pub cyVal: CY,
|
||||
pub date: f64,
|
||||
pub bstrVal: BSTR,
|
||||
pub punkVal: *mut core::ffi::c_void,
|
||||
pub pdispVal: *mut core::ffi::c_void,
|
||||
pub parray: *mut SAFEARRAY,
|
||||
pub pbVal: *mut u8,
|
||||
pub piVal: *mut i16,
|
||||
pub plVal: *mut i32,
|
||||
pub pllVal: *mut i64,
|
||||
pub pfltVal: *mut f32,
|
||||
pub pdblVal: *mut f64,
|
||||
pub pboolVal: *mut VARIANT_BOOL,
|
||||
pub __OBSOLETE__VARIANT_PBOOL: *mut VARIANT_BOOL,
|
||||
pub pscode: *mut i32,
|
||||
pub pcyVal: *mut CY,
|
||||
pub pdate: *mut f64,
|
||||
pub pbstrVal: *mut BSTR,
|
||||
pub ppunkVal: *mut *mut core::ffi::c_void,
|
||||
pub ppdispVal: *mut *mut core::ffi::c_void,
|
||||
pub pparray: *mut *mut SAFEARRAY,
|
||||
pub pvarVal: *mut VARIANT,
|
||||
pub byref: *mut core::ffi::c_void,
|
||||
pub cVal: i8,
|
||||
pub uiVal: u16,
|
||||
pub ulVal: u32,
|
||||
pub ullVal: u64,
|
||||
pub intVal: i32,
|
||||
pub uintVal: u32,
|
||||
pub pdecVal: *mut DECIMAL,
|
||||
pub pcVal: PSTR,
|
||||
pub puiVal: *mut u16,
|
||||
pub pulVal: *mut u32,
|
||||
pub pullVal: *mut u64,
|
||||
pub pintVal: *mut i32,
|
||||
pub puintVal: *mut u32,
|
||||
pub Anonymous: VARIANT_0_0_0_0,
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct VARIANT_0_0_0_0 {
|
||||
pub pvRecord: *mut core::ffi::c_void,
|
||||
pub pRecInfo: *mut core::ffi::c_void,
|
||||
}
|
||||
pub type VARIANT_BOOL = i16;
|
||||
pub type VARKIND = i32;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct VERSIONEDSTREAM {
|
||||
pub guidVersion: GUID,
|
||||
pub pStream: *mut core::ffi::c_void,
|
||||
}
|
||||
pub const VT_BOOL: VARENUM = 11u16;
|
||||
pub const VT_BSTR: VARENUM = 8u16;
|
||||
pub const VT_EMPTY: VARENUM = 0u16;
|
||||
pub const VT_I1: VARENUM = 16u16;
|
||||
pub const VT_I2: VARENUM = 2u16;
|
||||
pub const VT_I4: VARENUM = 3u16;
|
||||
pub const VT_I8: VARENUM = 20u16;
|
||||
pub const VT_R4: VARENUM = 4u16;
|
||||
pub const VT_R8: VARENUM = 5u16;
|
||||
pub const VT_UI1: VARENUM = 17u16;
|
||||
pub const VT_UI2: VARENUM = 18u16;
|
||||
pub const VT_UI4: VARENUM = 19u16;
|
||||
pub const VT_UI8: VARENUM = 21u16;
|
||||
pub const VT_UNKNOWN: VARENUM = 13u16;
|
||||
pub type WAIT_EVENT = u32;
|
||||
pub type WIN32_ERROR = u32;
|
||||
|
||||
5
third_party/rust/windows-core/src/imp/can_into.rs
vendored
Normal file
5
third_party/rust/windows-core/src/imp/can_into.rs
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
pub trait CanInto<T>: Sized {
|
||||
const QUERY: bool = false;
|
||||
}
|
||||
|
||||
impl<T> CanInto<T> for T where T: Clone {}
|
||||
1454
third_party/rust/windows-core/src/imp/com_bindings.rs
vendored
1454
third_party/rust/windows-core/src/imp/com_bindings.rs
vendored
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
||||
use super::*;
|
||||
|
||||
/// Attempts to load a function from a given library.
|
||||
///
|
||||
/// This is a small wrapper around `LoadLibrary` and `GetProcAddress`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// * Both the library and function names must be valid null-terminated strings.
|
||||
pub unsafe fn delay_load<T>(library: crate::PCSTR, function: crate::PCSTR) -> Option<T> {
|
||||
let library = LoadLibraryExA(library.0, 0, LOAD_LIBRARY_SEARCH_DEFAULT_DIRS);
|
||||
|
||||
if library == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let address = GetProcAddress(library, function.0);
|
||||
|
||||
if address.is_some() {
|
||||
return Some(std::mem::transmute_copy(&address));
|
||||
}
|
||||
|
||||
FreeLibrary(library);
|
||||
None
|
||||
}
|
||||
@@ -1,22 +1,34 @@
|
||||
use super::*;
|
||||
use crate::ComInterface;
|
||||
use std::marker::PhantomData;
|
||||
use std::sync::atomic::{AtomicPtr, Ordering};
|
||||
use crate::Interface;
|
||||
use core::ffi::c_void;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::{forget, transmute, transmute_copy};
|
||||
use core::ptr::null_mut;
|
||||
use core::sync::atomic::{AtomicPtr, Ordering};
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct FactoryCache<C, I> {
|
||||
shared: AtomicPtr<std::ffi::c_void>,
|
||||
shared: AtomicPtr<c_void>,
|
||||
_c: PhantomData<C>,
|
||||
_i: PhantomData<I>,
|
||||
}
|
||||
|
||||
impl<C, I> FactoryCache<C, I> {
|
||||
pub const fn new() -> Self {
|
||||
Self { shared: AtomicPtr::new(std::ptr::null_mut()), _c: PhantomData, _i: PhantomData }
|
||||
Self {
|
||||
shared: AtomicPtr::new(null_mut()),
|
||||
_c: PhantomData,
|
||||
_i: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: crate::RuntimeName, I: crate::ComInterface> FactoryCache<C, I> {
|
||||
impl<C, I> Default for FactoryCache<C, I> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: crate::RuntimeName, I: Interface> FactoryCache<C, I> {
|
||||
pub fn call<R, F: FnOnce(&I) -> crate::Result<R>>(&self, callback: F) -> crate::Result<R> {
|
||||
loop {
|
||||
// Attempt to load a previously cached factory pointer.
|
||||
@@ -24,7 +36,7 @@ impl<C: crate::RuntimeName, I: crate::ComInterface> FactoryCache<C, I> {
|
||||
|
||||
// If a pointer is found, the cache is primed and we're good to go.
|
||||
if !ptr.is_null() {
|
||||
return callback(unsafe { std::mem::transmute(&ptr) });
|
||||
return callback(unsafe { transmute::<&*mut c_void, &I>(&ptr) });
|
||||
}
|
||||
|
||||
// Otherwise, we load the factory the usual way.
|
||||
@@ -32,8 +44,17 @@ impl<C: crate::RuntimeName, I: crate::ComInterface> FactoryCache<C, I> {
|
||||
|
||||
// If the factory is agile, we can safely cache it.
|
||||
if factory.cast::<IAgileObject>().is_ok() {
|
||||
if self.shared.compare_exchange_weak(std::ptr::null_mut(), factory.as_raw(), Ordering::Relaxed, Ordering::Relaxed).is_ok() {
|
||||
std::mem::forget(factory);
|
||||
if self
|
||||
.shared
|
||||
.compare_exchange_weak(
|
||||
null_mut(),
|
||||
factory.as_raw(),
|
||||
Ordering::Relaxed,
|
||||
Ordering::Relaxed,
|
||||
)
|
||||
.is_ok()
|
||||
{
|
||||
forget(factory);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, for non-agile factories we simply use the factory
|
||||
@@ -45,39 +66,40 @@ impl<C: crate::RuntimeName, I: crate::ComInterface> FactoryCache<C, I> {
|
||||
}
|
||||
|
||||
// This is safe because `FactoryCache` only holds agile factory pointers, which are safe to cache and share between threads.
|
||||
unsafe impl<C, I> std::marker::Sync for FactoryCache<C, I> {}
|
||||
unsafe impl<C, I> Sync for FactoryCache<C, I> {}
|
||||
|
||||
/// Attempts to load the factory object for the given WinRT class.
|
||||
/// This can be used to access COM interfaces implemented on a Windows Runtime class factory.
|
||||
pub fn factory<C: crate::RuntimeName, I: crate::ComInterface>() -> crate::Result<I> {
|
||||
pub fn factory<C: crate::RuntimeName, I: Interface>() -> crate::Result<I> {
|
||||
let mut factory: Option<I> = None;
|
||||
let name = crate::HSTRING::from(C::NAME);
|
||||
|
||||
let code = if let Some(function) = unsafe { delay_load::<RoGetActivationFactory>(crate::s!("combase.dll"), crate::s!("RoGetActivationFactory")) } {
|
||||
unsafe {
|
||||
let mut code = function(std::mem::transmute_copy(&name), &I::IID, &mut factory as *mut _ as *mut _);
|
||||
let code = unsafe {
|
||||
let mut get_com_factory = || {
|
||||
crate::HRESULT(RoGetActivationFactory(
|
||||
transmute_copy(&name),
|
||||
&I::IID as *const _ as _,
|
||||
&mut factory as *mut _ as *mut _,
|
||||
))
|
||||
};
|
||||
let mut code = get_com_factory();
|
||||
|
||||
// If RoGetActivationFactory fails because combase hasn't been loaded yet then load combase
|
||||
// automatically so that it "just works" for apartment-agnostic code.
|
||||
if code == CO_E_NOTINITIALIZED {
|
||||
if let Some(mta) = delay_load::<CoIncrementMTAUsage>(crate::s!("ole32.dll"), crate::s!("CoIncrementMTAUsage")) {
|
||||
let mut cookie = std::ptr::null_mut();
|
||||
let _ = mta(&mut cookie);
|
||||
}
|
||||
// If RoGetActivationFactory fails because combase hasn't been loaded yet then load combase
|
||||
// automatically so that it "just works" for apartment-agnostic code.
|
||||
if code == CO_E_NOTINITIALIZED {
|
||||
let mut cookie = core::ptr::null_mut();
|
||||
CoIncrementMTAUsage(&mut cookie);
|
||||
|
||||
// Now try a second time to get the activation factory via the OS.
|
||||
code = function(std::mem::transmute_copy(&name), &I::IID, &mut factory as *mut _ as *mut _);
|
||||
}
|
||||
|
||||
code
|
||||
// Now try a second time to get the activation factory via the OS.
|
||||
code = get_com_factory();
|
||||
}
|
||||
} else {
|
||||
CLASS_E_CLASSNOTAVAILABLE
|
||||
|
||||
code
|
||||
};
|
||||
|
||||
// If this succeeded then return the resulting factory interface.
|
||||
if code.is_ok() {
|
||||
return code.and_some(factory);
|
||||
if let Some(factory) = factory {
|
||||
return Ok(factory);
|
||||
}
|
||||
|
||||
// If not, first capture the error information from the failure above so that we
|
||||
@@ -85,7 +107,9 @@ pub fn factory<C: crate::RuntimeName, I: crate::ComInterface>() -> crate::Result
|
||||
let original: crate::Error = code.into();
|
||||
|
||||
// Now attempt to find the factory's implementation heuristically.
|
||||
if let Some(i) = search_path(C::NAME, |library| unsafe { get_activation_factory(library, &name) }) {
|
||||
if let Some(i) = search_path(C::NAME, |library| unsafe {
|
||||
get_activation_factory(library, &name)
|
||||
}) {
|
||||
i.cast()
|
||||
} else {
|
||||
Err(original)
|
||||
@@ -103,7 +127,7 @@ where
|
||||
F: FnMut(crate::PCSTR) -> crate::Result<R>,
|
||||
{
|
||||
let suffix = b".dll\0";
|
||||
let mut library = vec![0; path.len() + suffix.len()];
|
||||
let mut library = alloc::vec![0; path.len() + suffix.len()];
|
||||
while let Some(pos) = path.rfind('.') {
|
||||
path = &path[..pos];
|
||||
library.truncate(path.len() + suffix.len());
|
||||
@@ -118,15 +142,40 @@ where
|
||||
None
|
||||
}
|
||||
|
||||
unsafe fn get_activation_factory(library: crate::PCSTR, name: &crate::HSTRING) -> crate::Result<IGenericFactory> {
|
||||
let function = delay_load::<DllGetActivationFactory>(library, crate::s!("DllGetActivationFactory")).ok_or_else(crate::Error::from_win32)?;
|
||||
let mut abi = std::ptr::null_mut();
|
||||
function(std::mem::transmute_copy(name), &mut abi).from_abi(abi)
|
||||
unsafe fn get_activation_factory(
|
||||
library: crate::PCSTR,
|
||||
name: &crate::HSTRING,
|
||||
) -> crate::Result<IGenericFactory> {
|
||||
let function =
|
||||
delay_load::<DllGetActivationFactory>(library, crate::s!("DllGetActivationFactory"))
|
||||
.ok_or_else(crate::Error::from_win32)?;
|
||||
let mut abi = null_mut();
|
||||
function(transmute_copy(name), &mut abi).and_then(|| crate::Type::from_abi(abi))
|
||||
}
|
||||
|
||||
type CoIncrementMTAUsage = extern "system" fn(cookie: *mut *mut std::ffi::c_void) -> crate::HRESULT;
|
||||
type RoGetActivationFactory = extern "system" fn(hstring: *mut std::ffi::c_void, interface: &crate::GUID, result: *mut *mut std::ffi::c_void) -> crate::HRESULT;
|
||||
type DllGetActivationFactory = extern "system" fn(name: *mut std::ffi::c_void, factory: *mut *mut std::ffi::c_void) -> crate::HRESULT;
|
||||
unsafe fn delay_load<T>(library: crate::PCSTR, function: crate::PCSTR) -> Option<T> {
|
||||
let library = LoadLibraryExA(
|
||||
library.0,
|
||||
core::ptr::null_mut(),
|
||||
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS,
|
||||
);
|
||||
|
||||
if library.is_null() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let address = GetProcAddress(library, function.0);
|
||||
|
||||
if address.is_some() {
|
||||
return Some(core::mem::transmute_copy(&address));
|
||||
}
|
||||
|
||||
FreeLibrary(library);
|
||||
None
|
||||
}
|
||||
|
||||
type DllGetActivationFactory =
|
||||
extern "system" fn(name: *mut c_void, factory: *mut *mut c_void) -> crate::HRESULT;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
@@ -143,7 +192,7 @@ mod tests {
|
||||
if unsafe { library.as_bytes() } == &b"A.dll"[..] {
|
||||
Ok(42)
|
||||
} else {
|
||||
Err(crate::Error::OK)
|
||||
Err(crate::Error::empty())
|
||||
}
|
||||
});
|
||||
assert!(matches!(end_result, Some(42)));
|
||||
@@ -153,7 +202,7 @@ mod tests {
|
||||
let mut results = Vec::new();
|
||||
let end_result = search_path(path, |library| {
|
||||
results.push(unsafe { library.to_string().unwrap() });
|
||||
crate::Result::<()>::Err(crate::Error::OK)
|
||||
crate::Result::<()>::Err(crate::Error::empty())
|
||||
});
|
||||
assert!(end_result.is_none());
|
||||
assert_eq!(results, vec!["A.B.dll", "A.dll"]);
|
||||
|
||||
@@ -1,16 +1,26 @@
|
||||
use crate::ComInterface;
|
||||
use crate::Interface;
|
||||
use core::ffi::c_void;
|
||||
use core::mem::{transmute_copy, zeroed};
|
||||
|
||||
// A streamlined version of the IActivationFactory interface used by WinRT class factories used internally by the windows crate
|
||||
// to simplify code generation. Components should implement the `IActivationFactory` interface published by the windows crate.
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct IGenericFactory(crate::IUnknown);
|
||||
super::define_interface!(
|
||||
IGenericFactory,
|
||||
IGenericFactory_Vtbl,
|
||||
0x00000035_0000_0000_c000_000000000046
|
||||
);
|
||||
super::interface_hierarchy!(IGenericFactory, crate::IUnknown, crate::IInspectable);
|
||||
|
||||
impl IGenericFactory {
|
||||
pub fn ActivateInstance<I: crate::ComInterface>(&self) -> crate::Result<I> {
|
||||
pub fn ActivateInstance<I: Interface>(&self) -> crate::Result<I> {
|
||||
unsafe {
|
||||
let mut result__ = std::mem::zeroed();
|
||||
(crate::Interface::vtable(self).ActivateInstance)(std::mem::transmute_copy(self), &mut result__ as *mut _ as *mut _).from_abi::<crate::IInspectable>(result__)?.cast()
|
||||
let mut result__ = zeroed();
|
||||
(Interface::vtable(self).ActivateInstance)(
|
||||
transmute_copy(self),
|
||||
&mut result__ as *mut _ as *mut _,
|
||||
)
|
||||
.and_then(|| crate::Type::from_abi(result__))
|
||||
.and_then(|interface: crate::IInspectable| interface.cast())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,13 +28,6 @@ impl IGenericFactory {
|
||||
#[repr(C)]
|
||||
pub struct IGenericFactory_Vtbl {
|
||||
pub base__: crate::IInspectable_Vtbl,
|
||||
pub ActivateInstance: unsafe extern "system" fn(this: *mut std::ffi::c_void, instance: *mut *mut std::ffi::c_void) -> crate::HRESULT,
|
||||
}
|
||||
|
||||
unsafe impl crate::Interface for IGenericFactory {
|
||||
type Vtable = IGenericFactory_Vtbl;
|
||||
}
|
||||
|
||||
unsafe impl crate::ComInterface for IGenericFactory {
|
||||
const IID: crate::GUID = crate::GUID::from_u128(0x00000035_0000_0000_c000_000000000046);
|
||||
pub ActivateInstance:
|
||||
unsafe extern "system" fn(this: *mut c_void, instance: *mut *mut c_void) -> crate::HRESULT,
|
||||
}
|
||||
|
||||
35
third_party/rust/windows-core/src/imp/heap.rs
vendored
35
third_party/rust/windows-core/src/imp/heap.rs
vendored
@@ -1,35 +0,0 @@
|
||||
use super::*;
|
||||
|
||||
/// Allocate memory of size `bytes` using `HeapAlloc`.
|
||||
///
|
||||
/// The memory allocated by this function is uninitialized.
|
||||
///
|
||||
/// This function will fail in OOM situations, if the heap is otherwise corrupt,
|
||||
/// or if getting a handle to the process heap fails.
|
||||
pub fn heap_alloc(bytes: usize) -> crate::Result<*mut std::ffi::c_void> {
|
||||
let ptr = unsafe { HeapAlloc(GetProcessHeap(), 0, bytes) };
|
||||
|
||||
if ptr.is_null() {
|
||||
Err(E_OUTOFMEMORY.into())
|
||||
} else {
|
||||
// HeapAlloc is not guaranteed to return zero memory but usually does. This just ensures that
|
||||
// it predictably returns non-zero memory for testing purposes. This is similar to what MSVC's
|
||||
// debug allocator does for the same reason.
|
||||
#[cfg(debug_assertions)]
|
||||
unsafe {
|
||||
std::ptr::write_bytes(ptr, 0xCC, bytes);
|
||||
}
|
||||
Ok(ptr)
|
||||
}
|
||||
}
|
||||
|
||||
/// Free memory allocated by `HeapAlloc` or `HeapReAlloc`.
|
||||
///
|
||||
/// The pointer is allowed to be null.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `ptr` must be a valid pointer to memory allocated by `HeapAlloc` or `HeapReAlloc`
|
||||
pub unsafe fn heap_free(ptr: *mut std::ffi::c_void) {
|
||||
HeapFree(GetProcessHeap(), 0, ptr);
|
||||
}
|
||||
109
third_party/rust/windows-core/src/imp/mod.rs
vendored
109
third_party/rust/windows-core/src/imp/mod.rs
vendored
@@ -1,51 +1,35 @@
|
||||
mod bindings;
|
||||
#[cfg(windows)]
|
||||
include!("windows.rs");
|
||||
|
||||
mod can_into;
|
||||
mod com_bindings;
|
||||
mod delay_load;
|
||||
mod factory_cache;
|
||||
mod generic_factory;
|
||||
mod heap;
|
||||
mod ref_count;
|
||||
mod sha1;
|
||||
mod waiter;
|
||||
mod weak_ref_count;
|
||||
|
||||
pub use bindings::*;
|
||||
pub use can_into::*;
|
||||
pub use com_bindings::*;
|
||||
pub use delay_load::*;
|
||||
pub use factory_cache::*;
|
||||
pub use generic_factory::*;
|
||||
pub use heap::*;
|
||||
pub use ref_count::*;
|
||||
pub use sha1::*;
|
||||
pub use waiter::*;
|
||||
pub use weak_ref_count::*;
|
||||
|
||||
// This is a workaround since 1.56 does not include `bool::then_some`.
|
||||
pub fn then_some<T>(value: bool, t: T) -> Option<T> {
|
||||
if value {
|
||||
Some(t)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wide_trim_end(mut wide: &[u16]) -> &[u16] {
|
||||
while let Some(last) = wide.last() {
|
||||
match last {
|
||||
32 | 9..=13 => wide = &wide[..wide.len() - 1],
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
wide
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! interface_hierarchy {
|
||||
($child:ty, $parent:ty) => {
|
||||
impl ::windows_core::CanInto<$parent> for $child {}
|
||||
($child:ident, $parent:ty) => {
|
||||
impl ::windows_core::imp::CanInto<$parent> for $child {}
|
||||
impl ::core::convert::From<&$child> for &$parent {
|
||||
fn from(value: &$child) -> Self {
|
||||
unsafe { ::core::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
impl ::core::convert::From<$child> for $parent {
|
||||
fn from(value: $child) -> Self {
|
||||
unsafe { ::core::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
};
|
||||
($child:ty, $first:ty, $($rest:ty),+) => {
|
||||
($child:ident, $first:ty, $($rest:ty),+) => {
|
||||
$crate::imp::interface_hierarchy!($child, $first);
|
||||
$crate::imp::interface_hierarchy!($child, $($rest),+);
|
||||
};
|
||||
@@ -53,3 +37,60 @@ macro_rules! interface_hierarchy {
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use interface_hierarchy;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! required_hierarchy {
|
||||
($child:ident, $parent:ty) => {
|
||||
impl ::windows_core::imp::CanInto<$parent> for $child { const QUERY: bool = true; }
|
||||
};
|
||||
($child:ident, $first:ty, $($rest:ty),+) => {
|
||||
$crate::imp::required_hierarchy!($child, $first);
|
||||
$crate::imp::required_hierarchy!($child, $($rest),+);
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use required_hierarchy;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! define_interface {
|
||||
($name:ident, $vtbl:ident, $iid:literal) => {
|
||||
#[repr(transparent)]
|
||||
#[derive(::core::cmp::PartialEq, ::core::cmp::Eq, ::core::clone::Clone)]
|
||||
pub struct $name(::windows_core::IUnknown);
|
||||
unsafe impl ::windows_core::Interface for $name {
|
||||
type Vtable = $vtbl;
|
||||
const IID: ::windows_core::GUID = ::windows_core::GUID::from_u128($iid);
|
||||
}
|
||||
impl ::core::fmt::Debug for $name {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_tuple(stringify!($name))
|
||||
.field(&::windows_core::Interface::as_raw(self))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
};
|
||||
($name:ident, $vtbl:ident) => {
|
||||
#[repr(transparent)]
|
||||
#[derive(::core::cmp::PartialEq, ::core::cmp::Eq, ::core::clone::Clone)]
|
||||
pub struct $name(::std::ptr::NonNull<::std::ffi::c_void>);
|
||||
unsafe impl ::windows_core::Interface for $name {
|
||||
type Vtable = $vtbl;
|
||||
const IID: ::windows_core::GUID = ::windows_core::GUID::zeroed();
|
||||
const UNKNOWN: bool = false;
|
||||
}
|
||||
impl ::core::fmt::Debug for $name {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_tuple(stringify!($name)).field(&self.0).finish()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use define_interface;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub use alloc::boxed::Box;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use std::sync::atomic::{fence, AtomicI32, Ordering};
|
||||
use core::sync::atomic::{fence, AtomicI32, Ordering};
|
||||
|
||||
#[doc(hidden)]
|
||||
#[repr(transparent)]
|
||||
#[derive(Default)]
|
||||
pub struct RefCount(pub(crate) AtomicI32);
|
||||
@@ -24,9 +23,9 @@ impl RefCount {
|
||||
let remaining = self.0.fetch_sub(1, Ordering::Release) - 1;
|
||||
|
||||
match remaining.cmp(&0) {
|
||||
std::cmp::Ordering::Equal => fence(Ordering::Acquire),
|
||||
std::cmp::Ordering::Less => panic!("Object has been over-released."),
|
||||
std::cmp::Ordering::Greater => {}
|
||||
core::cmp::Ordering::Equal => fence(Ordering::Acquire),
|
||||
core::cmp::Ordering::Less => panic!("Object has been over-released."),
|
||||
core::cmp::Ordering::Greater => {}
|
||||
}
|
||||
|
||||
remaining as u32
|
||||
|
||||
198
third_party/rust/windows-core/src/imp/sha1.rs
vendored
198
third_party/rust/windows-core/src/imp/sha1.rs
vendored
@@ -3,7 +3,10 @@
|
||||
pub const fn sha1(data: &ConstBuffer) -> Digest {
|
||||
let state: [u32; 5] = [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0];
|
||||
let len: u64 = 0;
|
||||
let blocks = Blocks { len: 0, data: [0; 64] };
|
||||
let blocks = Blocks {
|
||||
len: 0,
|
||||
data: [0; 64],
|
||||
};
|
||||
let (blocks, len, state) = process_blocks(blocks, data, len, state);
|
||||
digest(state, len, blocks)
|
||||
}
|
||||
@@ -16,13 +19,29 @@ pub struct ConstBuffer {
|
||||
}
|
||||
|
||||
impl ConstBuffer {
|
||||
pub const fn for_class<C: crate::RuntimeName, I: crate::RuntimeType>() -> Self {
|
||||
Self::new()
|
||||
.push_slice(b"rc(")
|
||||
.push_slice(C::NAME.as_bytes())
|
||||
.push(b';')
|
||||
.push_other(I::SIGNATURE)
|
||||
.push(b')')
|
||||
}
|
||||
|
||||
pub const fn for_interface<T: crate::Interface>() -> Self {
|
||||
Self::new().push_guid(&T::IID)
|
||||
}
|
||||
|
||||
pub const fn from_slice(slice: &[u8]) -> Self {
|
||||
let s = Self::new();
|
||||
s.push_slice(slice)
|
||||
}
|
||||
|
||||
pub const fn new() -> Self {
|
||||
Self { data: [0; BUFFER_SIZE], head: 0 }
|
||||
Self {
|
||||
data: [0; BUFFER_SIZE],
|
||||
head: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn push_slice(self, slice: &[u8]) -> Self {
|
||||
@@ -37,12 +56,42 @@ impl ConstBuffer {
|
||||
self.head
|
||||
}
|
||||
|
||||
const fn as_slice(&self) -> &[u8] {
|
||||
&self.data
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
&self.data[..self.head]
|
||||
}
|
||||
|
||||
pub const fn push_other(self, other: Self) -> Self {
|
||||
self.push_amount(other.as_slice(), other.len())
|
||||
self.push_amount(&other.data, other.len())
|
||||
}
|
||||
|
||||
const fn push(mut self, value: u8) -> Self {
|
||||
self.data[self.head] = value;
|
||||
self.head += 1;
|
||||
self
|
||||
}
|
||||
|
||||
const fn push_hex_u8(self, value: u8) -> Self {
|
||||
const fn digit(mut value: u8) -> u8 {
|
||||
value &= 0xF;
|
||||
|
||||
if value < 10 {
|
||||
b'0' + value
|
||||
} else {
|
||||
b'a' + (value - 10)
|
||||
}
|
||||
}
|
||||
|
||||
self.push(digit(value >> 4)).push(digit(value))
|
||||
}
|
||||
|
||||
const fn push_hex_u16(self, value: u16) -> Self {
|
||||
self.push_hex_u8((value >> 8) as u8)
|
||||
.push_hex_u8((value & 0xFF) as u8)
|
||||
}
|
||||
|
||||
const fn push_hex_u32(self, value: u32) -> Self {
|
||||
self.push_hex_u16((value >> 16) as u16)
|
||||
.push_hex_u16((value & 0xFFFF) as u16)
|
||||
}
|
||||
|
||||
const fn push_amount(mut self, slice: &[u8], amount: usize) -> Self {
|
||||
@@ -54,6 +103,22 @@ impl ConstBuffer {
|
||||
self.head += i;
|
||||
self
|
||||
}
|
||||
|
||||
const fn push_guid(self, guid: &crate::GUID) -> Self {
|
||||
self.push(b'{')
|
||||
.push_hex_u32(guid.data1)
|
||||
.push(b'-')
|
||||
.push_hex_u16(guid.data2)
|
||||
.push(b'-')
|
||||
.push_hex_u16(guid.data3)
|
||||
.push(b'-')
|
||||
.push_hex_u16((guid.data4[0] as u16) << 8 | guid.data4[1] as u16)
|
||||
.push(b'-')
|
||||
.push_hex_u16((guid.data4[2] as u16) << 8 | guid.data4[3] as u16)
|
||||
.push_hex_u16((guid.data4[4] as u16) << 8 | guid.data4[5] as u16)
|
||||
.push_hex_u16((guid.data4[6] as u16) << 8 | guid.data4[7] as u16)
|
||||
.push(b'}')
|
||||
}
|
||||
}
|
||||
|
||||
struct Blocks {
|
||||
@@ -61,20 +126,33 @@ struct Blocks {
|
||||
data: [u8; 64],
|
||||
}
|
||||
|
||||
const fn process_blocks(mut blocks: Blocks, data: &ConstBuffer, mut len: u64, mut state: [u32; 5]) -> (Blocks, u64, [u32; 5]) {
|
||||
const fn process_blocks(
|
||||
mut blocks: Blocks,
|
||||
data: &ConstBuffer,
|
||||
mut len: u64,
|
||||
mut state: [u32; 5],
|
||||
) -> (Blocks, u64, [u32; 5]) {
|
||||
const fn as_block(input: &ConstBuffer, offset: usize) -> [u32; 16] {
|
||||
let mut result = [0u32; 16];
|
||||
|
||||
let mut i = 0;
|
||||
while i != 16 {
|
||||
let off = offset + (i * 4);
|
||||
result[i] = (input.get(off + 3) as u32) | ((input.get(off + 2) as u32) << 8) | ((input.get(off + 1) as u32) << 16) | ((input.get(off) as u32) << 24);
|
||||
result[i] = (input.get(off + 3) as u32)
|
||||
| ((input.get(off + 2) as u32) << 8)
|
||||
| ((input.get(off + 1) as u32) << 16)
|
||||
| ((input.get(off) as u32) << 24);
|
||||
i += 1;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
const fn clone_from_slice_64(mut data: [u8; 64], slice: &[u8], offset: usize, num_elems: usize) -> [u8; 64] {
|
||||
const fn clone_from_slice_64(
|
||||
mut data: [u8; 64],
|
||||
slice: &[u8],
|
||||
offset: usize,
|
||||
num_elems: usize,
|
||||
) -> [u8; 64] {
|
||||
let mut i = 0;
|
||||
while i < num_elems {
|
||||
data[i] = slice[offset + i];
|
||||
@@ -92,7 +170,7 @@ const fn process_blocks(mut blocks: Blocks, data: &ConstBuffer, mut len: u64, mu
|
||||
i += 64;
|
||||
} else {
|
||||
let num_elems = data.len() - i;
|
||||
blocks.data = clone_from_slice_64(blocks.data, data.as_slice(), i, num_elems);
|
||||
blocks.data = clone_from_slice_64(blocks.data, &data.data, i, num_elems);
|
||||
blocks.len = num_elems as u32;
|
||||
break;
|
||||
}
|
||||
@@ -196,7 +274,12 @@ const fn process_state(mut state: [u32; 5], block: [u32; 16]) -> [u32; 5] {
|
||||
}
|
||||
|
||||
const fn digest(mut state: [u32; 5], len: u64, blocks: Blocks) -> Digest {
|
||||
const fn clone_from_slice_128(mut data: [u8; 128], slice: &[u8], offset: usize, num_elems: usize) -> [u8; 128] {
|
||||
const fn clone_from_slice_128(
|
||||
mut data: [u8; 128],
|
||||
slice: &[u8],
|
||||
offset: usize,
|
||||
num_elems: usize,
|
||||
) -> [u8; 128] {
|
||||
let mut i = 0;
|
||||
while i < num_elems {
|
||||
data[i] = slice[offset + i];
|
||||
@@ -220,14 +303,26 @@ const fn digest(mut state: [u32; 5], len: u64, blocks: Blocks) -> Digest {
|
||||
let mut i = 0;
|
||||
while i != 16 {
|
||||
let off = offset + (i * 4);
|
||||
result[i] = (input[off + 3] as u32) | ((input[off + 2] as u32) << 8) | ((input[off + 1] as u32) << 16) | ((input[off] as u32) << 24);
|
||||
result[i] = (input[off + 3] as u32)
|
||||
| ((input[off + 2] as u32) << 8)
|
||||
| ((input[off + 1] as u32) << 16)
|
||||
| ((input[off] as u32) << 24);
|
||||
i += 1;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
let bits = (len + (blocks.len as u64)) * 8;
|
||||
let extra = [(bits >> 56) as u8, (bits >> 48) as u8, (bits >> 40) as u8, (bits >> 32) as u8, (bits >> 24) as u8, (bits >> 16) as u8, (bits >> 8) as u8, bits as u8];
|
||||
let extra = [
|
||||
(bits >> 56) as u8,
|
||||
(bits >> 48) as u8,
|
||||
(bits >> 40) as u8,
|
||||
(bits >> 32) as u8,
|
||||
(bits >> 24) as u8,
|
||||
(bits >> 16) as u8,
|
||||
(bits >> 8) as u8,
|
||||
bits as u8,
|
||||
];
|
||||
let mut last = [0; 128];
|
||||
let blocklen = blocks.len as usize;
|
||||
last = clone_from_slice_128(last, &blocks.data, 0, blocklen);
|
||||
@@ -253,40 +348,95 @@ const fn blk(block: &[u32], i: usize) -> u32 {
|
||||
rol(value, 1)
|
||||
}
|
||||
|
||||
const fn r0(block: [u32; 16], v: u32, mut w: u32, x: u32, y: u32, mut z: u32, i: usize) -> ([u32; 16], u32, u32) {
|
||||
let n = ((w & (x ^ y)) ^ y).wrapping_add(block[i]).wrapping_add(0x5a82_7999).wrapping_add(rol(v, 5));
|
||||
const fn r0(
|
||||
block: [u32; 16],
|
||||
v: u32,
|
||||
mut w: u32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
mut z: u32,
|
||||
i: usize,
|
||||
) -> ([u32; 16], u32, u32) {
|
||||
let n = ((w & (x ^ y)) ^ y)
|
||||
.wrapping_add(block[i])
|
||||
.wrapping_add(0x5a82_7999)
|
||||
.wrapping_add(rol(v, 5));
|
||||
z = z.wrapping_add(n);
|
||||
w = rol(w, 30);
|
||||
(block, w, z)
|
||||
}
|
||||
|
||||
const fn r1(mut block: [u32; 16], v: u32, mut w: u32, x: u32, y: u32, mut z: u32, i: usize) -> ([u32; 16], u32, u32) {
|
||||
const fn r1(
|
||||
mut block: [u32; 16],
|
||||
v: u32,
|
||||
mut w: u32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
mut z: u32,
|
||||
i: usize,
|
||||
) -> ([u32; 16], u32, u32) {
|
||||
block[i] = blk(&block, i);
|
||||
let n = ((w & (x ^ y)) ^ y).wrapping_add(block[i]).wrapping_add(0x5a82_7999).wrapping_add(rol(v, 5));
|
||||
let n = ((w & (x ^ y)) ^ y)
|
||||
.wrapping_add(block[i])
|
||||
.wrapping_add(0x5a82_7999)
|
||||
.wrapping_add(rol(v, 5));
|
||||
z = z.wrapping_add(n);
|
||||
w = rol(w, 30);
|
||||
(block, w, z)
|
||||
}
|
||||
|
||||
const fn r2(mut block: [u32; 16], v: u32, mut w: u32, x: u32, y: u32, mut z: u32, i: usize) -> ([u32; 16], u32, u32) {
|
||||
const fn r2(
|
||||
mut block: [u32; 16],
|
||||
v: u32,
|
||||
mut w: u32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
mut z: u32,
|
||||
i: usize,
|
||||
) -> ([u32; 16], u32, u32) {
|
||||
block[i] = blk(&block, i);
|
||||
let n = (w ^ x ^ y).wrapping_add(block[i]).wrapping_add(0x6ed9_eba1).wrapping_add(rol(v, 5));
|
||||
let n = (w ^ x ^ y)
|
||||
.wrapping_add(block[i])
|
||||
.wrapping_add(0x6ed9_eba1)
|
||||
.wrapping_add(rol(v, 5));
|
||||
z = z.wrapping_add(n);
|
||||
w = rol(w, 30);
|
||||
(block, w, z)
|
||||
}
|
||||
|
||||
const fn r3(mut block: [u32; 16], v: u32, mut w: u32, x: u32, y: u32, mut z: u32, i: usize) -> ([u32; 16], u32, u32) {
|
||||
const fn r3(
|
||||
mut block: [u32; 16],
|
||||
v: u32,
|
||||
mut w: u32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
mut z: u32,
|
||||
i: usize,
|
||||
) -> ([u32; 16], u32, u32) {
|
||||
block[i] = blk(&block, i);
|
||||
let n = (((w | x) & y) | (w & x)).wrapping_add(block[i]).wrapping_add(0x8f1b_bcdc).wrapping_add(rol(v, 5));
|
||||
let n = (((w | x) & y) | (w & x))
|
||||
.wrapping_add(block[i])
|
||||
.wrapping_add(0x8f1b_bcdc)
|
||||
.wrapping_add(rol(v, 5));
|
||||
z = z.wrapping_add(n);
|
||||
w = rol(w, 30);
|
||||
(block, w, z)
|
||||
}
|
||||
|
||||
const fn r4(mut block: [u32; 16], v: u32, mut w: u32, x: u32, y: u32, mut z: u32, i: usize) -> ([u32; 16], u32, u32) {
|
||||
const fn r4(
|
||||
mut block: [u32; 16],
|
||||
v: u32,
|
||||
mut w: u32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
mut z: u32,
|
||||
i: usize,
|
||||
) -> ([u32; 16], u32, u32) {
|
||||
block[i] = blk(&block, i);
|
||||
let n = (w ^ x ^ y).wrapping_add(block[i]).wrapping_add(0xca62_c1d6).wrapping_add(rol(v, 5));
|
||||
let n = (w ^ x ^ y)
|
||||
.wrapping_add(block[i])
|
||||
.wrapping_add(0xca62_c1d6)
|
||||
.wrapping_add(rol(v, 5));
|
||||
z = z.wrapping_add(n);
|
||||
w = rol(w, 30);
|
||||
(block, w, z)
|
||||
@@ -323,8 +473,8 @@ impl Digest {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Digest {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
impl core::fmt::Display for Digest {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
for i in self.data.iter() {
|
||||
write!(f, "{:08x}", i)?;
|
||||
}
|
||||
|
||||
11
third_party/rust/windows-core/src/imp/waiter.rs
vendored
11
third_party/rust/windows-core/src/imp/waiter.rs
vendored
@@ -1,14 +1,15 @@
|
||||
use super::*;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct Waiter(isize);
|
||||
pub struct WaiterSignaler(isize);
|
||||
pub struct Waiter(HANDLE);
|
||||
pub struct WaiterSignaler(HANDLE);
|
||||
|
||||
unsafe impl Send for WaiterSignaler {}
|
||||
|
||||
impl Waiter {
|
||||
pub fn new() -> crate::Result<(Waiter, WaiterSignaler)> {
|
||||
unsafe {
|
||||
let handle = CreateEventW(std::ptr::null(), 1, 0, std::ptr::null());
|
||||
if handle == 0 {
|
||||
let handle = CreateEventW(core::ptr::null(), 1, 0, core::ptr::null());
|
||||
if handle.is_null() {
|
||||
Err(crate::Error::from_win32())
|
||||
} else {
|
||||
Ok((Waiter(handle), WaiterSignaler(handle)))
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
use super::*;
|
||||
use crate::ComInterface;
|
||||
use std::sync::atomic::{AtomicIsize, Ordering};
|
||||
use crate::Interface;
|
||||
use core::ffi::c_void;
|
||||
use core::mem::{transmute, transmute_copy};
|
||||
use core::ptr::null_mut;
|
||||
use core::sync::atomic::{AtomicIsize, Ordering};
|
||||
|
||||
#[doc(hidden)]
|
||||
#[repr(transparent)]
|
||||
#[derive(Default)]
|
||||
pub struct WeakRefCount(AtomicIsize);
|
||||
@@ -13,28 +15,43 @@ impl WeakRefCount {
|
||||
}
|
||||
|
||||
pub fn add_ref(&self) -> u32 {
|
||||
self.0.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |count_or_pointer| then_some(!is_weak_ref(count_or_pointer), count_or_pointer + 1)).map(|u| u as u32 + 1).unwrap_or_else(|pointer| unsafe { TearOff::decode(pointer).strong_count.add_ref() })
|
||||
self.0
|
||||
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |count_or_pointer| {
|
||||
bool::then_some(!is_weak_ref(count_or_pointer), count_or_pointer + 1)
|
||||
})
|
||||
.map(|u| u as u32 + 1)
|
||||
.unwrap_or_else(|pointer| unsafe { TearOff::decode(pointer).strong_count.add_ref() })
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn is_one(&self) -> bool {
|
||||
self.0.load(Ordering::Acquire) == 1
|
||||
}
|
||||
|
||||
pub fn release(&self) -> u32 {
|
||||
self.0.fetch_update(Ordering::Release, Ordering::Relaxed, |count_or_pointer| then_some(!is_weak_ref(count_or_pointer), count_or_pointer - 1)).map(|u| u as u32 - 1).unwrap_or_else(|pointer| unsafe {
|
||||
let tear_off = TearOff::decode(pointer);
|
||||
let remaining = tear_off.strong_count.release();
|
||||
self.0
|
||||
.fetch_update(Ordering::Release, Ordering::Relaxed, |count_or_pointer| {
|
||||
bool::then_some(!is_weak_ref(count_or_pointer), count_or_pointer - 1)
|
||||
})
|
||||
.map(|u| u as u32 - 1)
|
||||
.unwrap_or_else(|pointer| unsafe {
|
||||
let tear_off = TearOff::decode(pointer);
|
||||
let remaining = tear_off.strong_count.release();
|
||||
|
||||
// If this is the last strong reference, we can release the weak reference implied by the strong reference.
|
||||
// There may still be weak references, so the WeakRelease is called to handle such possibilities.
|
||||
if remaining == 0 {
|
||||
TearOff::WeakRelease(&mut tear_off.weak_vtable as *mut _ as _);
|
||||
}
|
||||
// If this is the last strong reference, we can release the weak reference implied by the strong reference.
|
||||
// There may still be weak references, so the WeakRelease is called to handle such possibilities.
|
||||
if remaining == 0 {
|
||||
TearOff::WeakRelease(&mut tear_off.weak_vtable as *mut _ as _);
|
||||
}
|
||||
|
||||
remaining
|
||||
})
|
||||
remaining
|
||||
})
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
pub unsafe fn query(&self, iid: *const crate::GUID, object: *mut std::ffi::c_void) -> *mut std::ffi::c_void {
|
||||
if *iid != IWeakReferenceSource::IID {
|
||||
return std::ptr::null_mut();
|
||||
pub unsafe fn query(&self, iid: &crate::GUID, object: *mut c_void) -> *mut c_void {
|
||||
if iid != &IWeakReferenceSource::IID {
|
||||
return null_mut();
|
||||
}
|
||||
|
||||
let mut count_or_pointer = self.0.load(Ordering::Relaxed);
|
||||
@@ -44,13 +61,18 @@ impl WeakRefCount {
|
||||
}
|
||||
|
||||
let tear_off = TearOff::new(object, count_or_pointer as u32);
|
||||
let tear_off_ptr: *mut std::ffi::c_void = std::mem::transmute_copy(&tear_off);
|
||||
let encoding: usize = ((tear_off_ptr as usize) >> 1) | (1 << (std::mem::size_of::<usize>() * 8 - 1));
|
||||
let tear_off_ptr: *mut c_void = transmute_copy(&tear_off);
|
||||
let encoding: usize = ((tear_off_ptr as usize) >> 1) | (1 << (usize::BITS - 1));
|
||||
|
||||
loop {
|
||||
match self.0.compare_exchange_weak(count_or_pointer, encoding as isize, Ordering::AcqRel, Ordering::Relaxed) {
|
||||
match self.0.compare_exchange_weak(
|
||||
count_or_pointer,
|
||||
encoding as isize,
|
||||
Ordering::AcqRel,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => {
|
||||
let result: *mut std::ffi::c_void = std::mem::transmute(tear_off);
|
||||
let result: *mut c_void = transmute(tear_off);
|
||||
TearOff::from_strong_ptr(result).strong_count.add_ref();
|
||||
return result;
|
||||
}
|
||||
@@ -61,7 +83,10 @@ impl WeakRefCount {
|
||||
return TearOff::from_encoding(count_or_pointer);
|
||||
}
|
||||
|
||||
TearOff::from_strong_ptr(tear_off_ptr).strong_count.0.store(count_or_pointer as i32, Ordering::SeqCst);
|
||||
TearOff::from_strong_ptr(tear_off_ptr)
|
||||
.strong_count
|
||||
.0
|
||||
.store(count_or_pointer as i32, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,15 +99,15 @@ fn is_weak_ref(value: isize) -> bool {
|
||||
struct TearOff {
|
||||
strong_vtable: *const IWeakReferenceSource_Vtbl,
|
||||
weak_vtable: *const IWeakReference_Vtbl,
|
||||
object: *mut std::ffi::c_void,
|
||||
object: *mut c_void,
|
||||
strong_count: RefCount,
|
||||
weak_count: RefCount,
|
||||
}
|
||||
|
||||
impl TearOff {
|
||||
#[allow(clippy::new_ret_no_self)]
|
||||
unsafe fn new(object: *mut std::ffi::c_void, strong_count: u32) -> IWeakReferenceSource {
|
||||
std::mem::transmute(std::boxed::Box::new(TearOff {
|
||||
unsafe fn new(object: *mut c_void, strong_count: u32) -> IWeakReferenceSource {
|
||||
transmute(Box::new(TearOff {
|
||||
strong_vtable: &Self::STRONG_VTABLE,
|
||||
weak_vtable: &Self::WEAK_VTABLE,
|
||||
object,
|
||||
@@ -91,43 +116,63 @@ impl TearOff {
|
||||
}))
|
||||
}
|
||||
|
||||
unsafe fn from_encoding(encoding: isize) -> *mut std::ffi::c_void {
|
||||
unsafe fn from_encoding(encoding: isize) -> *mut c_void {
|
||||
let tear_off = TearOff::decode(encoding);
|
||||
tear_off.strong_count.add_ref();
|
||||
tear_off as *mut _ as *mut _
|
||||
}
|
||||
|
||||
const STRONG_VTABLE: IWeakReferenceSource_Vtbl = IWeakReferenceSource_Vtbl {
|
||||
base__: crate::IUnknown_Vtbl { QueryInterface: Self::StrongQueryInterface, AddRef: Self::StrongAddRef, Release: Self::StrongRelease },
|
||||
base__: crate::IUnknown_Vtbl {
|
||||
QueryInterface: Self::StrongQueryInterface,
|
||||
AddRef: Self::StrongAddRef,
|
||||
Release: Self::StrongRelease,
|
||||
},
|
||||
GetWeakReference: Self::StrongDowngrade,
|
||||
};
|
||||
|
||||
const WEAK_VTABLE: IWeakReference_Vtbl = IWeakReference_Vtbl {
|
||||
base__: crate::IUnknown_Vtbl { QueryInterface: Self::WeakQueryInterface, AddRef: Self::WeakAddRef, Release: Self::WeakRelease },
|
||||
base__: crate::IUnknown_Vtbl {
|
||||
QueryInterface: Self::WeakQueryInterface,
|
||||
AddRef: Self::WeakAddRef,
|
||||
Release: Self::WeakRelease,
|
||||
},
|
||||
Resolve: Self::WeakUpgrade,
|
||||
};
|
||||
|
||||
unsafe fn from_strong_ptr<'a>(this: *mut std::ffi::c_void) -> &'a mut Self {
|
||||
&mut *(this as *mut *mut std::ffi::c_void as *mut Self)
|
||||
unsafe fn from_strong_ptr<'a>(this: *mut c_void) -> &'a mut Self {
|
||||
&mut *(this as *mut *mut c_void as *mut Self)
|
||||
}
|
||||
|
||||
unsafe fn from_weak_ptr<'a>(this: *mut std::ffi::c_void) -> &'a mut Self {
|
||||
&mut *((this as *mut *mut std::ffi::c_void).sub(1) as *mut Self)
|
||||
unsafe fn from_weak_ptr<'a>(this: *mut c_void) -> &'a mut Self {
|
||||
&mut *((this as *mut *mut c_void).sub(1) as *mut Self)
|
||||
}
|
||||
|
||||
unsafe fn decode<'a>(value: isize) -> &'a mut Self {
|
||||
std::mem::transmute(value << 1)
|
||||
transmute(value << 1)
|
||||
}
|
||||
|
||||
unsafe fn query_interface(&self, iid: *const crate::GUID, interface: *mut *mut std::ffi::c_void) -> crate::HRESULT {
|
||||
((*(*(self.object as *mut *mut crate::IUnknown_Vtbl))).QueryInterface)(self.object, iid, interface)
|
||||
unsafe fn query_interface(
|
||||
&self,
|
||||
iid: *const crate::GUID,
|
||||
interface: *mut *mut c_void,
|
||||
) -> crate::HRESULT {
|
||||
((*(*(self.object as *mut *mut crate::IUnknown_Vtbl))).QueryInterface)(
|
||||
self.object,
|
||||
iid,
|
||||
interface,
|
||||
)
|
||||
}
|
||||
|
||||
unsafe extern "system" fn StrongQueryInterface(ptr: *mut std::ffi::c_void, iid: *const crate::GUID, interface: *mut *mut std::ffi::c_void) -> crate::HRESULT {
|
||||
unsafe extern "system" fn StrongQueryInterface(
|
||||
ptr: *mut c_void,
|
||||
iid: *const crate::GUID,
|
||||
interface: *mut *mut c_void,
|
||||
) -> crate::HRESULT {
|
||||
let this = Self::from_strong_ptr(ptr);
|
||||
|
||||
if iid.is_null() || interface.is_null() {
|
||||
return ::windows_core::HRESULT(-2147467261); // E_POINTER
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
// Only directly respond to queries for the the tear-off's strong interface. This is
|
||||
@@ -143,18 +188,29 @@ impl TearOff {
|
||||
this.query_interface(iid, interface)
|
||||
}
|
||||
|
||||
unsafe extern "system" fn WeakQueryInterface(ptr: *mut std::ffi::c_void, iid: *const crate::GUID, interface: *mut *mut std::ffi::c_void) -> crate::HRESULT {
|
||||
unsafe extern "system" fn WeakQueryInterface(
|
||||
ptr: *mut c_void,
|
||||
iid: *const crate::GUID,
|
||||
interface: *mut *mut c_void,
|
||||
) -> crate::HRESULT {
|
||||
let this = Self::from_weak_ptr(ptr);
|
||||
|
||||
if iid.is_null() || interface.is_null() {
|
||||
return ::windows_core::HRESULT(-2147467261); // E_POINTER
|
||||
return E_POINTER;
|
||||
}
|
||||
|
||||
// While the weak vtable is packed into the same allocation as the strong vtable and
|
||||
// tear-off, it represents a distinct COM identity and thus does not share or delegate to
|
||||
// the object.
|
||||
|
||||
*interface = if *iid == IWeakReference::IID || *iid == crate::IUnknown::IID || *iid == IAgileObject::IID { ptr } else { std::ptr::null_mut() };
|
||||
*interface = if *iid == IWeakReference::IID
|
||||
|| *iid == crate::IUnknown::IID
|
||||
|| *iid == IAgileObject::IID
|
||||
{
|
||||
ptr
|
||||
} else {
|
||||
null_mut()
|
||||
};
|
||||
|
||||
// TODO: implement IMarshal
|
||||
|
||||
@@ -166,21 +222,21 @@ impl TearOff {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern "system" fn StrongAddRef(ptr: *mut std::ffi::c_void) -> u32 {
|
||||
unsafe extern "system" fn StrongAddRef(ptr: *mut c_void) -> u32 {
|
||||
let this = Self::from_strong_ptr(ptr);
|
||||
|
||||
// Implement `AddRef` directly as we own the strong reference.
|
||||
this.strong_count.add_ref()
|
||||
}
|
||||
|
||||
unsafe extern "system" fn WeakAddRef(ptr: *mut std::ffi::c_void) -> u32 {
|
||||
unsafe extern "system" fn WeakAddRef(ptr: *mut c_void) -> u32 {
|
||||
let this = Self::from_weak_ptr(ptr);
|
||||
|
||||
// Implement `AddRef` directly as we own the weak reference.
|
||||
this.weak_count.add_ref()
|
||||
}
|
||||
|
||||
unsafe extern "system" fn StrongRelease(ptr: *mut std::ffi::c_void) -> u32 {
|
||||
unsafe extern "system" fn StrongRelease(ptr: *mut c_void) -> u32 {
|
||||
let this = Self::from_strong_ptr(ptr);
|
||||
|
||||
// Forward strong `Release` to the object so that it can destroy itself. It will then
|
||||
@@ -188,7 +244,7 @@ impl TearOff {
|
||||
((*(*(this.object as *mut *mut crate::IUnknown_Vtbl))).Release)(this.object)
|
||||
}
|
||||
|
||||
unsafe extern "system" fn WeakRelease(ptr: *mut std::ffi::c_void) -> u32 {
|
||||
unsafe extern "system" fn WeakRelease(ptr: *mut c_void) -> u32 {
|
||||
let this = Self::from_weak_ptr(ptr);
|
||||
|
||||
// Implement `Release` directly as we own the weak reference.
|
||||
@@ -197,13 +253,16 @@ impl TearOff {
|
||||
// If there are no remaining references, it means that the object has already been
|
||||
// destroyed. Go ahead and destroy the tear-off.
|
||||
if remaining == 0 {
|
||||
let _ = std::boxed::Box::from_raw(this);
|
||||
let _ = Box::from_raw(this);
|
||||
}
|
||||
|
||||
remaining
|
||||
}
|
||||
|
||||
unsafe extern "system" fn StrongDowngrade(ptr: *mut std::ffi::c_void, interface: *mut *mut std::ffi::c_void) -> crate::HRESULT {
|
||||
unsafe extern "system" fn StrongDowngrade(
|
||||
ptr: *mut c_void,
|
||||
interface: *mut *mut c_void,
|
||||
) -> crate::HRESULT {
|
||||
let this = Self::from_strong_ptr(ptr);
|
||||
|
||||
// The strong vtable hands out a reference to the weak vtable. This is always safe and
|
||||
@@ -214,7 +273,11 @@ impl TearOff {
|
||||
crate::HRESULT(0)
|
||||
}
|
||||
|
||||
unsafe extern "system" fn WeakUpgrade(ptr: *mut std::ffi::c_void, iid: *const crate::GUID, interface: *mut *mut std::ffi::c_void) -> crate::HRESULT {
|
||||
unsafe extern "system" fn WeakUpgrade(
|
||||
ptr: *mut c_void,
|
||||
iid: *const crate::GUID,
|
||||
interface: *mut *mut c_void,
|
||||
) -> crate::HRESULT {
|
||||
let this = Self::from_weak_ptr(ptr);
|
||||
|
||||
this.strong_count
|
||||
@@ -222,7 +285,7 @@ impl TearOff {
|
||||
.fetch_update(Ordering::Acquire, Ordering::Relaxed, |count| {
|
||||
// Attempt to acquire a strong reference count to stabilize the object for the duration
|
||||
// of the `QueryInterface` call.
|
||||
then_some(count != 0, count + 1)
|
||||
bool::then_some(count != 0, count + 1)
|
||||
})
|
||||
.map(|_| {
|
||||
// Let the object respond to the upgrade query.
|
||||
@@ -233,7 +296,7 @@ impl TearOff {
|
||||
result
|
||||
})
|
||||
.unwrap_or_else(|_| {
|
||||
*interface = std::ptr::null_mut();
|
||||
*interface = null_mut();
|
||||
crate::HRESULT(0)
|
||||
})
|
||||
}
|
||||
|
||||
11
third_party/rust/windows-core/src/imp/windows.rs
vendored
Normal file
11
third_party/rust/windows-core/src/imp/windows.rs
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
mod factory_cache;
|
||||
pub use factory_cache::*;
|
||||
|
||||
mod generic_factory;
|
||||
pub use generic_factory::*;
|
||||
|
||||
mod waiter;
|
||||
pub use waiter::*;
|
||||
|
||||
mod bindings;
|
||||
pub use bindings::*;
|
||||
165
third_party/rust/windows-core/src/inspectable.rs
vendored
165
third_party/rust/windows-core/src/inspectable.rs
vendored
@@ -1,20 +1,34 @@
|
||||
use super::*;
|
||||
use core::ffi::c_void;
|
||||
use core::ptr::null_mut;
|
||||
|
||||
/// A WinRT object that may be used as a polymorphic stand-in for any WinRT class, interface, or boxed value.
|
||||
/// [`IInspectable`] represents the
|
||||
/// [IInspectable](https://docs.microsoft.com/en-us/windows/win32/api/inspectable/nn-inspectable-iinspectable)
|
||||
/// interface.
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct IInspectable(pub IUnknown);
|
||||
|
||||
interface_hierarchy!(IInspectable, IUnknown);
|
||||
|
||||
impl IInspectable {
|
||||
/// Returns the canonical type name for the underlying object.
|
||||
#[cfg(windows)]
|
||||
pub fn GetRuntimeClassName(&self) -> Result<HSTRING> {
|
||||
unsafe {
|
||||
let mut abi = std::ptr::null_mut();
|
||||
(self.vtable().GetRuntimeClassName)(std::mem::transmute_copy(self), &mut abi).ok()?;
|
||||
Ok(std::mem::transmute(abi))
|
||||
let mut abi = null_mut();
|
||||
(self.vtable().GetRuntimeClassName)(core::mem::transmute_copy(self), &mut abi).ok()?;
|
||||
Ok(core::mem::transmute::<*mut c_void, HSTRING>(abi))
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the trust level of the current object.
|
||||
pub fn GetTrustLevel(&self) -> Result<i32> {
|
||||
unsafe {
|
||||
let mut value = 0;
|
||||
(self.vtable().GetTrustLevel)(core::mem::transmute_copy(self), &mut value).ok()?;
|
||||
Ok(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,126 +37,79 @@ impl IInspectable {
|
||||
#[repr(C)]
|
||||
pub struct IInspectable_Vtbl {
|
||||
pub base: IUnknown_Vtbl,
|
||||
pub GetIids: unsafe extern "system" fn(this: *mut std::ffi::c_void, count: *mut u32, values: *mut *mut GUID) -> HRESULT,
|
||||
pub GetRuntimeClassName: unsafe extern "system" fn(this: *mut std::ffi::c_void, value: *mut *mut std::ffi::c_void) -> HRESULT,
|
||||
pub GetTrustLevel: unsafe extern "system" fn(this: *mut std::ffi::c_void, value: *mut i32) -> HRESULT,
|
||||
pub GetIids: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
count: *mut u32,
|
||||
values: *mut *mut GUID,
|
||||
) -> HRESULT,
|
||||
pub GetRuntimeClassName:
|
||||
unsafe extern "system" fn(this: *mut c_void, value: *mut *mut c_void) -> HRESULT,
|
||||
pub GetTrustLevel: unsafe extern "system" fn(this: *mut c_void, value: *mut i32) -> HRESULT,
|
||||
}
|
||||
|
||||
unsafe impl Interface for IInspectable {
|
||||
type Vtable = IInspectable_Vtbl;
|
||||
}
|
||||
|
||||
unsafe impl ComInterface for IInspectable {
|
||||
const IID: GUID = GUID::from_u128(0xaf86e2e0_b12d_4c6a_9c5a_d7aa65101e90);
|
||||
}
|
||||
|
||||
impl CanInto<IUnknown> for IInspectable {}
|
||||
|
||||
impl RuntimeType for IInspectable {
|
||||
const SIGNATURE: crate::imp::ConstBuffer = crate::imp::ConstBuffer::from_slice(b"cinterface(IInspectable)");
|
||||
const SIGNATURE: imp::ConstBuffer = imp::ConstBuffer::from_slice(b"cinterface(IInspectable)");
|
||||
}
|
||||
|
||||
impl RuntimeName for IInspectable {}
|
||||
|
||||
#[cfg(feature = "implement")]
|
||||
impl IInspectable_Vtbl {
|
||||
pub const fn new<Identity: IUnknownImpl, Name: RuntimeName, const OFFSET: isize>() -> Self {
|
||||
unsafe extern "system" fn GetIids(_: *mut std::ffi::c_void, count: *mut u32, values: *mut *mut GUID) -> HRESULT {
|
||||
unsafe extern "system" fn GetIids(
|
||||
_: *mut c_void,
|
||||
count: *mut u32,
|
||||
values: *mut *mut GUID,
|
||||
) -> HRESULT {
|
||||
if count.is_null() || values.is_null() {
|
||||
return imp::E_POINTER;
|
||||
}
|
||||
// Note: even if we end up implementing this in future, it still doesn't need a this pointer
|
||||
// since the data to be returned is type- not instance-specific so can be shared for all
|
||||
// interfaces.
|
||||
*count = 0;
|
||||
*values = std::ptr::null_mut();
|
||||
*values = null_mut();
|
||||
HRESULT(0)
|
||||
}
|
||||
unsafe extern "system" fn GetRuntimeClassName<T: RuntimeName>(_: *mut std::ffi::c_void, value: *mut *mut std::ffi::c_void) -> HRESULT {
|
||||
let h: HSTRING = T::NAME.into(); // TODO: should be try_into
|
||||
*value = std::mem::transmute(h);
|
||||
HRESULT(0)
|
||||
}
|
||||
unsafe extern "system" fn GetTrustLevel(_: *mut std::ffi::c_void, value: *mut i32) -> HRESULT {
|
||||
// Note: even if we end up implementing this in future, it still doesn't need a this pointer
|
||||
// since the data to be returned is type- not instance-specific so can be shared for all
|
||||
// interfaces.
|
||||
*value = 0;
|
||||
HRESULT(0)
|
||||
}
|
||||
Self { base: IUnknown_Vtbl::new::<Identity, OFFSET>(), GetIids, GetRuntimeClassName: GetRuntimeClassName::<Name>, GetTrustLevel }
|
||||
}
|
||||
}
|
||||
unsafe extern "system" fn GetRuntimeClassName<T: RuntimeName>(
|
||||
_: *mut c_void,
|
||||
value: *mut *mut c_void,
|
||||
) -> HRESULT {
|
||||
if value.is_null() {
|
||||
return imp::E_POINTER;
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for IInspectable {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
// Attempts to retrieve the string representation of the object via the
|
||||
// IStringable interface. If that fails, it will use the canonical type
|
||||
// name to give some idea of what the object represents.
|
||||
let name = <Self as ComInterface>::cast::<imp::IStringable>(self).and_then(|s| s.ToString()).or_else(|_| self.GetRuntimeClassName()).unwrap_or_default();
|
||||
write!(f, "\"{}\"", name)
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
*value = core::mem::transmute::<HSTRING, *mut c_void>(T::NAME.into());
|
||||
}
|
||||
|
||||
macro_rules! primitive_boxed_type {
|
||||
($(($t:ty, $m:ident)),+) => {
|
||||
$(impl std::convert::TryFrom<$t> for IInspectable {
|
||||
type Error = Error;
|
||||
fn try_from(value: $t) -> Result<Self> {
|
||||
imp::PropertyValue::$m(value)
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
*value = core::ptr::null_mut();
|
||||
}
|
||||
|
||||
HRESULT(0)
|
||||
}
|
||||
impl std::convert::TryFrom<IInspectable> for $t {
|
||||
type Error = Error;
|
||||
fn try_from(value: IInspectable) -> Result<Self> {
|
||||
<IInspectable as ComInterface>::cast::<imp::IReference<$t>>(&value)?.Value()
|
||||
unsafe extern "system" fn GetTrustLevel<T: IUnknownImpl, const OFFSET: isize>(
|
||||
this: *mut c_void,
|
||||
value: *mut i32,
|
||||
) -> HRESULT {
|
||||
if value.is_null() {
|
||||
return imp::E_POINTER;
|
||||
}
|
||||
let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T;
|
||||
(*this).GetTrustLevel(value)
|
||||
}
|
||||
Self {
|
||||
base: IUnknown_Vtbl::new::<Identity, OFFSET>(),
|
||||
GetIids,
|
||||
GetRuntimeClassName: GetRuntimeClassName::<Name>,
|
||||
GetTrustLevel: GetTrustLevel::<Identity, OFFSET>,
|
||||
}
|
||||
impl std::convert::TryFrom<&IInspectable> for $t {
|
||||
type Error = Error;
|
||||
fn try_from(value: &IInspectable) -> Result<Self> {
|
||||
<IInspectable as ComInterface>::cast::<imp::IReference<$t>>(value)?.Value()
|
||||
}
|
||||
})*
|
||||
};
|
||||
}
|
||||
primitive_boxed_type! {
|
||||
(bool, CreateBoolean),
|
||||
(u8, CreateUInt8),
|
||||
(i16, CreateInt16),
|
||||
(u16, CreateUInt16),
|
||||
(i32, CreateInt32),
|
||||
(u32, CreateUInt32),
|
||||
(i64, CreateInt64),
|
||||
(u64, CreateUInt64),
|
||||
(f32, CreateSingle),
|
||||
(f64, CreateDouble)
|
||||
}
|
||||
impl std::convert::TryFrom<&str> for IInspectable {
|
||||
type Error = Error;
|
||||
fn try_from(value: &str) -> Result<Self> {
|
||||
let value: HSTRING = value.into();
|
||||
imp::PropertyValue::CreateString(&value)
|
||||
}
|
||||
}
|
||||
impl std::convert::TryFrom<HSTRING> for IInspectable {
|
||||
type Error = Error;
|
||||
fn try_from(value: HSTRING) -> Result<Self> {
|
||||
imp::PropertyValue::CreateString(&value)
|
||||
}
|
||||
}
|
||||
impl std::convert::TryFrom<&HSTRING> for IInspectable {
|
||||
type Error = Error;
|
||||
fn try_from(value: &HSTRING) -> Result<Self> {
|
||||
imp::PropertyValue::CreateString(value)
|
||||
}
|
||||
}
|
||||
impl std::convert::TryFrom<IInspectable> for HSTRING {
|
||||
type Error = Error;
|
||||
fn try_from(value: IInspectable) -> Result<Self> {
|
||||
<IInspectable as ComInterface>::cast::<imp::IReference<HSTRING>>(&value)?.Value()
|
||||
}
|
||||
}
|
||||
impl std::convert::TryFrom<&IInspectable> for HSTRING {
|
||||
type Error = Error;
|
||||
fn try_from(value: &IInspectable) -> Result<Self> {
|
||||
<IInspectable as ComInterface>::cast::<imp::IReference<HSTRING>>(value)?.Value()
|
||||
}
|
||||
}
|
||||
|
||||
289
third_party/rust/windows-core/src/interface.rs
vendored
289
third_party/rust/windows-core/src/interface.rs
vendored
@@ -1,14 +1,29 @@
|
||||
use super::*;
|
||||
use core::any::Any;
|
||||
use core::ffi::c_void;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::{forget, transmute_copy, MaybeUninit};
|
||||
use core::ptr::NonNull;
|
||||
|
||||
/// Provides low-level access to an interface vtable.
|
||||
///
|
||||
/// This trait is automatically implemented by the generated bindings and should not be
|
||||
/// implemented manually.
|
||||
///
|
||||
/// # Safety
|
||||
pub unsafe trait Interface: Sized {
|
||||
pub unsafe trait Interface: Sized + Clone {
|
||||
#[doc(hidden)]
|
||||
type Vtable;
|
||||
|
||||
/// The `GUID` associated with the interface.
|
||||
const IID: GUID;
|
||||
|
||||
#[doc(hidden)]
|
||||
const UNKNOWN: bool = true;
|
||||
|
||||
/// A reference to the interface's vtable
|
||||
#[doc(hidden)]
|
||||
#[inline(always)]
|
||||
fn vtable(&self) -> &Self::Vtable {
|
||||
// SAFETY: the implementor of the trait guarantees that `Self` is castable to its vtable
|
||||
unsafe { self.assume_vtable::<Self>() }
|
||||
@@ -21,22 +36,24 @@ pub unsafe trait Interface: Sized {
|
||||
/// This is safe if `T` is an equivalent interface to `Self` or a super interface.
|
||||
/// In other words, `T::Vtable` must be equivalent to the beginning of `Self::Vtable`.
|
||||
#[doc(hidden)]
|
||||
#[inline(always)]
|
||||
unsafe fn assume_vtable<T: Interface>(&self) -> &T::Vtable {
|
||||
&**(self.as_raw() as *mut *mut T::Vtable)
|
||||
}
|
||||
|
||||
/// Returns the raw COM interface pointer. The resulting pointer continues to be owned by the `Interface` implementation.
|
||||
#[inline(always)]
|
||||
fn as_raw(&self) -> *mut std::ffi::c_void {
|
||||
fn as_raw(&self) -> *mut c_void {
|
||||
// SAFETY: implementors of this trait must guarantee that the implementing type has a pointer in-memory representation
|
||||
unsafe { std::mem::transmute_copy(self) }
|
||||
unsafe { transmute_copy(self) }
|
||||
}
|
||||
|
||||
/// Returns the raw COM interface pointer and releases ownership. It the caller's responsibility to release the COM interface pointer.
|
||||
fn into_raw(self) -> *mut std::ffi::c_void {
|
||||
#[inline(always)]
|
||||
fn into_raw(self) -> *mut c_void {
|
||||
// SAFETY: implementors of this trait must guarantee that the implementing type has a pointer in-memory representation
|
||||
let raw = self.as_raw();
|
||||
std::mem::forget(self);
|
||||
forget(self);
|
||||
raw
|
||||
}
|
||||
|
||||
@@ -46,8 +63,8 @@ pub unsafe trait Interface: Sized {
|
||||
///
|
||||
/// The `raw` pointer must be owned by the caller and represent a valid COM interface pointer. In other words,
|
||||
/// it must point to a vtable beginning with the `IUnknown` function pointers and match the vtable of `Interface`.
|
||||
unsafe fn from_raw(raw: *mut std::ffi::c_void) -> Self {
|
||||
std::mem::transmute_copy(&raw)
|
||||
unsafe fn from_raw(raw: *mut c_void) -> Self {
|
||||
transmute_copy(&raw)
|
||||
}
|
||||
|
||||
/// Creates an `Interface` that is valid so long as the `raw` COM interface pointer is valid.
|
||||
@@ -56,17 +73,269 @@ pub unsafe trait Interface: Sized {
|
||||
///
|
||||
/// The `raw` pointer must be a valid COM interface pointer. In other words, it must point to a vtable
|
||||
/// beginning with the `IUnknown` function pointers and match the vtable of `Interface`.
|
||||
unsafe fn from_raw_borrowed(raw: &*mut std::ffi::c_void) -> Option<&Self> {
|
||||
#[inline(always)]
|
||||
unsafe fn from_raw_borrowed(raw: &*mut c_void) -> Option<&Self> {
|
||||
if raw.is_null() {
|
||||
None
|
||||
} else {
|
||||
Some(std::mem::transmute_copy(&raw))
|
||||
Some(transmute_copy(&raw))
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to cast the current interface to another interface using `QueryInterface`.
|
||||
///
|
||||
/// The name `cast` is preferred to `query` because there is a WinRT method named query but not one
|
||||
/// named cast.
|
||||
#[inline(always)]
|
||||
fn cast<T: Interface>(&self) -> Result<T> {
|
||||
// SAFETY: `result` is valid for writing an interface pointer and it is safe
|
||||
// to cast the `result` pointer as `T` on success because we are using the `IID` tied
|
||||
// to `T` which the implementor of `Interface` has guaranteed is correct
|
||||
unsafe {
|
||||
// If query() returns a failure code then we propagate that failure code to the caller.
|
||||
// In that case, we ignore the contents of 'result' (which will _not_ be dropped,
|
||||
// because MaybeUninit intentionally does not drop its contents).
|
||||
//
|
||||
// This guards against implementations of COM interfaces which may store non-null values
|
||||
// in 'result' but still return E_NOINTERFACE.
|
||||
let mut result = MaybeUninit::<Option<T>>::zeroed();
|
||||
self.query(&T::IID, result.as_mut_ptr() as _).ok()?;
|
||||
|
||||
// If we get here, then query() has succeeded, but we still need to double-check
|
||||
// that the output pointer is non-null.
|
||||
if let Some(obj) = result.assume_init() {
|
||||
Ok(obj)
|
||||
} else {
|
||||
Err(imp::E_POINTER.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This casts the given COM interface to [`&dyn Any`].
|
||||
///
|
||||
/// Applications should generally _not_ call this method directly. Instead, use the
|
||||
/// [`Interface::cast_object_ref`] or [`Interface::cast_object`] methods.
|
||||
///
|
||||
/// `T` must be a type that has been annotated with `#[implement]`; this is checked at
|
||||
/// compile-time by the generic constraints of this method. However, note that the
|
||||
/// returned `&dyn Any` refers to the _outer_ implementation object that was generated by
|
||||
/// `#[implement]`, i.e. the `MyApp_Impl` type, not the inner `MyApp` type.
|
||||
///
|
||||
/// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust
|
||||
/// object that contains non-static lifetimes, then this function will return `Err(E_NOINTERFACE)`.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// **IMPORTANT!!** This uses a non-standard protocol for QueryInterface! The `DYNAMIC_CAST_IID`
|
||||
/// IID identifies this protocol, but there is no `IDynamicCast` interface. Instead, objects
|
||||
/// that recognize `DYNAMIC_CAST_IID` simply store their `&dyn Any` directly at the interface
|
||||
/// pointer that was passed to `QueryInterface. This means that the returned value has a
|
||||
/// size that is twice as large (`size_of::<&dyn Any>() == 2 * size_of::<*const c_void>()`).
|
||||
///
|
||||
/// This means that callers that use this protocol cannot simply pass `&mut ptr` for
|
||||
/// an ordinary single-pointer-sized pointer. Only this method understands this protocol.
|
||||
///
|
||||
/// Another part of this protocol is that the implementation of `QueryInterface` _does not_
|
||||
/// AddRef the object. The caller must guarantee the liveness of the COM object. In Rust,
|
||||
/// this means tying the lifetime of the IUnknown* that we used for the QueryInterface
|
||||
/// call to the lifetime of the returned `&dyn Any` value.
|
||||
///
|
||||
/// This method preserves type safety and relies on these invariants:
|
||||
///
|
||||
/// * All `QueryInterface` implementations that recognize `DYNAMIC_CAST_IID` are generated by
|
||||
/// the `#[implement]` macro and respect the rules described here.
|
||||
#[inline(always)]
|
||||
fn cast_to_any<T>(&self) -> Result<&dyn Any>
|
||||
where
|
||||
T: ComObjectInner,
|
||||
T::Outer: Any + 'static + IUnknownImpl<Impl = T>,
|
||||
{
|
||||
unsafe {
|
||||
let mut any_ref_arg: MaybeUninit<&dyn Any> = MaybeUninit::zeroed();
|
||||
self.query(
|
||||
&DYNAMIC_CAST_IID,
|
||||
any_ref_arg.as_mut_ptr() as *mut *mut c_void,
|
||||
)
|
||||
.ok()?;
|
||||
Ok(any_ref_arg.assume_init())
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the given COM interface refers to an implementation of `T`.
|
||||
///
|
||||
/// `T` must be a type that has been annotated with `#[implement]`; this is checked at
|
||||
/// compile-time by the generic constraints of this method.
|
||||
///
|
||||
/// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust
|
||||
/// object that contains non-static lifetimes, then this function will return `false`.
|
||||
#[inline(always)]
|
||||
fn is_object<T>(&self) -> bool
|
||||
where
|
||||
T: ComObjectInner,
|
||||
T::Outer: Any + 'static + IUnknownImpl<Impl = T>,
|
||||
{
|
||||
if let Ok(any) = self.cast_to_any::<T>() {
|
||||
any.is::<T::Outer>()
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/// This casts the given COM interface to [`&dyn Any`]. It returns a reference to the "outer"
|
||||
/// object, e.g. `&MyApp_Impl`, not the inner `&MyApp` object.
|
||||
///
|
||||
/// `T` must be a type that has been annotated with `#[implement]`; this is checked at
|
||||
/// compile-time by the generic constraints of this method. However, note that the
|
||||
/// returned `&dyn Any` refers to the _outer_ implementation object that was generated by
|
||||
/// `#[implement]`, i.e. the `MyApp_Impl` type, not the inner `MyApp` type.
|
||||
///
|
||||
/// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust
|
||||
/// object that contains non-static lifetimes, then this function will return `Err(E_NOINTERFACE)`.
|
||||
///
|
||||
/// The returned value is borrowed. If you need an owned (counted) reference, then use
|
||||
/// [`Interface::cast_object`].
|
||||
#[inline(always)]
|
||||
fn cast_object_ref<T>(&self) -> Result<&T::Outer>
|
||||
where
|
||||
T: ComObjectInner,
|
||||
T::Outer: Any + 'static + IUnknownImpl<Impl = T>,
|
||||
{
|
||||
let any: &dyn Any = self.cast_to_any::<T>()?;
|
||||
if let Some(outer) = any.downcast_ref::<T::Outer>() {
|
||||
Ok(outer)
|
||||
} else {
|
||||
Err(imp::E_NOINTERFACE.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// This casts the given COM interface to [`&dyn Any`]. It returns a reference to the "outer"
|
||||
/// object, e.g. `MyApp_Impl`, not the inner `MyApp` object.
|
||||
///
|
||||
/// `T` must be a type that has been annotated with `#[implement]`; this is checked at
|
||||
/// compile-time by the generic constraints of this method. However, note that the
|
||||
/// returned `&dyn Any` refers to the _outer_ implementation object that was generated by
|
||||
/// `#[implement]`, i.e. the `MyApp_Impl` type, not the inner `MyApp` type.
|
||||
///
|
||||
/// If the given object is not a Rust object, or is a Rust object but not `T`, or is a Rust
|
||||
/// object that contains non-static lifetimes, then this function will return `Err(E_NOINTERFACE)`.
|
||||
///
|
||||
/// The returned value is an owned (counted) reference; this function calls `AddRef` on the
|
||||
/// underlying COM object. If you do not need an owned reference, then you can use the
|
||||
/// [`Interface::cast_object_ref`] method instead, and avoid the cost of `AddRef` / `Release`.
|
||||
#[inline(always)]
|
||||
fn cast_object<T>(&self) -> Result<ComObject<T>>
|
||||
where
|
||||
T: ComObjectInner,
|
||||
T::Outer: Any + 'static + IUnknownImpl<Impl = T>,
|
||||
{
|
||||
let object_ref = self.cast_object_ref::<T>()?;
|
||||
Ok(object_ref.to_object())
|
||||
}
|
||||
|
||||
/// Attempts to create a [`Weak`] reference to this object.
|
||||
fn downgrade(&self) -> Result<Weak<Self>> {
|
||||
self.cast::<imp::IWeakReferenceSource>()
|
||||
.and_then(|source| Weak::downgrade(&source))
|
||||
}
|
||||
|
||||
/// Call `QueryInterface` on this interface
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// `interface` must be a non-null, valid pointer for writing an interface pointer.
|
||||
#[inline(always)]
|
||||
unsafe fn query(&self, iid: *const GUID, interface: *mut *mut c_void) -> HRESULT {
|
||||
if Self::UNKNOWN {
|
||||
(self.assume_vtable::<IUnknown>().QueryInterface)(self.as_raw(), iid, interface)
|
||||
} else {
|
||||
panic!("Non-COM interfaces cannot be queried.")
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates an `InterfaceRef` for this reference. The `InterfaceRef` tracks lifetimes statically,
|
||||
/// and eliminates the need for dynamic reference count adjustments (AddRef/Release).
|
||||
fn to_ref(&self) -> InterfaceRef<'_, Self> {
|
||||
InterfaceRef::from_interface(self)
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn from_raw_borrowed<T: Interface>(raw: &*mut std::ffi::c_void) -> Option<&T> {
|
||||
pub unsafe fn from_raw_borrowed<T: Interface>(raw: &*mut c_void) -> Option<&T> {
|
||||
T::from_raw_borrowed(raw)
|
||||
}
|
||||
|
||||
/// This has the same memory representation as `IFoo`, but represents a borrowed interface pointer.
|
||||
///
|
||||
/// This type has no `Drop` impl; it does not AddRef/Release the given interface. However, because
|
||||
/// it has a lifetime parameter, it always represents a non-null pointer to an interface.
|
||||
#[repr(transparent)]
|
||||
pub struct InterfaceRef<'a, I>(NonNull<c_void>, PhantomData<&'a I>);
|
||||
|
||||
impl<'a, I> Copy for InterfaceRef<'a, I> {}
|
||||
|
||||
impl<'a, I> Clone for InterfaceRef<'a, I> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I: core::fmt::Debug + Interface> core::fmt::Debug for InterfaceRef<'a, I> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
<I as core::fmt::Debug>::fmt(&**self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I: Interface> InterfaceRef<'a, I> {
|
||||
/// Creates an `InterfaceRef` from a raw pointer. _This is extremely dangerous, since there
|
||||
/// is no lifetime tracking at all!_
|
||||
///
|
||||
/// # Safety
|
||||
/// The caller must guarantee that the `'a` lifetime parameter is bound by context to a correct
|
||||
/// lifetime.
|
||||
#[inline(always)]
|
||||
pub unsafe fn from_raw(ptr: NonNull<c_void>) -> Self {
|
||||
Self(ptr, PhantomData)
|
||||
}
|
||||
|
||||
/// Creates an `InterfaceRef` from an interface reference. This safely associates the lifetime
|
||||
/// of the interface reference with the `'a` parameter of `InterfaceRef`. This allows for
|
||||
/// lifetime checking _without_ calling AddRef/Release on the underlying lifetime, which can
|
||||
/// improve efficiency.
|
||||
#[inline(always)]
|
||||
pub fn from_interface(interface: &I) -> Self {
|
||||
unsafe {
|
||||
// SAFETY: new_unchecked() should be valid because Interface::as_raw should always
|
||||
// return a non-null pointer.
|
||||
Self(NonNull::new_unchecked(interface.as_raw()), PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls AddRef on the underlying COM interface and returns an "owned" (counted) reference.
|
||||
#[inline(always)]
|
||||
pub fn to_owned(self) -> I {
|
||||
(*self).clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'i: 'a, I: Interface> From<&'i I> for InterfaceRef<'a, I> {
|
||||
#[inline(always)]
|
||||
fn from(interface: &'a I) -> InterfaceRef<'a, I> {
|
||||
InterfaceRef::from_interface(interface)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, I: Interface> core::ops::Deref for InterfaceRef<'a, I> {
|
||||
type Target = I;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &I {
|
||||
unsafe { core::mem::transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
/// This IID identifies a special protocol, used by [`Interface::cast_to_any`]. This is _not_
|
||||
/// an ordinary COM interface; it uses special lifetime rules and a larger interface pointer.
|
||||
/// See the comments on [`Interface::cast_to_any`].
|
||||
#[doc(hidden)]
|
||||
pub const DYNAMIC_CAST_IID: GUID = GUID::from_u128(0xae49d5cb_143f_431c_874c_2729336e4eca);
|
||||
|
||||
49
third_party/rust/windows-core/src/lib.rs
vendored
49
third_party/rust/windows-core/src/lib.rs
vendored
@@ -4,56 +4,57 @@ Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs
|
||||
|
||||
#![doc(html_no_source)]
|
||||
#![allow(non_snake_case)]
|
||||
#![cfg_attr(windows_debugger_visualizer, debugger_visualizer(natvis_file = "../windows.natvis"))]
|
||||
#![cfg_attr(
|
||||
windows_debugger_visualizer,
|
||||
debugger_visualizer(natvis_file = "../.natvis")
|
||||
)]
|
||||
#![cfg_attr(all(not(feature = "std")), no_std)]
|
||||
|
||||
#[cfg(windows)]
|
||||
include!("windows.rs");
|
||||
|
||||
extern crate self as windows_core;
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use alloc::boxed::Box;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod imp;
|
||||
|
||||
mod agile_reference;
|
||||
mod array;
|
||||
mod as_impl;
|
||||
mod com_interface;
|
||||
mod error;
|
||||
mod event;
|
||||
mod com_object;
|
||||
mod guid;
|
||||
mod hresult;
|
||||
mod inspectable;
|
||||
mod interface;
|
||||
mod out_param;
|
||||
mod out_ref;
|
||||
mod param;
|
||||
mod param_value;
|
||||
mod r#ref;
|
||||
mod runtime_name;
|
||||
mod runtime_type;
|
||||
mod scoped_interface;
|
||||
mod strings;
|
||||
mod r#type;
|
||||
mod unknown;
|
||||
mod weak;
|
||||
|
||||
pub use agile_reference::*;
|
||||
pub use array::*;
|
||||
pub use as_impl::*;
|
||||
pub use com_interface::*;
|
||||
pub use error::*;
|
||||
pub use event::*;
|
||||
pub use com_object::*;
|
||||
pub use guid::*;
|
||||
pub use hresult::*;
|
||||
pub use inspectable::*;
|
||||
pub use interface::*;
|
||||
pub use out_param::*;
|
||||
pub use out_ref::*;
|
||||
pub use param::*;
|
||||
pub use param_value::*;
|
||||
pub use r#ref::*;
|
||||
pub use r#type::*;
|
||||
pub use runtime_name::*;
|
||||
pub use runtime_type::*;
|
||||
pub use scoped_interface::*;
|
||||
pub use strings::*;
|
||||
pub use unknown::*;
|
||||
pub use weak::*;
|
||||
|
||||
/// A specialized [`Result`] type that provides Windows error information.
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
|
||||
/// Attempts to load the factory object for the given WinRT class.
|
||||
/// This can be used to access COM interfaces implemented on a Windows Runtime class factory.
|
||||
pub fn factory<C: RuntimeName, I: ComInterface>() -> Result<I> {
|
||||
crate::imp::factory::<C, I>()
|
||||
}
|
||||
pub use windows_implement::implement;
|
||||
pub use windows_interface::interface;
|
||||
pub use windows_result::*;
|
||||
|
||||
57
third_party/rust/windows-core/src/out_param.rs
vendored
Normal file
57
third_party/rust/windows-core/src/out_param.rs
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
use super::*;
|
||||
use core::mem::{take, transmute_copy, zeroed};
|
||||
|
||||
/// Provides automatic parameter conversion in cases where the Windows API expects implicit conversion support.
|
||||
///
|
||||
/// This is a mutable version of [Param] meant to support out parameters.
|
||||
/// There is no need to implement this trait. Blanket implementations are provided for all applicable Windows types.
|
||||
pub trait OutParam<T: TypeKind, C = <T as TypeKind>::TypeKind>: Sized
|
||||
where
|
||||
T: Type<T>,
|
||||
{
|
||||
#[doc(hidden)]
|
||||
unsafe fn borrow_mut(&self) -> OutRef<'_, T>;
|
||||
}
|
||||
|
||||
impl<T> OutParam<T, CloneType> for &mut T
|
||||
where
|
||||
T: TypeKind<TypeKind = CloneType> + Clone + Default,
|
||||
{
|
||||
unsafe fn borrow_mut(&self) -> OutRef<'_, T> {
|
||||
let this: &mut T = transmute_copy(self);
|
||||
take(this);
|
||||
transmute_copy(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> OutParam<T, CopyType> for &mut T
|
||||
where
|
||||
T: TypeKind<TypeKind = CopyType> + Clone + Default,
|
||||
{
|
||||
unsafe fn borrow_mut(&self) -> OutRef<'_, T> {
|
||||
transmute_copy(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> OutParam<T, InterfaceType> for &mut Option<T>
|
||||
where
|
||||
T: TypeKind<TypeKind = InterfaceType> + Clone,
|
||||
{
|
||||
unsafe fn borrow_mut(&self) -> OutRef<'_, T> {
|
||||
let this: &mut Option<T> = transmute_copy(self);
|
||||
take(this);
|
||||
transmute_copy(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> OutParam<T> for Option<&mut T>
|
||||
where
|
||||
T: Type<T>,
|
||||
{
|
||||
unsafe fn borrow_mut(&self) -> OutRef<'_, T> {
|
||||
match self {
|
||||
Some(this) => transmute_copy(this),
|
||||
None => zeroed(),
|
||||
}
|
||||
}
|
||||
}
|
||||
25
third_party/rust/windows-core/src/out_ref.rs
vendored
Normal file
25
third_party/rust/windows-core/src/out_ref.rs
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
use super::*;
|
||||
|
||||
/// A borrowed type with the same memory layout as the type itself that can be used to construct ABI-compatible function signatures.
|
||||
///
|
||||
/// This is a mutable version of [Ref] meant to support out parameters.
|
||||
#[repr(transparent)]
|
||||
pub struct OutRef<'a, T: Type<T>>(*mut T::Abi, core::marker::PhantomData<&'a T>);
|
||||
|
||||
impl<'a, T: Type<T>> OutRef<'a, T> {
|
||||
/// Returns `true` if the argument is null.
|
||||
pub fn is_null(&self) -> bool {
|
||||
self.0.is_null()
|
||||
}
|
||||
|
||||
/// Overwrites a memory location with the given value without reading or dropping the old value.
|
||||
pub fn write(self, value: T::Default) -> Result<()> {
|
||||
if self.0.is_null() {
|
||||
Err(Error::from_hresult(imp::E_POINTER))
|
||||
} else {
|
||||
unsafe { *self.0 = core::mem::transmute_copy(&value) }
|
||||
core::mem::forget(value);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
146
third_party/rust/windows-core/src/param.rs
vendored
146
third_party/rust/windows-core/src/param.rs
vendored
@@ -1,133 +1,63 @@
|
||||
use super::*;
|
||||
use core::mem::transmute_copy;
|
||||
use core::mem::zeroed;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub enum Param<T: Type<T>> {
|
||||
Owned(T),
|
||||
Borrowed(T::Abi),
|
||||
/// Provides automatic parameter conversion in cases where the Windows API expects implicit conversion support.
|
||||
///
|
||||
/// There is no need to implement this trait. Blanket implementations are provided for all applicable Windows types.
|
||||
pub trait Param<T: TypeKind, C = <T as TypeKind>::TypeKind>: Sized
|
||||
where
|
||||
T: Type<T>,
|
||||
{
|
||||
#[doc(hidden)]
|
||||
unsafe fn param(self) -> ParamValue<T>;
|
||||
}
|
||||
|
||||
impl<T: Type<T>> Param<T> {
|
||||
pub fn abi(&self) -> T::Abi {
|
||||
unsafe {
|
||||
match self {
|
||||
Self::Owned(item) => std::mem::transmute_copy(item),
|
||||
Self::Borrowed(borrowed) => std::mem::transmute_copy(borrowed),
|
||||
}
|
||||
}
|
||||
impl<T> Param<T> for Option<&T>
|
||||
where
|
||||
T: Type<T>,
|
||||
{
|
||||
unsafe fn param(self) -> ParamValue<T> {
|
||||
ParamValue::Borrowed(match self {
|
||||
Some(item) => transmute_copy(item),
|
||||
None => zeroed(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait TryIntoParam<T: Type<T>> {
|
||||
fn try_into_param(self) -> Result<Param<T>>;
|
||||
}
|
||||
|
||||
impl<T> TryIntoParam<T> for Option<&T>
|
||||
impl<T, U> Param<T, InterfaceType> for &U
|
||||
where
|
||||
T: ComInterface,
|
||||
T: TypeKind<TypeKind = InterfaceType> + Clone,
|
||||
T: Interface,
|
||||
U: Interface,
|
||||
U: imp::CanInto<T>,
|
||||
{
|
||||
fn try_into_param(self) -> Result<Param<T>> {
|
||||
match self {
|
||||
Some(from) => Ok(Param::Borrowed(from.abi())),
|
||||
None => Ok(Param::Borrowed(unsafe { std::mem::zeroed() })),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> TryIntoParam<T> for &U
|
||||
where
|
||||
T: ComInterface,
|
||||
U: ComInterface,
|
||||
U: CanTryInto<T>,
|
||||
{
|
||||
fn try_into_param(self) -> Result<Param<T>> {
|
||||
if U::CAN_INTO {
|
||||
Ok(Param::Borrowed(self.abi()))
|
||||
unsafe fn param(self) -> ParamValue<T> {
|
||||
if U::QUERY {
|
||||
self.cast()
|
||||
.map_or(ParamValue::Borrowed(zeroed()), |ok| ParamValue::Owned(ok))
|
||||
} else {
|
||||
Ok(Param::Owned(self.cast()?))
|
||||
ParamValue::Borrowed(transmute_copy(self))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait CanTryInto<T>: ComInterface
|
||||
impl<T> Param<T, CloneType> for &T
|
||||
where
|
||||
T: ComInterface,
|
||||
T: TypeKind<TypeKind = CloneType> + Clone,
|
||||
{
|
||||
const CAN_INTO: bool = false;
|
||||
}
|
||||
|
||||
impl<T, U> CanTryInto<T> for U
|
||||
where
|
||||
T: ComInterface,
|
||||
U: ComInterface,
|
||||
U: CanInto<T>,
|
||||
{
|
||||
const CAN_INTO: bool = true;
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait CanInto<T>: Sized
|
||||
where
|
||||
T: Clone,
|
||||
{
|
||||
fn can_into(&self) -> &T {
|
||||
unsafe { std::mem::transmute(self) }
|
||||
}
|
||||
|
||||
fn can_clone_into(&self) -> T {
|
||||
self.can_into().clone()
|
||||
}
|
||||
}
|
||||
impl<T> CanInto<T> for T where T: Clone {}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait IntoParam<T: TypeKind, C = <T as TypeKind>::TypeKind>: Sized
|
||||
where
|
||||
T: Type<T>,
|
||||
{
|
||||
fn into_param(self) -> Param<T>;
|
||||
}
|
||||
|
||||
impl<T> IntoParam<T> for Option<&T>
|
||||
where
|
||||
T: Type<T>,
|
||||
{
|
||||
fn into_param(self) -> Param<T> {
|
||||
match self {
|
||||
Some(item) => Param::Borrowed(item.abi()),
|
||||
None => Param::Borrowed(unsafe { std::mem::zeroed() }),
|
||||
}
|
||||
unsafe fn param(self) -> ParamValue<T> {
|
||||
ParamValue::Borrowed(transmute_copy(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> IntoParam<T, ReferenceType> for &U
|
||||
where
|
||||
T: TypeKind<TypeKind = ReferenceType> + Clone,
|
||||
U: TypeKind<TypeKind = ReferenceType> + Clone,
|
||||
U: CanInto<T>,
|
||||
{
|
||||
fn into_param(self) -> Param<T> {
|
||||
Param::Borrowed(self.abi())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> IntoParam<T, ValueType> for &T
|
||||
where
|
||||
T: TypeKind<TypeKind = ValueType> + Clone,
|
||||
{
|
||||
fn into_param(self) -> Param<T> {
|
||||
Param::Borrowed(self.abi())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, U> IntoParam<T, CopyType> for U
|
||||
impl<T, U> Param<T, CopyType> for U
|
||||
where
|
||||
T: TypeKind<TypeKind = CopyType> + Clone,
|
||||
U: TypeKind<TypeKind = CopyType> + Clone,
|
||||
U: CanInto<T>,
|
||||
U: imp::CanInto<T>,
|
||||
{
|
||||
fn into_param(self) -> Param<T> {
|
||||
unsafe { Param::Owned(std::mem::transmute_copy(&self)) }
|
||||
unsafe fn param(self) -> ParamValue<T> {
|
||||
ParamValue::Owned(transmute_copy(&self))
|
||||
}
|
||||
}
|
||||
|
||||
24
third_party/rust/windows-core/src/param_value.rs
vendored
Normal file
24
third_party/rust/windows-core/src/param_value.rs
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
use super::*;
|
||||
use core::mem::transmute_copy;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub enum ParamValue<T: Type<T>> {
|
||||
Owned(T),
|
||||
Borrowed(T::Abi),
|
||||
}
|
||||
|
||||
impl<T: Type<T>> ParamValue<T> {
|
||||
// TODO: replace with `borrow` in windows-bindgen
|
||||
pub fn abi(&self) -> T::Abi {
|
||||
unsafe {
|
||||
match self {
|
||||
Self::Owned(item) => transmute_copy(item),
|
||||
Self::Borrowed(borrowed) => transmute_copy(borrowed),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn borrow(&self) -> Ref<'_, T> {
|
||||
unsafe { transmute_copy(&self.abi()) }
|
||||
}
|
||||
}
|
||||
26
third_party/rust/windows-core/src/ref.rs
vendored
Normal file
26
third_party/rust/windows-core/src/ref.rs
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
use super::*;
|
||||
use core::ffi::c_void;
|
||||
use core::marker::PhantomData;
|
||||
use core::mem::transmute;
|
||||
|
||||
/// A borrowed type with the same memory layout as the type itself that can be used to construct ABI-compatible function signatures.
|
||||
#[repr(transparent)]
|
||||
pub struct Ref<'a, T: Type<T>>(T::Abi, PhantomData<&'a T>);
|
||||
|
||||
impl<'a, T: Type<T, Default = Option<T>, Abi = *mut c_void>> Ref<'a, T> {
|
||||
/// Converts the argument to a [Result<&T>] reference.
|
||||
pub fn ok(&self) -> Result<&T> {
|
||||
if self.0.is_null() {
|
||||
Err(Error::from_hresult(imp::E_POINTER))
|
||||
} else {
|
||||
unsafe { Ok(transmute::<&*mut c_void, &T>(&self.0)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Type<T>> core::ops::Deref for Ref<'a, T> {
|
||||
type Target = T::Default;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { transmute(&self.0) }
|
||||
}
|
||||
}
|
||||
@@ -2,14 +2,14 @@ use super::*;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub trait RuntimeType: Type<Self> {
|
||||
const SIGNATURE: crate::imp::ConstBuffer;
|
||||
const SIGNATURE: imp::ConstBuffer;
|
||||
}
|
||||
|
||||
macro_rules! primitives {
|
||||
($(($t:ty, $s:literal)),+) => {
|
||||
$(
|
||||
impl RuntimeType for $t {
|
||||
const SIGNATURE: crate::imp::ConstBuffer = crate::imp::ConstBuffer::from_slice($s);
|
||||
const SIGNATURE: imp::ConstBuffer = imp::ConstBuffer::from_slice($s);
|
||||
}
|
||||
)*
|
||||
};
|
||||
|
||||
@@ -1,25 +1,30 @@
|
||||
use super::*;
|
||||
use core::ffi::c_void;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[repr(C)]
|
||||
pub struct ScopedHeap {
|
||||
pub vtable: *const std::ffi::c_void,
|
||||
pub this: *const std::ffi::c_void,
|
||||
pub vtable: *const c_void,
|
||||
pub this: *const c_void,
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct ScopedInterface<'a, T: Interface> {
|
||||
interface: T,
|
||||
lifetime: std::marker::PhantomData<&'a T>,
|
||||
lifetime: PhantomData<&'a T>,
|
||||
}
|
||||
|
||||
impl<'a, T: Interface> ScopedInterface<'a, T> {
|
||||
pub fn new(interface: T) -> Self {
|
||||
Self { interface, lifetime: std::marker::PhantomData }
|
||||
Self {
|
||||
interface,
|
||||
lifetime: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: Interface> std::ops::Deref for ScopedInterface<'a, T> {
|
||||
impl<'a, T: Interface> core::ops::Deref for ScopedInterface<'a, T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
@@ -30,7 +35,7 @@ impl<'a, T: Interface> std::ops::Deref for ScopedInterface<'a, T> {
|
||||
impl<'a, T: Interface> Drop for ScopedInterface<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let _ = std::boxed::Box::from_raw(self.interface.as_raw() as *const _ as *mut ScopedHeap);
|
||||
let _ = Box::from_raw(self.interface.as_raw() as *const _ as *mut ScopedHeap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
162
third_party/rust/windows-core/src/strings/bstr.rs
vendored
162
third_party/rust/windows-core/src/strings/bstr.rs
vendored
@@ -1,162 +0,0 @@
|
||||
use super::*;
|
||||
|
||||
/// A BSTR string ([BSTR](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/automat/string-manipulation-functions))
|
||||
/// is a length-prefixed wide string.
|
||||
#[repr(transparent)]
|
||||
pub struct BSTR(*const u16);
|
||||
|
||||
impl BSTR {
|
||||
/// Create an empty `BSTR`.
|
||||
///
|
||||
/// This function does not allocate memory.
|
||||
pub const fn new() -> Self {
|
||||
Self(std::ptr::null_mut())
|
||||
}
|
||||
|
||||
/// Returns `true` if the string is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Returns the length of the string.
|
||||
pub fn len(&self) -> usize {
|
||||
if self.0.is_null() {
|
||||
0
|
||||
} else {
|
||||
unsafe { crate::imp::SysStringLen(self.0) as usize }
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the string as 16-bit wide characters (wchars).
|
||||
pub fn as_wide(&self) -> &[u16] {
|
||||
if self.0.is_null() {
|
||||
return &[];
|
||||
}
|
||||
|
||||
unsafe { std::slice::from_raw_parts(self.0, self.len()) }
|
||||
}
|
||||
|
||||
/// Create a `BSTR` from a slice of 16 bit characters (wchars).
|
||||
pub fn from_wide(value: &[u16]) -> Result<Self> {
|
||||
if value.is_empty() {
|
||||
return Ok(Self::new());
|
||||
}
|
||||
|
||||
let result = unsafe { Self(crate::imp::SysAllocStringLen(value.as_ptr(), value.len().try_into()?)) };
|
||||
|
||||
if result.is_empty() {
|
||||
Err(crate::imp::E_OUTOFMEMORY.into())
|
||||
} else {
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn from_raw(raw: *const u16) -> Self {
|
||||
Self(raw)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
#[doc(hidden)]
|
||||
pub fn into_raw(self) -> *const u16 {
|
||||
unsafe { std::mem::transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::clone::Clone for BSTR {
|
||||
fn clone(&self) -> Self {
|
||||
Self::from_wide(self.as_wide()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&str> for BSTR {
|
||||
fn from(value: &str) -> Self {
|
||||
let value: std::vec::Vec<u16> = value.encode_utf16().collect();
|
||||
Self::from_wide(&value).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::string::String> for BSTR {
|
||||
fn from(value: std::string::String) -> Self {
|
||||
value.as_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&std::string::String> for BSTR {
|
||||
fn from(value: &std::string::String) -> Self {
|
||||
value.as_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::convert::TryFrom<&'a BSTR> for std::string::String {
|
||||
type Error = std::string::FromUtf16Error;
|
||||
|
||||
fn try_from(value: &BSTR) -> std::result::Result<Self, Self::Error> {
|
||||
std::string::String::from_utf16(value.as_wide())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<BSTR> for std::string::String {
|
||||
type Error = std::string::FromUtf16Error;
|
||||
|
||||
fn try_from(value: BSTR) -> std::result::Result<Self, Self::Error> {
|
||||
std::string::String::try_from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::default::Default for BSTR {
|
||||
fn default() -> Self {
|
||||
Self(std::ptr::null_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for BSTR {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::write!(f, "{}", crate::Decode(|| std::char::decode_utf16(self.as_wide().iter().cloned())))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for BSTR {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
std::write!(f, "{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::cmp::PartialEq for BSTR {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_wide() == other.as_wide()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::cmp::Eq for BSTR {}
|
||||
|
||||
impl std::cmp::PartialEq<BSTR> for &str {
|
||||
fn eq(&self, other: &BSTR) -> bool {
|
||||
other == self
|
||||
}
|
||||
}
|
||||
|
||||
impl std::cmp::PartialEq<BSTR> for String {
|
||||
fn eq(&self, other: &BSTR) -> bool {
|
||||
other == self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<str> + ?Sized> std::cmp::PartialEq<T> for BSTR {
|
||||
fn eq(&self, other: &T) -> bool {
|
||||
self.as_wide().iter().copied().eq(other.as_ref().encode_utf16())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Drop for BSTR {
|
||||
fn drop(&mut self) {
|
||||
if !self.0.is_null() {
|
||||
unsafe { crate::imp::SysFreeString(self.0) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeKind for BSTR {
|
||||
type TypeKind = ValueType;
|
||||
}
|
||||
458
third_party/rust/windows-core/src/strings/hstring.rs
vendored
458
third_party/rust/windows-core/src/strings/hstring.rs
vendored
@@ -1,458 +0,0 @@
|
||||
use super::*;
|
||||
|
||||
/// A WinRT string ([HSTRING](https://docs.microsoft.com/en-us/windows/win32/winrt/hstring))
|
||||
/// is reference-counted and immutable.
|
||||
#[repr(transparent)]
|
||||
pub struct HSTRING(Option<std::ptr::NonNull<Header>>);
|
||||
|
||||
impl HSTRING {
|
||||
/// Create an empty `HSTRING`.
|
||||
///
|
||||
/// This function does not allocate memory.
|
||||
pub const fn new() -> Self {
|
||||
Self(None)
|
||||
}
|
||||
|
||||
/// Returns `true` if the string is empty.
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
// An empty HSTRING is represented by a null pointer.
|
||||
self.0.is_none()
|
||||
}
|
||||
|
||||
/// Returns the length of the string.
|
||||
pub fn len(&self) -> usize {
|
||||
if let Some(header) = self.get_header() {
|
||||
header.len as usize
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the string as 16-bit wide characters (wchars).
|
||||
pub fn as_wide(&self) -> &[u16] {
|
||||
unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) }
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the `HSTRING` buffer.
|
||||
pub fn as_ptr(&self) -> *const u16 {
|
||||
if let Some(header) = self.get_header() {
|
||||
header.data
|
||||
} else {
|
||||
const EMPTY: [u16; 1] = [0];
|
||||
EMPTY.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a `HSTRING` from a slice of 16 bit characters (wchars).
|
||||
pub fn from_wide(value: &[u16]) -> Result<Self> {
|
||||
unsafe { Self::from_wide_iter(value.iter().copied(), value.len()) }
|
||||
}
|
||||
|
||||
/// Get the contents of this `HSTRING` as a String lossily.
|
||||
pub fn to_string_lossy(&self) -> std::string::String {
|
||||
std::string::String::from_utf16_lossy(self.as_wide())
|
||||
}
|
||||
|
||||
/// Get the contents of this `HSTRING` as a OsString.
|
||||
#[cfg(windows)]
|
||||
pub fn to_os_string(&self) -> std::ffi::OsString {
|
||||
std::os::windows::ffi::OsStringExt::from_wide(self.as_wide())
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// len must not be less than the number of items in the iterator.
|
||||
unsafe fn from_wide_iter<I: Iterator<Item = u16>>(iter: I, len: usize) -> Result<Self> {
|
||||
if len == 0 {
|
||||
return Ok(Self::new());
|
||||
}
|
||||
|
||||
let ptr = Header::alloc(len.try_into()?)?;
|
||||
|
||||
// Place each utf-16 character into the buffer and
|
||||
// increase len as we go along.
|
||||
for (index, wide) in iter.enumerate() {
|
||||
debug_assert!(index < len);
|
||||
|
||||
std::ptr::write((*ptr).data.add(index), wide);
|
||||
(*ptr).len = index as u32 + 1;
|
||||
}
|
||||
|
||||
// Write a 0 byte to the end of the buffer.
|
||||
std::ptr::write((*ptr).data.offset((*ptr).len as isize), 0);
|
||||
Ok(Self(std::ptr::NonNull::new(ptr)))
|
||||
}
|
||||
|
||||
fn get_header(&self) -> Option<&Header> {
|
||||
if let Some(header) = &self.0 {
|
||||
unsafe { Some(header.as_ref()) }
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl RuntimeType for HSTRING {
|
||||
const SIGNATURE: crate::imp::ConstBuffer = crate::imp::ConstBuffer::from_slice(b"string");
|
||||
}
|
||||
|
||||
impl TypeKind for HSTRING {
|
||||
type TypeKind = ValueType;
|
||||
}
|
||||
|
||||
impl Default for HSTRING {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for HSTRING {
|
||||
fn clone(&self) -> Self {
|
||||
if let Some(header) = self.get_header() {
|
||||
Self(std::ptr::NonNull::new(header.duplicate().unwrap()))
|
||||
} else {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for HSTRING {
|
||||
fn drop(&mut self) {
|
||||
if self.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(header) = self.0.take() {
|
||||
// REFERENCE_FLAG indicates a string backed by static or stack memory that is
|
||||
// thus not reference-counted and does not need to be freed.
|
||||
unsafe {
|
||||
let header = header.as_ref();
|
||||
if header.flags & REFERENCE_FLAG == 0 && header.count.release() == 0 {
|
||||
crate::imp::heap_free(header as *const _ as *mut _);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for HSTRING {}
|
||||
unsafe impl Sync for HSTRING {}
|
||||
|
||||
impl std::fmt::Display for HSTRING {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", Decode(|| std::char::decode_utf16(self.as_wide().iter().cloned())))
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for HSTRING {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "\"{}\"", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&str> for HSTRING {
|
||||
fn from(value: &str) -> Self {
|
||||
unsafe { Self::from_wide_iter(value.encode_utf16(), value.len()).unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::string::String> for HSTRING {
|
||||
fn from(value: std::string::String) -> Self {
|
||||
value.as_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&std::string::String> for HSTRING {
|
||||
fn from(value: &std::string::String) -> Self {
|
||||
value.as_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl std::convert::From<&std::path::Path> for HSTRING {
|
||||
fn from(value: &std::path::Path) -> Self {
|
||||
value.as_os_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl std::convert::From<&std::ffi::OsStr> for HSTRING {
|
||||
fn from(value: &std::ffi::OsStr) -> Self {
|
||||
unsafe { Self::from_wide_iter(std::os::windows::ffi::OsStrExt::encode_wide(value), value.len()).unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl std::convert::From<std::ffi::OsString> for HSTRING {
|
||||
fn from(value: std::ffi::OsString) -> Self {
|
||||
value.as_os_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl std::convert::From<&std::ffi::OsString> for HSTRING {
|
||||
fn from(value: &std::ffi::OsString) -> Self {
|
||||
value.as_os_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for HSTRING {}
|
||||
|
||||
impl Ord for HSTRING {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.as_wide().cmp(other.as_wide())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for HSTRING {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for HSTRING {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
*self.as_wide() == *other.as_wide()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::string::String> for HSTRING {
|
||||
fn eq(&self, other: &std::string::String) -> bool {
|
||||
*self == **other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<std::string::String> for &HSTRING {
|
||||
fn eq(&self, other: &std::string::String) -> bool {
|
||||
**self == **other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&std::string::String> for HSTRING {
|
||||
fn eq(&self, other: &&std::string::String) -> bool {
|
||||
*self == ***other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for HSTRING {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
self.as_wide().iter().copied().eq(other.encode_utf16())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for &HSTRING {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&str> for HSTRING {
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
*self == **other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<HSTRING> for str {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == *self
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<HSTRING> for &str {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == **self
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&HSTRING> for str {
|
||||
fn eq(&self, other: &&HSTRING) -> bool {
|
||||
**other == *self
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<HSTRING> for std::string::String {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == **self
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<HSTRING> for &std::string::String {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == ***self
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&HSTRING> for std::string::String {
|
||||
fn eq(&self, other: &&HSTRING) -> bool {
|
||||
**other == **self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl PartialEq<std::ffi::OsString> for HSTRING {
|
||||
fn eq(&self, other: &std::ffi::OsString) -> bool {
|
||||
*self == **other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl PartialEq<std::ffi::OsString> for &HSTRING {
|
||||
fn eq(&self, other: &std::ffi::OsString) -> bool {
|
||||
**self == **other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl PartialEq<&std::ffi::OsString> for HSTRING {
|
||||
fn eq(&self, other: &&std::ffi::OsString) -> bool {
|
||||
*self == ***other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl PartialEq<std::ffi::OsStr> for HSTRING {
|
||||
fn eq(&self, other: &std::ffi::OsStr) -> bool {
|
||||
self.as_wide().iter().copied().eq(std::os::windows::ffi::OsStrExt::encode_wide(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl PartialEq<std::ffi::OsStr> for &HSTRING {
|
||||
fn eq(&self, other: &std::ffi::OsStr) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl PartialEq<&std::ffi::OsStr> for HSTRING {
|
||||
fn eq(&self, other: &&std::ffi::OsStr) -> bool {
|
||||
*self == **other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl PartialEq<HSTRING> for std::ffi::OsStr {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == *self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl PartialEq<HSTRING> for &std::ffi::OsStr {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == **self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl PartialEq<&HSTRING> for std::ffi::OsStr {
|
||||
fn eq(&self, other: &&HSTRING) -> bool {
|
||||
**other == *self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl PartialEq<HSTRING> for std::ffi::OsString {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == **self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl PartialEq<HSTRING> for &std::ffi::OsString {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == ***self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl PartialEq<&HSTRING> for std::ffi::OsString {
|
||||
fn eq(&self, other: &&HSTRING) -> bool {
|
||||
**other == **self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> std::convert::TryFrom<&'a HSTRING> for std::string::String {
|
||||
type Error = std::string::FromUtf16Error;
|
||||
|
||||
fn try_from(hstring: &HSTRING) -> std::result::Result<Self, Self::Error> {
|
||||
std::string::String::from_utf16(hstring.as_wide())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<HSTRING> for std::string::String {
|
||||
type Error = std::string::FromUtf16Error;
|
||||
|
||||
fn try_from(hstring: HSTRING) -> std::result::Result<Self, Self::Error> {
|
||||
std::string::String::try_from(&hstring)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl<'a> std::convert::From<&'a HSTRING> for std::ffi::OsString {
|
||||
fn from(hstring: &HSTRING) -> Self {
|
||||
hstring.to_os_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
impl std::convert::From<HSTRING> for std::ffi::OsString {
|
||||
fn from(hstring: HSTRING) -> Self {
|
||||
Self::from(&hstring)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoParam<PCWSTR> for &HSTRING {
|
||||
fn into_param(self) -> Param<PCWSTR> {
|
||||
Param::Owned(PCWSTR(self.as_ptr()))
|
||||
}
|
||||
}
|
||||
|
||||
const REFERENCE_FLAG: u32 = 1;
|
||||
|
||||
#[repr(C)]
|
||||
struct Header {
|
||||
flags: u32,
|
||||
len: u32,
|
||||
_0: u32,
|
||||
_1: u32,
|
||||
data: *mut u16,
|
||||
count: crate::imp::RefCount,
|
||||
buffer_start: u16,
|
||||
}
|
||||
|
||||
impl Header {
|
||||
fn alloc(len: u32) -> Result<*mut Header> {
|
||||
debug_assert!(len != 0);
|
||||
// Allocate enough space for header and two bytes per character.
|
||||
// The space for the terminating null character is already accounted for inside of `Header`.
|
||||
let alloc_size = std::mem::size_of::<Header>() + 2 * len as usize;
|
||||
|
||||
let header = crate::imp::heap_alloc(alloc_size)? as *mut Header;
|
||||
|
||||
// SAFETY: uses `std::ptr::write` (since `header` is unintialized). `Header` is safe to be all zeros.
|
||||
unsafe {
|
||||
header.write(std::mem::MaybeUninit::<Header>::zeroed().assume_init());
|
||||
(*header).len = len;
|
||||
(*header).count = crate::imp::RefCount::new(1);
|
||||
(*header).data = &mut (*header).buffer_start;
|
||||
}
|
||||
Ok(header)
|
||||
}
|
||||
|
||||
fn duplicate(&self) -> Result<*mut Header> {
|
||||
if self.flags & REFERENCE_FLAG == 0 {
|
||||
// If this is not a "fast pass" string then simply increment the reference count.
|
||||
self.count.add_ref();
|
||||
Ok(self as *const Header as *mut Header)
|
||||
} else {
|
||||
// Otherwise, allocate a new string and copy the value into the new string.
|
||||
let copy = Header::alloc(self.len)?;
|
||||
// SAFETY: since we are duplicating the string it is safe to copy all data from self to the initialized `copy`.
|
||||
// We copy `len + 1` characters since `len` does not account for the terminating null character.
|
||||
unsafe {
|
||||
std::ptr::copy_nonoverlapping(self.data, (*copy).data, self.len as usize + 1);
|
||||
}
|
||||
Ok(copy)
|
||||
}
|
||||
}
|
||||
}
|
||||
38
third_party/rust/windows-core/src/type.rs
vendored
38
third_party/rust/windows-core/src/type.rs
vendored
@@ -6,10 +6,10 @@ pub trait TypeKind {
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct ReferenceType;
|
||||
pub struct InterfaceType;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct ValueType;
|
||||
pub struct CloneType;
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct CopyType;
|
||||
@@ -19,43 +19,39 @@ pub trait Type<T: TypeKind, C = <T as TypeKind>::TypeKind>: TypeKind + Sized + C
|
||||
type Abi;
|
||||
type Default;
|
||||
|
||||
fn abi(&self) -> Self::Abi {
|
||||
unsafe { std::mem::transmute_copy(self) }
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
unsafe fn from_abi(abi: Self::Abi) -> Result<Self>;
|
||||
fn from_default(default: &Self::Default) -> Result<Self>;
|
||||
}
|
||||
|
||||
impl<T> Type<T, ReferenceType> for T
|
||||
impl<T> Type<T, InterfaceType> for T
|
||||
where
|
||||
T: TypeKind<TypeKind = ReferenceType> + Clone,
|
||||
T: TypeKind<TypeKind = InterfaceType> + Clone,
|
||||
{
|
||||
type Abi = *mut std::ffi::c_void;
|
||||
type Abi = *mut core::ffi::c_void;
|
||||
type Default = Option<Self>;
|
||||
|
||||
unsafe fn from_abi(abi: Self::Abi) -> Result<Self> {
|
||||
if !abi.is_null() {
|
||||
Ok(std::mem::transmute_copy(&abi))
|
||||
Ok(core::mem::transmute_copy(&abi))
|
||||
} else {
|
||||
Err(Error::OK)
|
||||
Err(Error::empty())
|
||||
}
|
||||
}
|
||||
|
||||
fn from_default(default: &Self::Default) -> Result<Self> {
|
||||
default.as_ref().cloned().ok_or(Error::OK)
|
||||
default.as_ref().cloned().ok_or(Error::empty())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Type<T, ValueType> for T
|
||||
impl<T> Type<T, CloneType> for T
|
||||
where
|
||||
T: TypeKind<TypeKind = ValueType> + Clone,
|
||||
T: TypeKind<TypeKind = CloneType> + Clone,
|
||||
{
|
||||
type Abi = std::mem::MaybeUninit<Self>;
|
||||
type Abi = core::mem::MaybeUninit<Self>;
|
||||
type Default = Self;
|
||||
|
||||
unsafe fn from_abi(abi: std::mem::MaybeUninit<Self>) -> Result<Self> {
|
||||
unsafe fn from_abi(abi: Self::Abi) -> Result<Self> {
|
||||
Ok(abi.assume_init())
|
||||
}
|
||||
|
||||
@@ -71,7 +67,7 @@ where
|
||||
type Abi = Self;
|
||||
type Default = Self;
|
||||
|
||||
unsafe fn from_abi(abi: Self) -> Result<Self> {
|
||||
unsafe fn from_abi(abi: Self::Abi) -> Result<Self> {
|
||||
Ok(abi)
|
||||
}
|
||||
|
||||
@@ -81,7 +77,7 @@ where
|
||||
}
|
||||
|
||||
impl<T: Interface> TypeKind for T {
|
||||
type TypeKind = ReferenceType;
|
||||
type TypeKind = InterfaceType;
|
||||
}
|
||||
|
||||
impl<T> TypeKind for *mut T {
|
||||
@@ -102,9 +98,3 @@ primitives!(bool, i8, u8, i16, u16, i32, u32, i64, u64, f32, f64, usize, isize);
|
||||
|
||||
#[doc(hidden)]
|
||||
pub type AbiType<T> = <T as Type<T>>::Abi;
|
||||
|
||||
/// # Safety
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn from_abi<T: Type<T>>(abi: T::Abi) -> Result<T> {
|
||||
T::from_abi(abi)
|
||||
}
|
||||
|
||||
140
third_party/rust/windows-core/src/unknown.rs
vendored
140
third_party/rust/windows-core/src/unknown.rs
vendored
@@ -1,32 +1,36 @@
|
||||
use super::*;
|
||||
use core::ffi::c_void;
|
||||
use core::ptr::NonNull;
|
||||
|
||||
/// All COM interfaces (and thus WinRT classes and interfaces) implement
|
||||
/// [IUnknown](https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nn-unknwn-iunknown)
|
||||
/// under the hood to provide reference-counted lifetime management as well as the ability
|
||||
/// to query for additional interfaces that the object may implement.
|
||||
#[repr(transparent)]
|
||||
pub struct IUnknown(std::ptr::NonNull<std::ffi::c_void>);
|
||||
pub struct IUnknown(NonNull<c_void>);
|
||||
|
||||
#[doc(hidden)]
|
||||
#[repr(C)]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct IUnknown_Vtbl {
|
||||
pub QueryInterface: unsafe extern "system" fn(this: *mut std::ffi::c_void, iid: *const GUID, interface: *mut *mut std::ffi::c_void) -> HRESULT,
|
||||
pub AddRef: unsafe extern "system" fn(this: *mut std::ffi::c_void) -> u32,
|
||||
pub Release: unsafe extern "system" fn(this: *mut std::ffi::c_void) -> u32,
|
||||
pub QueryInterface: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
iid: *const GUID,
|
||||
interface: *mut *mut c_void,
|
||||
) -> HRESULT,
|
||||
pub AddRef: unsafe extern "system" fn(this: *mut c_void) -> u32,
|
||||
pub Release: unsafe extern "system" fn(this: *mut c_void) -> u32,
|
||||
}
|
||||
|
||||
unsafe impl Interface for IUnknown {
|
||||
type Vtable = IUnknown_Vtbl;
|
||||
}
|
||||
|
||||
unsafe impl ComInterface for IUnknown {
|
||||
const IID: GUID = GUID::from_u128(0x00000000_0000_0000_c000_000000000046);
|
||||
}
|
||||
|
||||
impl Clone for IUnknown {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe {
|
||||
(self.vtable().AddRef)(std::mem::transmute_copy(self));
|
||||
(self.vtable().AddRef)(core::mem::transmute_copy(self));
|
||||
}
|
||||
|
||||
Self(self.0)
|
||||
@@ -36,68 +40,154 @@ impl Clone for IUnknown {
|
||||
impl Drop for IUnknown {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
(self.vtable().Release)(std::mem::transmute_copy(self));
|
||||
(self.vtable().Release)(core::mem::transmute_copy(self));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for IUnknown {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
// First we test for ordinary pointer equality. If two COM interface pointers have the
|
||||
// same pointer value, then they are the same object. This can save us a lot of time,
|
||||
// since calling QueryInterface is much more expensive than a single pointer comparison.
|
||||
//
|
||||
// However, interface pointers may have different values and yet point to the same object.
|
||||
// Since COM objects may implement multiple interfaces, COM identity can only
|
||||
// be determined by querying for `IUnknown` explicitly and then comparing the
|
||||
// pointer values. This works since `QueryInterface` is required to return
|
||||
// the same pointer value for queries for `IUnknown`.
|
||||
self.cast::<IUnknown>().unwrap().0 == other.cast::<IUnknown>().unwrap().0
|
||||
self.as_raw() == other.as_raw()
|
||||
|| self.cast::<IUnknown>().unwrap().0 == other.cast::<IUnknown>().unwrap().0
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for IUnknown {}
|
||||
|
||||
impl std::fmt::Debug for IUnknown {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_tuple("IUnknown").field(&self.0).finish()
|
||||
impl core::fmt::Debug for IUnknown {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.debug_tuple("IUnknown").field(&self.as_raw()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// The `#[implement]` macro generates implementations of this trait for the types
|
||||
/// that it generates, e.g. `MyApp_Impl`,
|
||||
///
|
||||
/// `ComObject` uses this trait to interact with boxed COM objects.
|
||||
#[doc(hidden)]
|
||||
pub trait IUnknownImpl {
|
||||
/// The contained user type, e.g. `MyApp`. Also known as the "inner" type.
|
||||
type Impl;
|
||||
|
||||
/// Get a reference to the backing implementation.
|
||||
fn get_impl(&self) -> &Self::Impl;
|
||||
|
||||
/// Get a mutable reference to the contained (inner) object.
|
||||
fn get_impl_mut(&mut self) -> &mut Self::Impl;
|
||||
|
||||
/// Consumes the box and returns the contained (inner) object. This is the opposite of `new_box`.
|
||||
fn into_inner(self) -> Self::Impl;
|
||||
|
||||
/// The classic `QueryInterface` method from COM.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function is safe to call as long as the interface pointer is non-null and valid for writes
|
||||
/// of an interface pointer.
|
||||
unsafe fn QueryInterface(&self, iid: *const GUID, interface: *mut *mut std::ffi::c_void) -> HRESULT;
|
||||
unsafe fn QueryInterface(&self, iid: *const GUID, interface: *mut *mut c_void) -> HRESULT;
|
||||
|
||||
/// Increments the reference count of the interface
|
||||
fn AddRef(&self) -> u32;
|
||||
|
||||
/// Decrements the reference count causing the interface's memory to be freed when the count is 0
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function should only be called when the interfacer pointer is no longer used as calling `Release`
|
||||
/// This function should only be called when the interface pointer is no longer used as calling `Release`
|
||||
/// on a non-aliased interface pointer and then using that interface pointer may result in use after free.
|
||||
unsafe fn Release(&self) -> u32;
|
||||
///
|
||||
/// This function takes `*mut Self` because the object may be freed by the time this method returns.
|
||||
/// Taking `&self` would violate Rust's rules on reference lifetime.
|
||||
unsafe fn Release(self_: *mut Self) -> u32;
|
||||
|
||||
/// Returns `true` if the reference count of the box is equal to 1.
|
||||
fn is_reference_count_one(&self) -> bool;
|
||||
|
||||
/// Gets the trust level of the current object.
|
||||
unsafe fn GetTrustLevel(&self, value: *mut i32) -> HRESULT;
|
||||
|
||||
/// Given a reference to an inner type, returns a reference to the outer shared type.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function should only be called from methods that implement COM interfaces, i.e.
|
||||
/// implementations of methods on `IFoo_Impl` traits.
|
||||
// TODO: This can be made safe, if IFoo_Impl are moved to the Object_Impl types.
|
||||
// That requires some substantial redesign, though.
|
||||
unsafe fn from_inner_ref(inner: &Self::Impl) -> &Self;
|
||||
|
||||
/// Gets a borrowed reference to an interface that is implemented by this ComObject.
|
||||
///
|
||||
/// The returned reference does not have an additional reference count.
|
||||
/// You can AddRef it by calling to_owned().
|
||||
#[inline(always)]
|
||||
fn as_interface<I: Interface>(&self) -> InterfaceRef<'_, I>
|
||||
where
|
||||
Self: ComObjectInterface<I>,
|
||||
{
|
||||
<Self as ComObjectInterface<I>>::as_interface_ref(self)
|
||||
}
|
||||
|
||||
/// Gets an owned (counted) reference to an interface that is implemented by this ComObject.
|
||||
#[inline(always)]
|
||||
fn to_interface<I: Interface>(&self) -> I
|
||||
where
|
||||
Self: ComObjectInterface<I>,
|
||||
{
|
||||
<Self as ComObjectInterface<I>>::as_interface_ref(self).to_owned()
|
||||
}
|
||||
|
||||
/// Creates a new owned reference to this object.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function can only be safely called by `<Foo>_Impl` objects that are embedded in a
|
||||
/// `ComObject`. Since we only allow safe Rust code to access these objects using a `ComObject`
|
||||
/// or a `&<Foo>_Impl` that points within a `ComObject`, this is safe.
|
||||
fn to_object(&self) -> ComObject<Self::Impl>
|
||||
where
|
||||
Self::Impl: ComObjectInner<Outer = Self>;
|
||||
|
||||
/// The distance from the start of `<Foo>_Impl` to the `this` field within it, measured in
|
||||
/// pointer-sized elements. The `this` field contains the `MyApp` instance.
|
||||
const INNER_OFFSET_IN_POINTERS: usize;
|
||||
}
|
||||
|
||||
#[cfg(feature = "implement")]
|
||||
impl IUnknown_Vtbl {
|
||||
pub const fn new<T: IUnknownImpl, const OFFSET: isize>() -> Self {
|
||||
unsafe extern "system" fn QueryInterface<T: IUnknownImpl, const OFFSET: isize>(this: *mut std::ffi::c_void, iid: *const GUID, interface: *mut *mut std::ffi::c_void) -> HRESULT {
|
||||
let this = (this as *mut *mut std::ffi::c_void).offset(OFFSET) as *mut T;
|
||||
unsafe extern "system" fn QueryInterface<T: IUnknownImpl, const OFFSET: isize>(
|
||||
this: *mut c_void,
|
||||
iid: *const GUID,
|
||||
interface: *mut *mut c_void,
|
||||
) -> HRESULT {
|
||||
let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T;
|
||||
(*this).QueryInterface(iid, interface)
|
||||
}
|
||||
unsafe extern "system" fn AddRef<T: IUnknownImpl, const OFFSET: isize>(this: *mut std::ffi::c_void) -> u32 {
|
||||
let this = (this as *mut *mut std::ffi::c_void).offset(OFFSET) as *mut T;
|
||||
unsafe extern "system" fn AddRef<T: IUnknownImpl, const OFFSET: isize>(
|
||||
this: *mut c_void,
|
||||
) -> u32 {
|
||||
let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T;
|
||||
(*this).AddRef()
|
||||
}
|
||||
unsafe extern "system" fn Release<T: IUnknownImpl, const OFFSET: isize>(this: *mut std::ffi::c_void) -> u32 {
|
||||
let this = (this as *mut *mut std::ffi::c_void).offset(OFFSET) as *mut T;
|
||||
(*this).Release()
|
||||
unsafe extern "system" fn Release<T: IUnknownImpl, const OFFSET: isize>(
|
||||
this: *mut c_void,
|
||||
) -> u32 {
|
||||
let this = (this as *mut *mut c_void).offset(OFFSET) as *mut T;
|
||||
T::Release(this)
|
||||
}
|
||||
Self {
|
||||
QueryInterface: QueryInterface::<T, OFFSET>,
|
||||
AddRef: AddRef::<T, OFFSET>,
|
||||
Release: Release::<T, OFFSET>,
|
||||
}
|
||||
Self { QueryInterface: QueryInterface::<T, OFFSET>, AddRef: AddRef::<T, OFFSET>, Release: Release::<T, OFFSET> }
|
||||
}
|
||||
}
|
||||
|
||||
852
third_party/rust/windows-core/src/variant.rs
vendored
Normal file
852
third_party/rust/windows-core/src/variant.rs
vendored
Normal file
@@ -0,0 +1,852 @@
|
||||
use super::*;
|
||||
use core::mem::transmute;
|
||||
|
||||
/// A VARIANT ([VARIANT](https://learn.microsoft.com/en-us/windows/win32/api/oaidl/ns-oaidl-variant)) is a container that can store different types of values.
|
||||
#[repr(transparent)]
|
||||
pub struct VARIANT(imp::VARIANT);
|
||||
|
||||
/// A PROPVARIANT ([PROPVARIANT](https://learn.microsoft.com/en-us/windows/win32/api/propidlbase/ns-propidlbase-propvariant)) is a container that can store different types of values.
|
||||
#[repr(transparent)]
|
||||
pub struct PROPVARIANT(imp::PROPVARIANT);
|
||||
|
||||
impl Default for VARIANT {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for PROPVARIANT {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for VARIANT {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe {
|
||||
let mut value = Self::new();
|
||||
imp::VariantCopy(&mut value.0, &self.0);
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for PROPVARIANT {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe {
|
||||
let mut value = Self::new();
|
||||
imp::PropVariantCopy(&mut value.0, &self.0);
|
||||
value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for VARIANT {
|
||||
fn drop(&mut self) {
|
||||
unsafe { imp::VariantClear(&mut self.0) };
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PROPVARIANT {
|
||||
fn drop(&mut self) {
|
||||
unsafe { imp::PropVariantClear(&mut self.0) };
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeKind for VARIANT {
|
||||
type TypeKind = CloneType;
|
||||
}
|
||||
|
||||
impl TypeKind for PROPVARIANT {
|
||||
type TypeKind = CloneType;
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for VARIANT {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
let mut debug = f.debug_struct("VARIANT");
|
||||
debug.field("type", &unsafe { self.0.Anonymous.Anonymous.vt });
|
||||
|
||||
if let Ok(value) = BSTR::try_from(self) {
|
||||
debug.field("value", &value);
|
||||
}
|
||||
|
||||
debug.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for PROPVARIANT {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
let mut debug = f.debug_struct("PROPVARIANT");
|
||||
debug.field("type", &unsafe { self.0.Anonymous.Anonymous.vt });
|
||||
|
||||
if let Ok(value) = BSTR::try_from(self) {
|
||||
debug.field("value", &value);
|
||||
}
|
||||
|
||||
debug.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for VARIANT {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
core::write!(f, "{}", BSTR::try_from(self).unwrap_or_default())
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for PROPVARIANT {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
core::write!(f, "{}", BSTR::try_from(self).unwrap_or_default())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for VARIANT {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
unsafe {
|
||||
if self.0.Anonymous.Anonymous.vt != other.0.Anonymous.Anonymous.vt {
|
||||
return false;
|
||||
}
|
||||
let this = PROPVARIANT::try_from(self);
|
||||
let other = PROPVARIANT::try_from(other);
|
||||
|
||||
if let (Ok(this), Ok(other)) = (this, other) {
|
||||
this.eq(&other)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for PROPVARIANT {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
unsafe {
|
||||
if self.0.Anonymous.Anonymous.vt != other.0.Anonymous.Anonymous.vt {
|
||||
return false;
|
||||
}
|
||||
|
||||
imp::PropVariantCompareEx(&self.0, &other.0, 0, 0) == 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for VARIANT {}
|
||||
impl Eq for PROPVARIANT {}
|
||||
|
||||
impl VARIANT {
|
||||
/// Create an empty `VARIANT`.
|
||||
///
|
||||
/// This function does not allocate memory.
|
||||
pub fn new() -> Self {
|
||||
unsafe { core::mem::zeroed() }
|
||||
}
|
||||
|
||||
/// Returns true if the `VARIANT` is empty.
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
unsafe { self.0.Anonymous.Anonymous.vt == imp::VT_EMPTY }
|
||||
}
|
||||
|
||||
/// Creates a `VARIANT` by taking ownership of the raw data.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The raw data must be owned by the caller and represent a valid `VARIANT` data structure.
|
||||
pub unsafe fn from_raw(raw: imp::VARIANT) -> Self {
|
||||
Self(raw)
|
||||
}
|
||||
|
||||
/// Returns the underlying raw data for the `VARIANT`.
|
||||
pub fn as_raw(&self) -> &imp::VARIANT {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl PROPVARIANT {
|
||||
/// Create an empty `PROPVARIANT`.
|
||||
///
|
||||
/// This function does not allocate memory.
|
||||
pub fn new() -> Self {
|
||||
unsafe { core::mem::zeroed() }
|
||||
}
|
||||
|
||||
/// Returns true if the `PROPVARIANT` is empty.
|
||||
pub const fn is_empty(&self) -> bool {
|
||||
unsafe { self.0.Anonymous.Anonymous.vt == imp::VT_EMPTY }
|
||||
}
|
||||
|
||||
/// Creates a `PROPVARIANT` by taking ownership of the raw data.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The raw data must be owned by the caller and represent a valid `PROPVARIANT` data structure.
|
||||
pub unsafe fn from_raw(raw: imp::PROPVARIANT) -> Self {
|
||||
Self(raw)
|
||||
}
|
||||
|
||||
/// Returns the underlying raw data for the `PROPVARIANT`.
|
||||
pub fn as_raw(&self) -> &imp::PROPVARIANT {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&VARIANT> for PROPVARIANT {
|
||||
type Error = Error;
|
||||
fn try_from(from: &VARIANT) -> Result<Self> {
|
||||
unsafe {
|
||||
let mut value = Self::new();
|
||||
HRESULT(imp::VariantToPropVariant(&from.0, &mut value.0)).map(|| value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&PROPVARIANT> for VARIANT {
|
||||
type Error = Error;
|
||||
fn try_from(from: &PROPVARIANT) -> Result<Self> {
|
||||
unsafe {
|
||||
let mut value = Self::new();
|
||||
HRESULT(imp::PropVariantToVariant(&from.0, &mut value.0)).map(|| value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VT_UNKNOWN
|
||||
|
||||
impl From<IUnknown> for VARIANT {
|
||||
fn from(value: IUnknown) -> Self {
|
||||
Self(imp::VARIANT {
|
||||
Anonymous: imp::VARIANT_0 {
|
||||
Anonymous: imp::VARIANT_0_0 {
|
||||
vt: imp::VT_UNKNOWN,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::VARIANT_0_0_0 {
|
||||
punkVal: value.into_raw(),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IUnknown> for PROPVARIANT {
|
||||
fn from(value: IUnknown) -> Self {
|
||||
Self(imp::PROPVARIANT {
|
||||
Anonymous: imp::PROPVARIANT_0 {
|
||||
Anonymous: imp::PROPVARIANT_0_0 {
|
||||
vt: imp::VT_UNKNOWN,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::PROPVARIANT_0_0_0 {
|
||||
punkVal: value.into_raw(),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&VARIANT> for IUnknown {
|
||||
type Error = Error;
|
||||
fn try_from(from: &VARIANT) -> Result<Self> {
|
||||
unsafe {
|
||||
if from.0.Anonymous.Anonymous.vt == imp::VT_UNKNOWN
|
||||
&& !from.0.Anonymous.Anonymous.Anonymous.punkVal.is_null()
|
||||
{
|
||||
let unknown: &IUnknown = transmute(&from.0.Anonymous.Anonymous.Anonymous.punkVal);
|
||||
Ok(unknown.clone())
|
||||
} else {
|
||||
Err(Error::from_hresult(imp::TYPE_E_TYPEMISMATCH))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&PROPVARIANT> for IUnknown {
|
||||
type Error = Error;
|
||||
fn try_from(from: &PROPVARIANT) -> Result<Self> {
|
||||
unsafe {
|
||||
if from.0.Anonymous.Anonymous.vt == imp::VT_UNKNOWN
|
||||
&& !from.0.Anonymous.Anonymous.Anonymous.punkVal.is_null()
|
||||
{
|
||||
let unknown: &IUnknown = transmute(&from.0.Anonymous.Anonymous.Anonymous.punkVal);
|
||||
Ok(unknown.clone())
|
||||
} else {
|
||||
Err(Error::from_hresult(imp::TYPE_E_TYPEMISMATCH))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VT_BSTR
|
||||
|
||||
impl From<BSTR> for VARIANT {
|
||||
fn from(value: BSTR) -> Self {
|
||||
Self(imp::VARIANT {
|
||||
Anonymous: imp::VARIANT_0 {
|
||||
Anonymous: imp::VARIANT_0_0 {
|
||||
vt: imp::VT_BSTR,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::VARIANT_0_0_0 {
|
||||
bstrVal: value.into_raw(),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BSTR> for PROPVARIANT {
|
||||
fn from(value: BSTR) -> Self {
|
||||
Self(imp::PROPVARIANT {
|
||||
Anonymous: imp::PROPVARIANT_0 {
|
||||
Anonymous: imp::PROPVARIANT_0_0 {
|
||||
vt: imp::VT_BSTR,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::PROPVARIANT_0_0_0 {
|
||||
bstrVal: value.into_raw(),
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for VARIANT {
|
||||
fn from(value: &str) -> Self {
|
||||
BSTR::from(value).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for PROPVARIANT {
|
||||
fn from(value: &str) -> Self {
|
||||
BSTR::from(value).into()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&VARIANT> for BSTR {
|
||||
type Error = Error;
|
||||
fn try_from(from: &VARIANT) -> Result<Self> {
|
||||
let pv = PROPVARIANT::try_from(from)?;
|
||||
BSTR::try_from(&pv)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&PROPVARIANT> for BSTR {
|
||||
type Error = Error;
|
||||
fn try_from(from: &PROPVARIANT) -> Result<Self> {
|
||||
let mut value = Self::new();
|
||||
HRESULT(unsafe { imp::PropVariantToBSTR(&from.0, &mut value as *mut _ as *mut _) })
|
||||
.map(|| value)
|
||||
}
|
||||
}
|
||||
|
||||
// VT_BOOL
|
||||
|
||||
impl From<bool> for VARIANT {
|
||||
fn from(value: bool) -> Self {
|
||||
Self(imp::VARIANT {
|
||||
Anonymous: imp::VARIANT_0 {
|
||||
Anonymous: imp::VARIANT_0_0 {
|
||||
vt: imp::VT_BOOL,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::VARIANT_0_0_0 {
|
||||
boolVal: if value { -1 } else { 0 },
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for PROPVARIANT {
|
||||
fn from(value: bool) -> Self {
|
||||
Self(imp::PROPVARIANT {
|
||||
Anonymous: imp::PROPVARIANT_0 {
|
||||
Anonymous: imp::PROPVARIANT_0_0 {
|
||||
vt: imp::VT_BOOL,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::PROPVARIANT_0_0_0 {
|
||||
boolVal: if value { -1 } else { 0 },
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&VARIANT> for bool {
|
||||
type Error = Error;
|
||||
fn try_from(from: &VARIANT) -> Result<Self> {
|
||||
let mut value = 0;
|
||||
HRESULT(unsafe { imp::VariantToBoolean(&from.0, &mut value) }).map(|| value != 0)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&PROPVARIANT> for bool {
|
||||
type Error = Error;
|
||||
fn try_from(from: &PROPVARIANT) -> Result<Self> {
|
||||
let mut value = 0;
|
||||
HRESULT(unsafe { imp::PropVariantToBoolean(&from.0, &mut value) }).map(|| value != 0)
|
||||
}
|
||||
}
|
||||
|
||||
// VT_UI1
|
||||
|
||||
impl From<u8> for VARIANT {
|
||||
fn from(value: u8) -> Self {
|
||||
Self(imp::VARIANT {
|
||||
Anonymous: imp::VARIANT_0 {
|
||||
Anonymous: imp::VARIANT_0_0 {
|
||||
vt: imp::VT_UI1,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::VARIANT_0_0_0 { bVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for PROPVARIANT {
|
||||
fn from(value: u8) -> Self {
|
||||
Self(imp::PROPVARIANT {
|
||||
Anonymous: imp::PROPVARIANT_0 {
|
||||
Anonymous: imp::PROPVARIANT_0_0 {
|
||||
vt: imp::VT_UI1,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::PROPVARIANT_0_0_0 { bVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// VT_I1
|
||||
|
||||
impl From<i8> for VARIANT {
|
||||
fn from(value: i8) -> Self {
|
||||
Self(imp::VARIANT {
|
||||
Anonymous: imp::VARIANT_0 {
|
||||
Anonymous: imp::VARIANT_0_0 {
|
||||
vt: imp::VT_I1,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::VARIANT_0_0_0 { cVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i8> for PROPVARIANT {
|
||||
fn from(value: i8) -> Self {
|
||||
Self(imp::PROPVARIANT {
|
||||
Anonymous: imp::PROPVARIANT_0 {
|
||||
Anonymous: imp::PROPVARIANT_0_0 {
|
||||
vt: imp::VT_I1,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::PROPVARIANT_0_0_0 { cVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// VT_UI2
|
||||
|
||||
impl From<u16> for VARIANT {
|
||||
fn from(value: u16) -> Self {
|
||||
Self(imp::VARIANT {
|
||||
Anonymous: imp::VARIANT_0 {
|
||||
Anonymous: imp::VARIANT_0_0 {
|
||||
vt: imp::VT_UI2,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::VARIANT_0_0_0 { uiVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for PROPVARIANT {
|
||||
fn from(value: u16) -> Self {
|
||||
Self(imp::PROPVARIANT {
|
||||
Anonymous: imp::PROPVARIANT_0 {
|
||||
Anonymous: imp::PROPVARIANT_0_0 {
|
||||
vt: imp::VT_UI2,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::PROPVARIANT_0_0_0 { uiVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&VARIANT> for u16 {
|
||||
type Error = Error;
|
||||
fn try_from(from: &VARIANT) -> Result<Self> {
|
||||
let mut value = 0;
|
||||
HRESULT(unsafe { imp::VariantToUInt16(&from.0, &mut value) }).map(|| value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&PROPVARIANT> for u16 {
|
||||
type Error = Error;
|
||||
fn try_from(from: &PROPVARIANT) -> Result<Self> {
|
||||
let mut value = 0;
|
||||
HRESULT(unsafe { imp::PropVariantToUInt16(&from.0, &mut value) }).map(|| value)
|
||||
}
|
||||
}
|
||||
|
||||
// VT_I2
|
||||
|
||||
impl From<i16> for VARIANT {
|
||||
fn from(value: i16) -> Self {
|
||||
Self(imp::VARIANT {
|
||||
Anonymous: imp::VARIANT_0 {
|
||||
Anonymous: imp::VARIANT_0_0 {
|
||||
vt: imp::VT_I2,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::VARIANT_0_0_0 { iVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i16> for PROPVARIANT {
|
||||
fn from(value: i16) -> Self {
|
||||
Self(imp::PROPVARIANT {
|
||||
Anonymous: imp::PROPVARIANT_0 {
|
||||
Anonymous: imp::PROPVARIANT_0_0 {
|
||||
vt: imp::VT_I2,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::PROPVARIANT_0_0_0 { iVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&VARIANT> for i16 {
|
||||
type Error = Error;
|
||||
fn try_from(from: &VARIANT) -> Result<Self> {
|
||||
let mut value = 0;
|
||||
HRESULT(unsafe { imp::VariantToInt16(&from.0, &mut value) }).map(|| value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&PROPVARIANT> for i16 {
|
||||
type Error = Error;
|
||||
fn try_from(from: &PROPVARIANT) -> Result<Self> {
|
||||
let mut value = 0;
|
||||
HRESULT(unsafe { imp::PropVariantToInt16(&from.0, &mut value) }).map(|| value)
|
||||
}
|
||||
}
|
||||
|
||||
// VT_UI4
|
||||
|
||||
impl From<u32> for VARIANT {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(imp::VARIANT {
|
||||
Anonymous: imp::VARIANT_0 {
|
||||
Anonymous: imp::VARIANT_0_0 {
|
||||
vt: imp::VT_UI4,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::VARIANT_0_0_0 { ulVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for PROPVARIANT {
|
||||
fn from(value: u32) -> Self {
|
||||
Self(imp::PROPVARIANT {
|
||||
Anonymous: imp::PROPVARIANT_0 {
|
||||
Anonymous: imp::PROPVARIANT_0_0 {
|
||||
vt: imp::VT_UI4,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::PROPVARIANT_0_0_0 { ulVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&VARIANT> for u32 {
|
||||
type Error = Error;
|
||||
fn try_from(from: &VARIANT) -> Result<Self> {
|
||||
let mut value = 0;
|
||||
HRESULT(unsafe { imp::VariantToUInt32(&from.0, &mut value) }).map(|| value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&PROPVARIANT> for u32 {
|
||||
type Error = Error;
|
||||
fn try_from(from: &PROPVARIANT) -> Result<Self> {
|
||||
let mut value = 0;
|
||||
HRESULT(unsafe { imp::PropVariantToUInt32(&from.0, &mut value) }).map(|| value)
|
||||
}
|
||||
}
|
||||
|
||||
// VT_I4
|
||||
|
||||
impl From<i32> for VARIANT {
|
||||
fn from(value: i32) -> Self {
|
||||
Self(imp::VARIANT {
|
||||
Anonymous: imp::VARIANT_0 {
|
||||
Anonymous: imp::VARIANT_0_0 {
|
||||
vt: imp::VT_I4,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::VARIANT_0_0_0 { lVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for PROPVARIANT {
|
||||
fn from(value: i32) -> Self {
|
||||
Self(imp::PROPVARIANT {
|
||||
Anonymous: imp::PROPVARIANT_0 {
|
||||
Anonymous: imp::PROPVARIANT_0_0 {
|
||||
vt: imp::VT_I4,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::PROPVARIANT_0_0_0 { lVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&VARIANT> for i32 {
|
||||
type Error = Error;
|
||||
fn try_from(from: &VARIANT) -> Result<Self> {
|
||||
let mut value = 0;
|
||||
HRESULT(unsafe { imp::VariantToInt32(&from.0, &mut value) }).map(|| value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&PROPVARIANT> for i32 {
|
||||
type Error = Error;
|
||||
fn try_from(from: &PROPVARIANT) -> Result<Self> {
|
||||
let mut value = 0;
|
||||
HRESULT(unsafe { imp::PropVariantToInt32(&from.0, &mut value) }).map(|| value)
|
||||
}
|
||||
}
|
||||
|
||||
// VT_UI8
|
||||
|
||||
impl From<u64> for VARIANT {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(imp::VARIANT {
|
||||
Anonymous: imp::VARIANT_0 {
|
||||
Anonymous: imp::VARIANT_0_0 {
|
||||
vt: imp::VT_UI8,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::VARIANT_0_0_0 { ullVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for PROPVARIANT {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(imp::PROPVARIANT {
|
||||
Anonymous: imp::PROPVARIANT_0 {
|
||||
Anonymous: imp::PROPVARIANT_0_0 {
|
||||
vt: imp::VT_UI8,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::PROPVARIANT_0_0_0 { uhVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&VARIANT> for u64 {
|
||||
type Error = Error;
|
||||
fn try_from(from: &VARIANT) -> Result<Self> {
|
||||
let mut value = 0;
|
||||
HRESULT(unsafe { imp::VariantToUInt64(&from.0, &mut value) }).map(|| value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&PROPVARIANT> for u64 {
|
||||
type Error = Error;
|
||||
fn try_from(from: &PROPVARIANT) -> Result<Self> {
|
||||
let mut value = 0;
|
||||
HRESULT(unsafe { imp::PropVariantToUInt64(&from.0, &mut value) }).map(|| value)
|
||||
}
|
||||
}
|
||||
|
||||
// VT_I8
|
||||
|
||||
impl From<i64> for VARIANT {
|
||||
fn from(value: i64) -> Self {
|
||||
Self(imp::VARIANT {
|
||||
Anonymous: imp::VARIANT_0 {
|
||||
Anonymous: imp::VARIANT_0_0 {
|
||||
vt: imp::VT_I8,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::VARIANT_0_0_0 { llVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for PROPVARIANT {
|
||||
fn from(value: i64) -> Self {
|
||||
Self(imp::PROPVARIANT {
|
||||
Anonymous: imp::PROPVARIANT_0 {
|
||||
Anonymous: imp::PROPVARIANT_0_0 {
|
||||
vt: imp::VT_I8,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::PROPVARIANT_0_0_0 { hVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&VARIANT> for i64 {
|
||||
type Error = Error;
|
||||
fn try_from(from: &VARIANT) -> Result<Self> {
|
||||
let mut value = 0;
|
||||
HRESULT(unsafe { imp::VariantToInt64(&from.0, &mut value) }).map(|| value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&PROPVARIANT> for i64 {
|
||||
type Error = Error;
|
||||
fn try_from(from: &PROPVARIANT) -> Result<Self> {
|
||||
let mut value = 0;
|
||||
HRESULT(unsafe { imp::PropVariantToInt64(&from.0, &mut value) }).map(|| value)
|
||||
}
|
||||
}
|
||||
|
||||
// VT_R4
|
||||
|
||||
impl From<f32> for VARIANT {
|
||||
fn from(value: f32) -> Self {
|
||||
Self(imp::VARIANT {
|
||||
Anonymous: imp::VARIANT_0 {
|
||||
Anonymous: imp::VARIANT_0_0 {
|
||||
vt: imp::VT_R4,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::VARIANT_0_0_0 { fltVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for PROPVARIANT {
|
||||
fn from(value: f32) -> Self {
|
||||
Self(imp::PROPVARIANT {
|
||||
Anonymous: imp::PROPVARIANT_0 {
|
||||
Anonymous: imp::PROPVARIANT_0_0 {
|
||||
vt: imp::VT_R4,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::PROPVARIANT_0_0_0 { fltVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// VT_R8
|
||||
|
||||
impl From<f64> for VARIANT {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(imp::VARIANT {
|
||||
Anonymous: imp::VARIANT_0 {
|
||||
Anonymous: imp::VARIANT_0_0 {
|
||||
vt: imp::VT_R8,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::VARIANT_0_0_0 { dblVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for PROPVARIANT {
|
||||
fn from(value: f64) -> Self {
|
||||
Self(imp::PROPVARIANT {
|
||||
Anonymous: imp::PROPVARIANT_0 {
|
||||
Anonymous: imp::PROPVARIANT_0_0 {
|
||||
vt: imp::VT_R8,
|
||||
wReserved1: 0,
|
||||
wReserved2: 0,
|
||||
wReserved3: 0,
|
||||
Anonymous: imp::PROPVARIANT_0_0_0 { dblVal: value },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&VARIANT> for f64 {
|
||||
type Error = Error;
|
||||
fn try_from(from: &VARIANT) -> Result<Self> {
|
||||
let mut value = 0.0;
|
||||
HRESULT(unsafe { imp::VariantToDouble(&from.0, &mut value) }).map(|| value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&PROPVARIANT> for f64 {
|
||||
type Error = Error;
|
||||
fn try_from(from: &PROPVARIANT) -> Result<Self> {
|
||||
let mut value = 0.0;
|
||||
HRESULT(unsafe { imp::PropVariantToDouble(&from.0, &mut value) }).map(|| value)
|
||||
}
|
||||
}
|
||||
15
third_party/rust/windows-core/src/weak.rs
vendored
15
third_party/rust/windows-core/src/weak.rs
vendored
@@ -1,11 +1,11 @@
|
||||
use super::*;
|
||||
use std::marker::PhantomData;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
/// `Weak` holds a non-owning reference to an object.
|
||||
#[derive(Clone, PartialEq, Eq, Default)]
|
||||
pub struct Weak<I: ComInterface>(Option<crate::imp::IWeakReference>, PhantomData<I>);
|
||||
pub struct Weak<I: Interface>(Option<imp::IWeakReference>, PhantomData<I>);
|
||||
|
||||
impl<I: ComInterface> Weak<I> {
|
||||
impl<I: Interface> Weak<I> {
|
||||
/// Creates a new `Weak` object without any backing object.
|
||||
pub fn new() -> Self {
|
||||
Self(None, PhantomData)
|
||||
@@ -13,11 +13,16 @@ impl<I: ComInterface> Weak<I> {
|
||||
|
||||
/// Attempts to upgrade the weak reference to a strong reference.
|
||||
pub fn upgrade(&self) -> Option<I> {
|
||||
self.0.as_ref().and_then(|inner| unsafe { inner.Resolve().ok() })
|
||||
self.0
|
||||
.as_ref()
|
||||
.and_then(|inner| unsafe { inner.Resolve().ok() })
|
||||
}
|
||||
|
||||
pub(crate) fn downgrade(source: &crate::imp::IWeakReferenceSource) -> Result<Self> {
|
||||
pub(crate) fn downgrade(source: &imp::IWeakReferenceSource) -> Result<Self> {
|
||||
let reference = unsafe { source.GetWeakReference().ok() };
|
||||
Ok(Self(reference, PhantomData))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<I: Interface> Send for Weak<I> {}
|
||||
unsafe impl<I: Interface> Sync for Weak<I> {}
|
||||
|
||||
76
third_party/rust/windows-core/src/windows.rs
vendored
Normal file
76
third_party/rust/windows-core/src/windows.rs
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
mod agile_reference;
|
||||
pub use agile_reference::*;
|
||||
|
||||
mod array;
|
||||
pub use array::*;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod event;
|
||||
#[cfg(feature = "std")]
|
||||
pub use event::*;
|
||||
|
||||
mod handles;
|
||||
pub use handles::*;
|
||||
|
||||
mod variant;
|
||||
pub use variant::*;
|
||||
|
||||
pub use windows_strings::*;
|
||||
|
||||
/// Attempts to load the factory object for the given WinRT class.
|
||||
/// This can be used to access COM interfaces implemented on a Windows Runtime class factory.
|
||||
pub fn factory<C: RuntimeName, I: Interface>() -> Result<I> {
|
||||
imp::factory::<C, I>()
|
||||
}
|
||||
|
||||
impl Param<PCWSTR> for &BSTR {
|
||||
unsafe fn param(self) -> ParamValue<PCWSTR> {
|
||||
ParamValue::Owned(PCWSTR(self.as_ptr()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Param<PCWSTR> for &HSTRING {
|
||||
unsafe fn param(self) -> ParamValue<PCWSTR> {
|
||||
ParamValue::Owned(PCWSTR(self.as_ptr()))
|
||||
}
|
||||
}
|
||||
|
||||
impl Param<PCWSTR> for PWSTR {
|
||||
unsafe fn param(self) -> ParamValue<PCWSTR> {
|
||||
ParamValue::Owned(PCWSTR(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl Param<PCSTR> for PSTR {
|
||||
unsafe fn param(self) -> ParamValue<PCSTR> {
|
||||
ParamValue::Owned(PCSTR(self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl RuntimeType for HSTRING {
|
||||
const SIGNATURE: imp::ConstBuffer = imp::ConstBuffer::from_slice(b"string");
|
||||
}
|
||||
|
||||
impl TypeKind for PWSTR {
|
||||
type TypeKind = CopyType;
|
||||
}
|
||||
|
||||
impl TypeKind for PSTR {
|
||||
type TypeKind = CopyType;
|
||||
}
|
||||
|
||||
impl TypeKind for PCWSTR {
|
||||
type TypeKind = CopyType;
|
||||
}
|
||||
|
||||
impl TypeKind for PCSTR {
|
||||
type TypeKind = CopyType;
|
||||
}
|
||||
|
||||
impl TypeKind for HSTRING {
|
||||
type TypeKind = CloneType;
|
||||
}
|
||||
|
||||
impl TypeKind for BSTR {
|
||||
type TypeKind = CloneType;
|
||||
}
|
||||
84
third_party/rust/windows-core/windows.natvis
vendored
84
third_party/rust/windows-core/windows.natvis
vendored
@@ -1,84 +0,0 @@
|
||||
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
|
||||
<Type Name="windows_core::array::Array<*>">
|
||||
<DisplayString>{{ len={len} }}</DisplayString>
|
||||
|
||||
<Expand>
|
||||
<Item Name="[len]">len</Item>
|
||||
<ArrayItems>
|
||||
<Size>len</Size>
|
||||
<ValuePointer>data</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="windows_core::error::Error">
|
||||
<Expand>
|
||||
<ExpandedItem>code</ExpandedItem>
|
||||
<Item Name="[info]">info</Item>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="windows_core::hresult::HRESULT">
|
||||
<DisplayString>{(HRESULT)__0}</DisplayString>
|
||||
</Type>
|
||||
|
||||
<Type Name="windows_core::imp::ref_count::RefCount">
|
||||
<DisplayString>{__0}</DisplayString>
|
||||
</Type>
|
||||
|
||||
<Type Name="windows_core::strings::hstring::HSTRING">
|
||||
<Intrinsic Name="header" Expression="*((windows_core::strings::hstring::Header**)this)" ReturnType="windows_core::strings::hstring::Header *" />
|
||||
<Intrinsic Name="is_empty" Expression="header() == nullptr" />
|
||||
<DisplayString Condition="is_empty()">""</DisplayString>
|
||||
<DisplayString>{((char16_t*)header()->data),[header()->len]su}</DisplayString>
|
||||
|
||||
<Expand>
|
||||
<Item Name="[len]">is_empty() ? (unsigned int)0 : header()->len</Item>
|
||||
<Item Name="[ref_count]" Condition="!is_empty()">header()->count</Item>
|
||||
<Item Name="[flags]" Condition="!is_empty()">header()->flags</Item>
|
||||
<Synthetic Name="[chars]" Condition="!is_empty()">
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
<Size>header()->len</Size>
|
||||
<ValuePointer>(char16_t*)header()->data</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="windows_core::strings::pstr::PSTR">
|
||||
<AlternativeType Name="windows_core::strings::pcstr::PCSTR" />
|
||||
<Intrinsic Name="len" Expression="strlen(((char*)__0))" />
|
||||
<DisplayString>{(char*)__0,[len()]s8}</DisplayString>
|
||||
<Expand>
|
||||
<Item Name="[len]">len()</Item>
|
||||
<Synthetic Name="[chars]">
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
<Size>len()</Size>
|
||||
<ValuePointer>(char*)__0</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
|
||||
<Type Name="windows_core::strings::pwstr::PWSTR">
|
||||
<AlternativeType Name="windows_core::strings::pcwstr::PCWSTR" />
|
||||
<Intrinsic Name="len" Expression="wcslen(((WCHAR*)__0))" />
|
||||
<DisplayString>{(char16_t*)__0,[len()]su}</DisplayString>
|
||||
|
||||
<Expand>
|
||||
<Item Name="[len]">len()</Item>
|
||||
<Synthetic Name="[chars]">
|
||||
<Expand>
|
||||
<ArrayItems>
|
||||
<Size>len()</Size>
|
||||
<ValuePointer>(char16_t*)__0</ValuePointer>
|
||||
</ArrayItems>
|
||||
</Expand>
|
||||
</Synthetic>
|
||||
</Expand>
|
||||
</Type>
|
||||
</AutoVisualizer>
|
||||
1
third_party/rust/windows-implement/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/windows-implement/.cargo-checksum.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"files":{"Cargo.toml":"e2760c01e9e1b707bbe2ba1af6ddbc7555e3f6111eb4981fed6a1077afce1695","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","src/lib.rs":"d372c5fa2db9fe014e71ba3cd2c81a1b566571fbca2d6a6330f4e0d224bfa880"},"package":"2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"}
|
||||
64
third_party/rust/windows-implement/Cargo.toml
vendored
Normal file
64
third_party/rust/windows-implement/Cargo.toml
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.70"
|
||||
name = "windows-implement"
|
||||
version = "0.58.0"
|
||||
authors = ["Microsoft"]
|
||||
build = false
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "The implement macro for the windows crate"
|
||||
readme = false
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/microsoft/windows-rs"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "x86_64-pc-windows-msvc"
|
||||
targets = []
|
||||
|
||||
[lib]
|
||||
name = "windows_implement"
|
||||
path = "src/lib.rs"
|
||||
proc-macro = true
|
||||
|
||||
[dependencies.proc-macro2]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.quote]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.syn]
|
||||
version = "2.0"
|
||||
features = [
|
||||
"parsing",
|
||||
"proc-macro",
|
||||
"printing",
|
||||
"full",
|
||||
"derive",
|
||||
]
|
||||
default-features = false
|
||||
|
||||
[lints.rust]
|
||||
missing_docs = "warn"
|
||||
|
||||
[lints.rust.rust_2018_idioms]
|
||||
level = "warn"
|
||||
priority = -1
|
||||
|
||||
[lints.rust.unexpected_cfgs]
|
||||
level = "warn"
|
||||
priority = 0
|
||||
check-cfg = ["cfg(windows_raw_dylib, windows_debugger_visualizer, windows_slim_errors)"]
|
||||
201
third_party/rust/windows-implement/license-apache-2.0
vendored
Normal file
201
third_party/rust/windows-implement/license-apache-2.0
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
21
third_party/rust/windows-implement/license-mit
vendored
Normal file
21
third_party/rust/windows-implement/license-mit
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
588
third_party/rust/windows-implement/src/lib.rs
vendored
Normal file
588
third_party/rust/windows-implement/src/lib.rs
vendored
Normal file
@@ -0,0 +1,588 @@
|
||||
/*!
|
||||
Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs>
|
||||
*/
|
||||
|
||||
use quote::{quote, ToTokens};
|
||||
|
||||
/// Implements one or more COM interfaces.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// Here is a [more complete tutorial](https://kennykerr.ca/rust-getting-started/how-to-implement-com-interface.html).
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// #[interface("094d70d6-5202-44b8-abb8-43860da5aca2")]
|
||||
/// unsafe trait IValue: IUnknown {
|
||||
/// fn GetValue(&self, value: *mut i32) -> HRESULT;
|
||||
/// }
|
||||
///
|
||||
/// #[implement(IValue)]
|
||||
/// struct Value(i32);
|
||||
///
|
||||
/// impl IValue_Impl for Value {
|
||||
/// unsafe fn GetValue(&self, value: *mut i32) -> HRESULT {
|
||||
/// *value = self.0;
|
||||
/// HRESULT(0)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let rust_instance = Value(123);
|
||||
/// let com_object: IValue = rust_instance.into();
|
||||
/// // You can now call interface methods on com_object.
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn implement(
|
||||
attributes: proc_macro::TokenStream,
|
||||
original_type: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
let attributes = syn::parse_macro_input!(attributes as ImplementAttributes);
|
||||
let interfaces_len = proc_macro2::Literal::usize_unsuffixed(attributes.implement.len());
|
||||
|
||||
let identity_type = if let Some(first) = attributes.implement.first() {
|
||||
first.to_ident()
|
||||
} else {
|
||||
quote! { ::windows_core::IInspectable }
|
||||
};
|
||||
|
||||
let original_type2 = original_type.clone();
|
||||
let original_type2 = syn::parse_macro_input!(original_type2 as syn::ItemStruct);
|
||||
let vis = &original_type2.vis;
|
||||
let original_ident = &original_type2.ident;
|
||||
let mut constraints = quote! {};
|
||||
|
||||
if let Some(where_clause) = &original_type2.generics.where_clause {
|
||||
where_clause.predicates.to_tokens(&mut constraints);
|
||||
}
|
||||
|
||||
let generics = if original_type2.generics.lt_token.is_some() {
|
||||
let mut params = quote! {};
|
||||
original_type2.generics.params.to_tokens(&mut params);
|
||||
quote! { <#params> }
|
||||
} else {
|
||||
quote! { <> }
|
||||
};
|
||||
|
||||
let impl_ident = quote::format_ident!("{}_Impl", original_ident);
|
||||
let vtbl_idents = attributes
|
||||
.implement
|
||||
.iter()
|
||||
.map(|implement| implement.to_vtbl_ident());
|
||||
let vtbl_idents2 = vtbl_idents.clone();
|
||||
|
||||
let vtable_news = attributes
|
||||
.implement
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(enumerate, implement)| {
|
||||
let vtbl_ident = implement.to_vtbl_ident();
|
||||
let offset = proc_macro2::Literal::isize_unsuffixed(-1 - enumerate as isize);
|
||||
quote! { #vtbl_ident::new::<Self, #offset>() }
|
||||
});
|
||||
|
||||
let offset = attributes
|
||||
.implement
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(offset, _)| proc_macro2::Literal::usize_unsuffixed(offset));
|
||||
|
||||
let queries = attributes
|
||||
.implement
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(count, implement)| {
|
||||
let vtbl_ident = implement.to_vtbl_ident();
|
||||
let offset = proc_macro2::Literal::usize_unsuffixed(count);
|
||||
quote! {
|
||||
else if #vtbl_ident::matches(iid) {
|
||||
&self.vtables.#offset as *const _ as *mut _
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Dynamic casting requires that the object not contain non-static lifetimes.
|
||||
let enable_dyn_casting = original_type2.generics.lifetimes().count() == 0;
|
||||
let dynamic_cast_query = if enable_dyn_casting {
|
||||
quote! {
|
||||
else if *iid == ::windows_core::DYNAMIC_CAST_IID {
|
||||
// DYNAMIC_CAST_IID is special. We _do not_ increase the reference count for this pseudo-interface.
|
||||
// Also, instead of returning an interface pointer, we simply write the `&dyn Any` directly to the
|
||||
// 'interface' pointer. Since the size of `&dyn Any` is 2 pointers, not one, the caller must be
|
||||
// prepared for this. This is not a normal QueryInterface call.
|
||||
//
|
||||
// See the `Interface::cast_to_any` method, which is the only caller that should use DYNAMIC_CAST_ID.
|
||||
(interface as *mut *const dyn core::any::Any).write(self as &dyn ::core::any::Any as *const dyn ::core::any::Any);
|
||||
return ::windows_core::HRESULT(0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote!()
|
||||
};
|
||||
|
||||
// The distance from the beginning of the generated type to the 'this' field, in units of pointers (not bytes).
|
||||
let offset_of_this_in_pointers = 1 + attributes.implement.len();
|
||||
let offset_of_this_in_pointers_token =
|
||||
proc_macro2::Literal::usize_unsuffixed(offset_of_this_in_pointers);
|
||||
|
||||
let trust_level = proc_macro2::Literal::usize_unsuffixed(attributes.trust_level);
|
||||
|
||||
let conversions = attributes.implement.iter().enumerate().map(|(enumerate, implement)| {
|
||||
let interface_ident = implement.to_ident();
|
||||
let offset = proc_macro2::Literal::usize_unsuffixed(enumerate);
|
||||
quote! {
|
||||
impl #generics ::core::convert::From<#original_ident::#generics> for #interface_ident where #constraints {
|
||||
#[inline(always)]
|
||||
fn from(this: #original_ident::#generics) -> Self {
|
||||
let com_object = ::windows_core::ComObject::new(this);
|
||||
com_object.into_interface()
|
||||
}
|
||||
}
|
||||
|
||||
impl #generics ::windows_core::ComObjectInterface<#interface_ident> for #impl_ident::#generics where #constraints {
|
||||
#[inline(always)]
|
||||
fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, #interface_ident> {
|
||||
unsafe {
|
||||
let interface_ptr = &self.vtables.#offset;
|
||||
::core::mem::transmute(interface_ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl #generics ::windows_core::AsImpl<#original_ident::#generics> for #interface_ident where #constraints {
|
||||
// SAFETY: the offset is guranteed to be in bounds, and the implementation struct
|
||||
// is guaranteed to live at least as long as `self`.
|
||||
#[inline(always)]
|
||||
unsafe fn as_impl_ptr(&self) -> ::core::ptr::NonNull<#original_ident::#generics> {
|
||||
let this = ::windows_core::Interface::as_raw(self);
|
||||
// Subtract away the vtable offset plus 1, for the `identity` field, to get
|
||||
// to the impl struct which contains that original implementation type.
|
||||
let this = (this as *mut *mut ::core::ffi::c_void).sub(1 + #offset) as *mut #impl_ident::#generics;
|
||||
::core::ptr::NonNull::new_unchecked(::core::ptr::addr_of!((*this).this) as *const #original_ident::#generics as *mut #original_ident::#generics)
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let tokens = quote! {
|
||||
#[repr(C)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#vis struct #impl_ident #generics where #constraints {
|
||||
identity: &'static ::windows_core::IInspectable_Vtbl,
|
||||
vtables: (#(&'static #vtbl_idents,)*),
|
||||
this: #original_ident::#generics,
|
||||
count: ::windows_core::imp::WeakRefCount,
|
||||
}
|
||||
|
||||
impl #generics #impl_ident::#generics where #constraints {
|
||||
const VTABLES: (#(#vtbl_idents2,)*) = (#(#vtable_news,)*);
|
||||
const IDENTITY: ::windows_core::IInspectable_Vtbl = ::windows_core::IInspectable_Vtbl::new::<Self, #identity_type, 0>();
|
||||
}
|
||||
|
||||
impl #generics ::windows_core::ComObjectInner for #original_ident::#generics where #constraints {
|
||||
type Outer = #impl_ident::#generics;
|
||||
|
||||
// IMPORTANT! This function handles assembling the "boxed" type of a COM object.
|
||||
// It immediately moves the box into a heap allocation (box) and returns only a ComObject
|
||||
// reference that points to it. We intentionally _do not_ expose any owned instances of
|
||||
// Foo_Impl to safe Rust code, because doing so would allow unsound behavior in safe Rust
|
||||
// code, due to the adjustments of the reference count that Foo_Impl permits.
|
||||
//
|
||||
// This is why this function returns ComObject<Self> instead of returning #impl_ident.
|
||||
|
||||
fn into_object(self) -> ::windows_core::ComObject<Self> {
|
||||
let boxed = ::windows_core::imp::Box::new(#impl_ident::#generics {
|
||||
identity: &#impl_ident::#generics::IDENTITY,
|
||||
vtables: (#(&#impl_ident::#generics::VTABLES.#offset,)*),
|
||||
this: self,
|
||||
count: ::windows_core::imp::WeakRefCount::new(),
|
||||
});
|
||||
unsafe {
|
||||
let ptr = ::windows_core::imp::Box::into_raw(boxed);
|
||||
::windows_core::ComObject::from_raw(
|
||||
::core::ptr::NonNull::new_unchecked(ptr)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl #generics ::windows_core::IUnknownImpl for #impl_ident::#generics where #constraints {
|
||||
type Impl = #original_ident::#generics;
|
||||
|
||||
#[inline(always)]
|
||||
fn get_impl(&self) -> &Self::Impl {
|
||||
&self.this
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn get_impl_mut(&mut self) -> &mut Self::Impl {
|
||||
&mut self.this
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn is_reference_count_one(&self) -> bool {
|
||||
self.count.is_one()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn into_inner(self) -> Self::Impl {
|
||||
self.this
|
||||
}
|
||||
|
||||
unsafe fn QueryInterface(&self, iid: *const ::windows_core::GUID, interface: *mut *mut ::core::ffi::c_void) -> ::windows_core::HRESULT {
|
||||
if iid.is_null() || interface.is_null() {
|
||||
return ::windows_core::imp::E_POINTER;
|
||||
}
|
||||
|
||||
let iid = &*iid;
|
||||
|
||||
let interface_ptr: *mut ::core::ffi::c_void = if iid == &<::windows_core::IUnknown as ::windows_core::Interface>::IID
|
||||
|| iid == &<::windows_core::IInspectable as ::windows_core::Interface>::IID
|
||||
|| iid == &<::windows_core::imp::IAgileObject as ::windows_core::Interface>::IID {
|
||||
&self.identity as *const _ as *mut _
|
||||
}
|
||||
#(#queries)*
|
||||
#dynamic_cast_query
|
||||
else {
|
||||
::core::ptr::null_mut()
|
||||
};
|
||||
|
||||
if !interface_ptr.is_null() {
|
||||
*interface = interface_ptr;
|
||||
self.count.add_ref();
|
||||
return ::windows_core::HRESULT(0);
|
||||
}
|
||||
|
||||
let interface_ptr = self.count.query(iid, &self.identity as *const _ as *mut _);
|
||||
*interface = interface_ptr;
|
||||
|
||||
if interface_ptr.is_null() {
|
||||
::windows_core::imp::E_NOINTERFACE
|
||||
} else {
|
||||
::windows_core::HRESULT(0)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn AddRef(&self) -> u32 {
|
||||
self.count.add_ref()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn Release(self_: *mut Self) -> u32 {
|
||||
let remaining = (*self_).count.release();
|
||||
if remaining == 0 {
|
||||
_ = ::windows_core::imp::Box::from_raw(self_);
|
||||
}
|
||||
remaining
|
||||
}
|
||||
|
||||
unsafe fn GetTrustLevel(&self, value: *mut i32) -> ::windows_core::HRESULT {
|
||||
if value.is_null() {
|
||||
return ::windows_core::imp::E_POINTER;
|
||||
}
|
||||
*value = #trust_level;
|
||||
::windows_core::HRESULT(0)
|
||||
}
|
||||
|
||||
unsafe fn from_inner_ref(inner: &Self::Impl) -> &Self {
|
||||
&*((inner as *const Self::Impl as *const *const ::core::ffi::c_void)
|
||||
.sub(#offset_of_this_in_pointers_token) as *const Self)
|
||||
}
|
||||
|
||||
fn to_object(&self) -> ::windows_core::ComObject<Self::Impl> {
|
||||
self.count.add_ref();
|
||||
unsafe {
|
||||
::windows_core::ComObject::from_raw(
|
||||
::core::ptr::NonNull::new_unchecked(self as *const Self as *mut Self)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const INNER_OFFSET_IN_POINTERS: usize = #offset_of_this_in_pointers_token;
|
||||
}
|
||||
|
||||
impl #generics #original_ident::#generics where #constraints {
|
||||
/// Try casting as the provided interface
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// This function can only be safely called if `self` has been heap allocated and pinned using
|
||||
/// the mechanisms provided by `implement` macro.
|
||||
#[inline(always)]
|
||||
unsafe fn cast<I: ::windows_core::Interface>(&self) -> ::windows_core::Result<I> {
|
||||
let boxed = (self as *const _ as *const *mut ::core::ffi::c_void).sub(1 + #interfaces_len) as *mut #impl_ident::#generics;
|
||||
let mut result = ::core::ptr::null_mut();
|
||||
_ = <#impl_ident::#generics as ::windows_core::IUnknownImpl>::QueryInterface(&*boxed, &I::IID, &mut result);
|
||||
::windows_core::Type::from_abi(result)
|
||||
}
|
||||
}
|
||||
|
||||
impl #generics ::core::convert::From<#original_ident::#generics> for ::windows_core::IUnknown where #constraints {
|
||||
#[inline(always)]
|
||||
fn from(this: #original_ident::#generics) -> Self {
|
||||
let com_object = ::windows_core::ComObject::new(this);
|
||||
com_object.into_interface()
|
||||
}
|
||||
}
|
||||
|
||||
impl #generics ::core::convert::From<#original_ident::#generics> for ::windows_core::IInspectable where #constraints {
|
||||
#[inline(always)]
|
||||
fn from(this: #original_ident::#generics) -> Self {
|
||||
let com_object = ::windows_core::ComObject::new(this);
|
||||
com_object.into_interface()
|
||||
}
|
||||
}
|
||||
|
||||
impl #generics ::windows_core::ComObjectInterface<::windows_core::IUnknown> for #impl_ident::#generics where #constraints {
|
||||
#[inline(always)]
|
||||
fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, ::windows_core::IUnknown> {
|
||||
unsafe {
|
||||
let interface_ptr = &self.identity;
|
||||
::core::mem::transmute(interface_ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl #generics ::windows_core::ComObjectInterface<::windows_core::IInspectable> for #impl_ident::#generics where #constraints {
|
||||
#[inline(always)]
|
||||
fn as_interface_ref(&self) -> ::windows_core::InterfaceRef<'_, ::windows_core::IInspectable> {
|
||||
unsafe {
|
||||
let interface_ptr = &self.identity;
|
||||
::core::mem::transmute(interface_ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl #generics ::windows_core::AsImpl<#original_ident::#generics> for ::windows_core::IUnknown where #constraints {
|
||||
// SAFETY: the offset is guranteed to be in bounds, and the implementation struct
|
||||
// is guaranteed to live at least as long as `self`.
|
||||
#[inline(always)]
|
||||
unsafe fn as_impl_ptr(&self) -> ::core::ptr::NonNull<#original_ident::#generics> {
|
||||
let this = ::windows_core::Interface::as_raw(self);
|
||||
// Subtract away the vtable offset plus 1, for the `identity` field, to get
|
||||
// to the impl struct which contains that original implementation type.
|
||||
let this = (this as *mut *mut ::core::ffi::c_void).sub(1) as *mut #impl_ident::#generics;
|
||||
::core::ptr::NonNull::new_unchecked(::core::ptr::addr_of!((*this).this) as *const #original_ident::#generics as *mut #original_ident::#generics)
|
||||
}
|
||||
}
|
||||
|
||||
impl #generics ::core::ops::Deref for #impl_ident::#generics where #constraints {
|
||||
type Target = #original_ident::#generics;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.this
|
||||
}
|
||||
}
|
||||
|
||||
// We intentionally do not provide a DerefMut impl, due to paranoia around soundness.
|
||||
|
||||
#(#conversions)*
|
||||
};
|
||||
|
||||
let mut tokens: proc_macro::TokenStream = tokens.into();
|
||||
tokens.extend(core::iter::once(original_type));
|
||||
tokens
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ImplementType {
|
||||
type_name: String,
|
||||
generics: Vec<ImplementType>,
|
||||
}
|
||||
|
||||
impl ImplementType {
|
||||
fn to_ident(&self) -> proc_macro2::TokenStream {
|
||||
let type_name = syn::parse_str::<proc_macro2::TokenStream>(&self.type_name)
|
||||
.expect("Invalid token stream");
|
||||
let generics = self.generics.iter().map(|g| g.to_ident());
|
||||
quote! { #type_name<#(#generics,)*> }
|
||||
}
|
||||
fn to_vtbl_ident(&self) -> proc_macro2::TokenStream {
|
||||
let ident = self.to_ident();
|
||||
quote! {
|
||||
<#ident as ::windows_core::Interface>::Vtable
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct ImplementAttributes {
|
||||
pub implement: Vec<ImplementType>,
|
||||
pub trust_level: usize,
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for ImplementAttributes {
|
||||
fn parse(cursor: syn::parse::ParseStream<'_>) -> syn::parse::Result<Self> {
|
||||
let mut input = Self::default();
|
||||
|
||||
while !cursor.is_empty() {
|
||||
input.parse_implement(cursor)?;
|
||||
}
|
||||
|
||||
Ok(input)
|
||||
}
|
||||
}
|
||||
|
||||
impl ImplementAttributes {
|
||||
fn parse_implement(&mut self, cursor: syn::parse::ParseStream<'_>) -> syn::parse::Result<()> {
|
||||
let tree = cursor.parse::<UseTree2>()?;
|
||||
self.walk_implement(&tree, &mut String::new())?;
|
||||
|
||||
if !cursor.is_empty() {
|
||||
cursor.parse::<syn::Token![,]>()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn walk_implement(
|
||||
&mut self,
|
||||
tree: &UseTree2,
|
||||
namespace: &mut String,
|
||||
) -> syn::parse::Result<()> {
|
||||
match tree {
|
||||
UseTree2::Path(input) => {
|
||||
if !namespace.is_empty() {
|
||||
namespace.push_str("::");
|
||||
}
|
||||
|
||||
namespace.push_str(&input.ident.to_string());
|
||||
self.walk_implement(&input.tree, namespace)?;
|
||||
}
|
||||
UseTree2::Name(_) => {
|
||||
self.implement.push(tree.to_element_type(namespace)?);
|
||||
}
|
||||
UseTree2::Group(input) => {
|
||||
for tree in &input.items {
|
||||
self.walk_implement(tree, namespace)?;
|
||||
}
|
||||
}
|
||||
UseTree2::TrustLevel(input) => self.trust_level = *input,
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
enum UseTree2 {
|
||||
Path(UsePath2),
|
||||
Name(UseName2),
|
||||
Group(UseGroup2),
|
||||
TrustLevel(usize),
|
||||
}
|
||||
|
||||
impl UseTree2 {
|
||||
fn to_element_type(&self, namespace: &mut String) -> syn::parse::Result<ImplementType> {
|
||||
match self {
|
||||
UseTree2::Path(input) => {
|
||||
if !namespace.is_empty() {
|
||||
namespace.push_str("::");
|
||||
}
|
||||
|
||||
namespace.push_str(&input.ident.to_string());
|
||||
input.tree.to_element_type(namespace)
|
||||
}
|
||||
UseTree2::Name(input) => {
|
||||
let mut type_name = input.ident.to_string();
|
||||
|
||||
if !namespace.is_empty() {
|
||||
type_name = format!("{namespace}::{type_name}");
|
||||
}
|
||||
|
||||
let mut generics = vec![];
|
||||
|
||||
for g in &input.generics {
|
||||
generics.push(g.to_element_type(&mut String::new())?);
|
||||
}
|
||||
|
||||
Ok(ImplementType {
|
||||
type_name,
|
||||
generics,
|
||||
})
|
||||
}
|
||||
UseTree2::Group(input) => Err(syn::parse::Error::new(
|
||||
input.brace_token.span.join(),
|
||||
"Syntax not supported",
|
||||
)),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct UsePath2 {
|
||||
pub ident: syn::Ident,
|
||||
pub tree: Box<UseTree2>,
|
||||
}
|
||||
|
||||
struct UseName2 {
|
||||
pub ident: syn::Ident,
|
||||
pub generics: Vec<UseTree2>,
|
||||
}
|
||||
|
||||
struct UseGroup2 {
|
||||
pub brace_token: syn::token::Brace,
|
||||
pub items: syn::punctuated::Punctuated<UseTree2, syn::Token![,]>,
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for UseTree2 {
|
||||
fn parse(input: syn::parse::ParseStream<'_>) -> syn::parse::Result<UseTree2> {
|
||||
let lookahead = input.lookahead1();
|
||||
if lookahead.peek(syn::Ident) {
|
||||
use syn::ext::IdentExt;
|
||||
let ident = input.call(syn::Ident::parse_any)?;
|
||||
if input.peek(syn::Token![::]) {
|
||||
input.parse::<syn::Token![::]>()?;
|
||||
Ok(UseTree2::Path(UsePath2 {
|
||||
ident,
|
||||
tree: Box::new(input.parse()?),
|
||||
}))
|
||||
} else if input.peek(syn::Token![=]) {
|
||||
if ident != "TrustLevel" {
|
||||
return Err(syn::parse::Error::new(
|
||||
ident.span(),
|
||||
"Unrecognized key-value pair",
|
||||
));
|
||||
}
|
||||
input.parse::<syn::Token![=]>()?;
|
||||
let span = input.span();
|
||||
let value = input.call(syn::Ident::parse_any)?;
|
||||
match value.to_string().as_str() {
|
||||
"Partial" => Ok(UseTree2::TrustLevel(1)),
|
||||
"Full" => Ok(UseTree2::TrustLevel(2)),
|
||||
_ => Err(syn::parse::Error::new(
|
||||
span,
|
||||
"`TrustLevel` must be `Partial` or `Full`",
|
||||
)),
|
||||
}
|
||||
} else {
|
||||
let generics = if input.peek(syn::Token![<]) {
|
||||
input.parse::<syn::Token![<]>()?;
|
||||
let mut generics = Vec::new();
|
||||
loop {
|
||||
generics.push(input.parse::<UseTree2>()?);
|
||||
|
||||
if input.parse::<syn::Token![,]>().is_err() {
|
||||
break;
|
||||
}
|
||||
}
|
||||
input.parse::<syn::Token![>]>()?;
|
||||
generics
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
|
||||
Ok(UseTree2::Name(UseName2 { ident, generics }))
|
||||
}
|
||||
} else if lookahead.peek(syn::token::Brace) {
|
||||
let content;
|
||||
let brace_token = syn::braced!(content in input);
|
||||
let items = content.parse_terminated(UseTree2::parse, syn::Token![,])?;
|
||||
|
||||
Ok(UseTree2::Group(UseGroup2 { brace_token, items }))
|
||||
} else {
|
||||
Err(lookahead.error())
|
||||
}
|
||||
}
|
||||
}
|
||||
1
third_party/rust/windows-interface/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/windows-interface/.cargo-checksum.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"files":{"Cargo.toml":"06b4907a2ab2cd6418fe91777edd5b336ab8bf31c8d9420baaa1d064f4885be2","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","src/lib.rs":"a4d6dc0b000d483e77c10bb8bdf0c36f906aaec35dbe7649150bbf9648221f65"},"package":"053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"}
|
||||
65
third_party/rust/windows-interface/Cargo.toml
vendored
Normal file
65
third_party/rust/windows-interface/Cargo.toml
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.70"
|
||||
name = "windows-interface"
|
||||
version = "0.58.0"
|
||||
authors = ["Microsoft"]
|
||||
build = false
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "The interface macro for the windows crate"
|
||||
readme = false
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/microsoft/windows-rs"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "x86_64-pc-windows-msvc"
|
||||
targets = []
|
||||
|
||||
[lib]
|
||||
name = "windows_interface"
|
||||
path = "src/lib.rs"
|
||||
proc-macro = true
|
||||
|
||||
[dependencies.proc-macro2]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.quote]
|
||||
version = "1.0"
|
||||
|
||||
[dependencies.syn]
|
||||
version = "2.0"
|
||||
features = [
|
||||
"parsing",
|
||||
"proc-macro",
|
||||
"printing",
|
||||
"full",
|
||||
"derive",
|
||||
"clone-impls",
|
||||
]
|
||||
default-features = false
|
||||
|
||||
[lints.rust]
|
||||
missing_docs = "warn"
|
||||
|
||||
[lints.rust.rust_2018_idioms]
|
||||
level = "warn"
|
||||
priority = -1
|
||||
|
||||
[lints.rust.unexpected_cfgs]
|
||||
level = "warn"
|
||||
priority = 0
|
||||
check-cfg = ["cfg(windows_raw_dylib, windows_debugger_visualizer, windows_slim_errors)"]
|
||||
201
third_party/rust/windows-interface/license-apache-2.0
vendored
Normal file
201
third_party/rust/windows-interface/license-apache-2.0
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
21
third_party/rust/windows-interface/license-mit
vendored
Normal file
21
third_party/rust/windows-interface/license-mit
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
760
third_party/rust/windows-interface/src/lib.rs
vendored
Normal file
760
third_party/rust/windows-interface/src/lib.rs
vendored
Normal file
@@ -0,0 +1,760 @@
|
||||
/*!
|
||||
Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs>
|
||||
*/
|
||||
|
||||
use quote::quote;
|
||||
use syn::spanned::Spanned;
|
||||
|
||||
/// Defines a COM interface to call or implement.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust,ignore
|
||||
/// #[interface("094d70d6-5202-44b8-abb8-43860da5aca2")]
|
||||
/// unsafe trait IValue: IUnknown {
|
||||
/// fn GetValue(&self, value: *mut i32) -> HRESULT;
|
||||
/// }
|
||||
///
|
||||
/// #[implement(IValue)]
|
||||
/// struct Value(i32);
|
||||
///
|
||||
/// impl IValue_Impl for Value {
|
||||
/// unsafe fn GetValue(&self, value: *mut i32) -> HRESULT {
|
||||
/// *value = self.0;
|
||||
/// HRESULT(0)
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let object: IValue = Value(123).into();
|
||||
/// // Call interface methods...
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn interface(
|
||||
attributes: proc_macro::TokenStream,
|
||||
original_type: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
let guid = syn::parse_macro_input!(attributes as Guid);
|
||||
let interface = syn::parse_macro_input!(original_type as Interface);
|
||||
let tokens = match interface.gen_tokens(&guid) {
|
||||
Ok(t) => t,
|
||||
Err(e) => return e.to_compile_error().into(),
|
||||
};
|
||||
tokens.into()
|
||||
}
|
||||
|
||||
macro_rules! bail {
|
||||
($item:expr, $($msg:tt),*) => {
|
||||
return Err(syn::Error::new($item.span(), std::fmt::format(format_args!($($msg),*))));
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
macro_rules! unexpected_token {
|
||||
($item:expr, $msg:expr) => {
|
||||
if let Some(i) = $item {
|
||||
bail!(i, "unexpected {}", $msg);
|
||||
}
|
||||
};
|
||||
}
|
||||
macro_rules! expected_token {
|
||||
($sig:tt.$item:tt(), $msg:expr) => {
|
||||
if let None = $sig.$item() {
|
||||
bail!($sig, "expected {}", $msg);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Parsed interface
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// #[windows_interface::interface("8CEEB155-2849-4ce5-9448-91FF70E1E4D9")]
|
||||
/// unsafe trait IUIAnimationVariable: IUnknown {
|
||||
/// //^ parses this
|
||||
/// fn GetValue(&self, value: *mut f64) -> HRESULT;
|
||||
/// }
|
||||
/// ```
|
||||
struct Interface {
|
||||
visibility: syn::Visibility,
|
||||
name: syn::Ident,
|
||||
parent: Option<syn::Path>,
|
||||
methods: Vec<InterfaceMethod>,
|
||||
docs: Vec<syn::Attribute>,
|
||||
}
|
||||
|
||||
impl Interface {
|
||||
/// Generates all the code needed for a COM interface
|
||||
fn gen_tokens(&self, guid: &Guid) -> syn::Result<proc_macro2::TokenStream> {
|
||||
let vis = &self.visibility;
|
||||
let name = &self.name;
|
||||
let docs = &self.docs;
|
||||
let parent = self.parent_type();
|
||||
let vtable_name = quote::format_ident!("{}_Vtbl", name);
|
||||
let guid = guid.to_tokens()?;
|
||||
let implementation = self.gen_implementation();
|
||||
let com_trait = self.get_com_trait();
|
||||
let vtable = self.gen_vtable(&vtable_name);
|
||||
let conversions = self.gen_conversions();
|
||||
|
||||
Ok(quote! {
|
||||
#[repr(transparent)]
|
||||
#(#docs)*
|
||||
#vis struct #name(#parent);
|
||||
#implementation
|
||||
unsafe impl ::windows_core::Interface for #name {
|
||||
type Vtable = #vtable_name;
|
||||
const IID: ::windows_core::GUID = #guid;
|
||||
}
|
||||
impl ::windows_core::RuntimeName for #name {}
|
||||
impl ::core::ops::Deref for #name {
|
||||
type Target = #parent;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { ::core::mem::transmute(self) }
|
||||
}
|
||||
}
|
||||
#com_trait
|
||||
#vtable
|
||||
#conversions
|
||||
})
|
||||
}
|
||||
|
||||
/// Generates the methods users can call on the COM interface pointer
|
||||
fn gen_implementation(&self) -> proc_macro2::TokenStream {
|
||||
let name = &self.name;
|
||||
let methods = self
|
||||
.methods
|
||||
.iter()
|
||||
.map(|m| {
|
||||
let vis = &m.visibility;
|
||||
let name = &m.name;
|
||||
|
||||
let generics = m.gen_consume_generics();
|
||||
let params = m.gen_consume_params();
|
||||
let args = m.gen_consume_args();
|
||||
let ret = &m.ret;
|
||||
|
||||
if m.is_result() {
|
||||
quote! {
|
||||
#[inline(always)]
|
||||
#vis unsafe fn #name<#(#generics),*>(&self, #(#params),*) #ret {
|
||||
(::windows_core::Interface::vtable(self).#name)(::windows_core::Interface::as_raw(self), #(#args),*).ok()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
#[inline(always)]
|
||||
#vis unsafe fn #name<#(#generics),*>(&self, #(#params),*) #ret {
|
||||
(::windows_core::Interface::vtable(self).#name)(::windows_core::Interface::as_raw(self), #(#args),*)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
quote! {
|
||||
impl #name {
|
||||
#(#methods)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_com_trait(&self) -> proc_macro2::TokenStream {
|
||||
let name = quote::format_ident!("{}_Impl", self.name);
|
||||
let vis = &self.visibility;
|
||||
let methods = self
|
||||
.methods
|
||||
.iter()
|
||||
.map(|m| {
|
||||
let name = &m.name;
|
||||
let docs = &m.docs;
|
||||
let args = m.gen_args();
|
||||
let ret = &m.ret;
|
||||
quote! {
|
||||
#(#docs)*
|
||||
unsafe fn #name(&self, #(#args),*) #ret;
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let parent = self.parent_trait_constraint();
|
||||
|
||||
quote! {
|
||||
#[allow(non_camel_case_types)]
|
||||
#vis trait #name: Sized + #parent {
|
||||
#(#methods)*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates the vtable for a COM interface
|
||||
fn gen_vtable(&self, vtable_name: &syn::Ident) -> proc_macro2::TokenStream {
|
||||
let vis = &self.visibility;
|
||||
let name = &self.name;
|
||||
let trait_name = quote::format_ident!("{}_Impl", name);
|
||||
let implvtbl_name = quote::format_ident!("{}_ImplVtbl", name);
|
||||
|
||||
let vtable_entries = self
|
||||
.methods
|
||||
.iter()
|
||||
.map(|m| {
|
||||
let name = &m.name;
|
||||
let ret = &m.ret;
|
||||
let args = m.gen_args();
|
||||
|
||||
if m.is_result() {
|
||||
quote! {
|
||||
pub #name: unsafe extern "system" fn(this: *mut ::core::ffi::c_void, #(#args),*) -> ::windows_core::HRESULT,
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
pub #name: unsafe extern "system" fn(this: *mut ::core::ffi::c_void, #(#args),*) #ret,
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let parent_vtable_generics = quote!(Identity, OFFSET);
|
||||
let parent_vtable = self.parent_vtable();
|
||||
|
||||
// or_parent_matches will be `|| parent::matches(iid)` if this interface inherits from another
|
||||
// interface (except for IUnknown) or will be empty if this is not applicable. This is what allows
|
||||
// QueryInterface to work correctly for all interfaces in an inheritance chain, e.g.
|
||||
// IFoo3 derives from IFoo2 derives from IFoo.
|
||||
//
|
||||
// We avoid matching IUnknown because object identity depends on the uniqueness of the IUnknown pointer.
|
||||
let or_parent_matches = match parent_vtable.as_ref() {
|
||||
Some(parent) if !self.parent_is_iunknown() => quote! (|| <#parent>::matches(iid)),
|
||||
_ => quote!(),
|
||||
};
|
||||
|
||||
let functions = self
|
||||
.methods
|
||||
.iter()
|
||||
.map(|m| {
|
||||
let name = &m.name;
|
||||
let args = m.gen_args();
|
||||
let params = &m
|
||||
.args
|
||||
.iter()
|
||||
.map(|a| {
|
||||
let pat = &a.pat;
|
||||
quote! { #pat }
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let ret = &m.ret;
|
||||
|
||||
let ret = if m.is_result() {
|
||||
quote! { -> ::windows_core::HRESULT }
|
||||
} else {
|
||||
quote! { #ret }
|
||||
};
|
||||
|
||||
if parent_vtable.is_some() {
|
||||
quote! {
|
||||
unsafe extern "system" fn #name<
|
||||
Identity: ::windows_core::IUnknownImpl,
|
||||
const OFFSET: isize
|
||||
>(
|
||||
this: *mut ::core::ffi::c_void, // <-- This is the COM "this" pointer, which is not the same as &T or &T_Impl.
|
||||
#(#args),*
|
||||
) #ret
|
||||
where
|
||||
Identity : #trait_name
|
||||
{
|
||||
// This step is essentially a virtual dispatch adjustor thunk. Its purpose is to adjust
|
||||
// the "this" pointer from the address used by the COM interface to the root of the
|
||||
// MyApp_Impl object. Since a given MyApp_Impl may implement more than one COM interface
|
||||
// (and more than one COM interface chain), we need to know how to get from COM's "this"
|
||||
// back to &MyApp_Impl. The OFFSET constant gives us the value (in pointer-sized units).
|
||||
let this_outer: &Identity = &*((this as *const *const ()).offset(OFFSET) as *const Identity);
|
||||
|
||||
// Last, we invoke the implementation function.
|
||||
// We use explicit <Impl as IFoo_Impl> so that we can select the correct method
|
||||
// for situations where IFoo3 derives from IFoo2 and both declare a method with
|
||||
// the same name.
|
||||
<Identity as #trait_name>::#name(this_outer, #(#params),*).into()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
unsafe extern "system" fn #name<Impl: #trait_name>(this: *mut ::core::ffi::c_void, #(#args),*) #ret {
|
||||
let this = (this as *mut *mut ::core::ffi::c_void) as *const ::windows_core::ScopedHeap;
|
||||
let this = (*this).this as *const Impl;
|
||||
(*this).#name(#(#params),*).into()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if let Some(parent_vtable) = parent_vtable {
|
||||
let entries = self
|
||||
.methods
|
||||
.iter()
|
||||
.map(|m| {
|
||||
let name = &m.name;
|
||||
quote!(#name: #name::<Identity, OFFSET>)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
#[repr(C)]
|
||||
#[doc(hidden)]
|
||||
#vis struct #vtable_name {
|
||||
pub base__: #parent_vtable,
|
||||
#(#vtable_entries)*
|
||||
}
|
||||
impl #vtable_name {
|
||||
pub const fn new<
|
||||
Identity: ::windows_core::IUnknownImpl,
|
||||
const OFFSET: isize,
|
||||
>() -> Self
|
||||
where
|
||||
Identity : #trait_name
|
||||
{
|
||||
#(#functions)*
|
||||
Self { base__: #parent_vtable::new::<#parent_vtable_generics>(), #(#entries),* }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn matches(iid: &::windows_core::GUID) -> bool {
|
||||
*iid == <#name as ::windows_core::Interface>::IID
|
||||
#or_parent_matches
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let entries = self
|
||||
.methods
|
||||
.iter()
|
||||
.map(|m| {
|
||||
let name = &m.name;
|
||||
quote!(#name: #name::<Impl>)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
quote! {
|
||||
#[repr(C)]
|
||||
#[doc(hidden)]
|
||||
#vis struct #vtable_name {
|
||||
#(#vtable_entries)*
|
||||
}
|
||||
impl #vtable_name {
|
||||
pub const fn new<Impl: #trait_name>() -> Self {
|
||||
#(#functions)*
|
||||
Self { #(#entries),* }
|
||||
}
|
||||
}
|
||||
struct #implvtbl_name<T: #trait_name> (::core::marker::PhantomData<T>);
|
||||
impl<T: #trait_name> #implvtbl_name<T> {
|
||||
const VTABLE: #vtable_name = #vtable_name::new::<T>();
|
||||
}
|
||||
impl #name {
|
||||
fn new<'a, T: #trait_name>(this: &'a T) -> ::windows_core::ScopedInterface<'a, #name> {
|
||||
let this = ::windows_core::ScopedHeap { vtable: &#implvtbl_name::<T>::VTABLE as *const _ as *const _, this: this as *const _ as *const _ };
|
||||
let this = ::core::mem::ManuallyDrop::new(::windows_core::imp::Box::new(this));
|
||||
unsafe { ::windows_core::ScopedInterface::new(::core::mem::transmute(&this.vtable)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Generates various conversions such as from and to `IUnknown`
|
||||
fn gen_conversions(&self) -> proc_macro2::TokenStream {
|
||||
let name = &self.name;
|
||||
let name_string = format!("{name}");
|
||||
quote! {
|
||||
impl ::core::convert::From<#name> for ::windows_core::IUnknown {
|
||||
fn from(value: #name) -> Self {
|
||||
unsafe { ::core::mem::transmute(value) }
|
||||
}
|
||||
}
|
||||
impl ::core::convert::From<&#name> for ::windows_core::IUnknown {
|
||||
fn from(value: &#name) -> Self {
|
||||
::core::convert::From::from(::core::clone::Clone::clone(value))
|
||||
}
|
||||
}
|
||||
impl ::core::clone::Clone for #name {
|
||||
fn clone(&self) -> Self {
|
||||
Self(self.0.clone())
|
||||
}
|
||||
}
|
||||
impl ::core::cmp::PartialEq for #name {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
impl ::core::cmp::Eq for #name {}
|
||||
impl ::core::fmt::Debug for #name {
|
||||
fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
|
||||
f.debug_tuple(#name_string).field(&::windows_core::Interface::as_raw(self)).finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_type(&self) -> proc_macro2::TokenStream {
|
||||
if let Some(parent) = &self.parent {
|
||||
quote!(#parent)
|
||||
} else {
|
||||
quote!(::core::ptr::NonNull<::core::ffi::c_void>)
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_vtable(&self) -> Option<proc_macro2::TokenStream> {
|
||||
if let Some((ident, path)) = self.parent_path().split_last() {
|
||||
let ident = quote::format_ident!("{}_Vtbl", ident);
|
||||
Some(quote! { #(#path::)* #ident })
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_is_iunknown(&self) -> bool {
|
||||
if let Some(ident) = self.parent_path().last() {
|
||||
ident == "IUnknown"
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn parent_path(&self) -> Vec<syn::Ident> {
|
||||
if let Some(parent) = &self.parent {
|
||||
parent
|
||||
.segments
|
||||
.iter()
|
||||
.map(|segment| segment.ident.clone())
|
||||
.collect()
|
||||
} else {
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the parent trait constrait which is nothing if the parent is IUnknown
|
||||
fn parent_trait_constraint(&self) -> proc_macro2::TokenStream {
|
||||
if let Some((ident, path)) = self.parent_path().split_last() {
|
||||
if ident != "IUnknown" {
|
||||
let ident = quote::format_ident!("{}_Impl", ident);
|
||||
return quote! { #(#path::)* #ident };
|
||||
}
|
||||
}
|
||||
|
||||
quote! {}
|
||||
}
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for Interface {
|
||||
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
|
||||
let attributes = input.call(syn::Attribute::parse_outer)?;
|
||||
let mut docs = Vec::new();
|
||||
for attr in attributes.into_iter() {
|
||||
let path = attr.path();
|
||||
if path.is_ident("doc") {
|
||||
docs.push(attr);
|
||||
} else {
|
||||
return Err(syn::Error::new(path.span(), "Unrecognized attribute "));
|
||||
}
|
||||
}
|
||||
|
||||
let visibility = input.parse::<syn::Visibility>()?;
|
||||
_ = input.parse::<syn::Token![unsafe]>()?;
|
||||
_ = input.parse::<syn::Token![trait]>()?;
|
||||
let name = input.parse::<syn::Ident>()?;
|
||||
_ = input.parse::<syn::Token![:]>();
|
||||
let parent = input.parse::<syn::Path>().ok();
|
||||
let content;
|
||||
syn::braced!(content in input);
|
||||
let mut methods = Vec::new();
|
||||
while !content.is_empty() {
|
||||
methods.push(content.parse::<InterfaceMethod>()?);
|
||||
}
|
||||
Ok(Self {
|
||||
visibility,
|
||||
methods,
|
||||
name,
|
||||
parent,
|
||||
docs,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Parsed interface guid attribute
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// #[windows_interface::interface("8CEEB155-2849-4ce5-9448-91FF70E1E4D9")]
|
||||
/// //^ parses this
|
||||
/// unsafe trait IUIAnimationVariable: IUnknown {
|
||||
/// fn GetValue(&self, value: *mut f64) -> HRESULT;
|
||||
/// }
|
||||
/// ```
|
||||
struct Guid(Option<syn::LitStr>);
|
||||
|
||||
impl Guid {
|
||||
fn to_tokens(&self) -> syn::Result<proc_macro2::TokenStream> {
|
||||
fn hex_lit(num: &str) -> syn::LitInt {
|
||||
syn::LitInt::new(&format!("0x{num}"), proc_macro2::Span::call_site())
|
||||
}
|
||||
|
||||
fn ensure_length(
|
||||
part: Option<&str>,
|
||||
index: usize,
|
||||
length: usize,
|
||||
span: proc_macro2::Span,
|
||||
) -> syn::Result<String> {
|
||||
let part = match part {
|
||||
Some(p) => p,
|
||||
None => {
|
||||
return Err(syn::Error::new(
|
||||
span,
|
||||
format!("The IID missing part at index {index}"),
|
||||
))
|
||||
}
|
||||
};
|
||||
|
||||
if part.len() != length {
|
||||
return Err(syn::Error::new(
|
||||
span,
|
||||
format!(
|
||||
"The IID part at index {} must be {} characters long but was {} characters",
|
||||
index,
|
||||
length,
|
||||
part.len()
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(part.to_owned())
|
||||
}
|
||||
|
||||
if let Some(value) = &self.0 {
|
||||
let guid_value = value.value();
|
||||
let mut delimited = guid_value.split('-').fuse();
|
||||
let chunks = [
|
||||
ensure_length(delimited.next(), 0, 8, value.span())?,
|
||||
ensure_length(delimited.next(), 1, 4, value.span())?,
|
||||
ensure_length(delimited.next(), 2, 4, value.span())?,
|
||||
ensure_length(delimited.next(), 3, 4, value.span())?,
|
||||
ensure_length(delimited.next(), 4, 12, value.span())?,
|
||||
];
|
||||
|
||||
let data1 = hex_lit(&chunks[0]);
|
||||
let data2 = hex_lit(&chunks[1]);
|
||||
let data3 = hex_lit(&chunks[2]);
|
||||
let (data4_1, data4_2) = chunks[3].split_at(2);
|
||||
let data4_1 = hex_lit(data4_1);
|
||||
let data4_2 = hex_lit(data4_2);
|
||||
let (data4_3, rest) = chunks[4].split_at(2);
|
||||
let data4_3 = hex_lit(data4_3);
|
||||
|
||||
let (data4_4, rest) = rest.split_at(2);
|
||||
let data4_4 = hex_lit(data4_4);
|
||||
|
||||
let (data4_5, rest) = rest.split_at(2);
|
||||
let data4_5 = hex_lit(data4_5);
|
||||
|
||||
let (data4_6, rest) = rest.split_at(2);
|
||||
let data4_6 = hex_lit(data4_6);
|
||||
|
||||
let (data4_7, data4_8) = rest.split_at(2);
|
||||
let data4_7 = hex_lit(data4_7);
|
||||
let data4_8 = hex_lit(data4_8);
|
||||
Ok(quote! {
|
||||
::windows_core::GUID {
|
||||
data1: #data1,
|
||||
data2: #data2,
|
||||
data3: #data3,
|
||||
data4: [#data4_1, #data4_2, #data4_3, #data4_4, #data4_5, #data4_6, #data4_7, #data4_8]
|
||||
}
|
||||
})
|
||||
} else {
|
||||
Ok(quote! {
|
||||
::windows_core::GUID::zeroed()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for Guid {
|
||||
fn parse(cursor: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
|
||||
let string: Option<syn::LitStr> = cursor.parse().ok();
|
||||
|
||||
Ok(Self(string))
|
||||
}
|
||||
}
|
||||
|
||||
/// A parsed interface method
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// #[windows_interface::interface("8CEEB155-2849-4ce5-9448-91FF70E1E4D9")]
|
||||
/// unsafe trait IUIAnimationVariable: IUnknown {
|
||||
/// fn GetValue(&self, value: *mut f64) -> HRESULT;
|
||||
/// //^ parses this
|
||||
/// }
|
||||
/// ```
|
||||
struct InterfaceMethod {
|
||||
pub name: syn::Ident,
|
||||
pub visibility: syn::Visibility,
|
||||
pub args: Vec<InterfaceMethodArg>,
|
||||
pub ret: syn::ReturnType,
|
||||
pub docs: Vec<syn::Attribute>,
|
||||
}
|
||||
|
||||
impl InterfaceMethod {
|
||||
fn is_result(&self) -> bool {
|
||||
if let syn::ReturnType::Type(_, ty) = &self.ret {
|
||||
if let syn::Type::Path(path) = &**ty {
|
||||
if let Some(segment) = path.path.segments.last() {
|
||||
let ident = segment.ident.to_string();
|
||||
if ident == "Result" {
|
||||
if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
|
||||
if args.args.len() == 1 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
|
||||
/// Generates arguments (of the form `$pat: $type`)
|
||||
fn gen_args(&self) -> Vec<proc_macro2::TokenStream> {
|
||||
self.args
|
||||
.iter()
|
||||
.map(|a| {
|
||||
let pat = &a.pat;
|
||||
let ty = &a.ty;
|
||||
quote! { #pat: #ty }
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn gen_consume_generics(&self) -> Vec<proc_macro2::TokenStream> {
|
||||
self.args
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter_map(|(generic_index, a)| {
|
||||
if let Some((ty, ident)) = a.borrow_type() {
|
||||
let generic_ident = quote::format_ident!("P{generic_index}");
|
||||
if ident == "Ref" {
|
||||
Some(quote! { #generic_ident: ::windows_core::Param<#ty> })
|
||||
} else {
|
||||
Some(quote! { #generic_ident: ::windows_core::OutParam<#ty> })
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn gen_consume_params(&self) -> Vec<proc_macro2::TokenStream> {
|
||||
self.args
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(generic_index, a)| {
|
||||
let pat = &a.pat;
|
||||
|
||||
if a.borrow_type().is_some() {
|
||||
let generic_ident = quote::format_ident!("P{generic_index}");
|
||||
quote! { #pat: #generic_ident }
|
||||
} else {
|
||||
let ty = &a.ty;
|
||||
quote! { #pat: #ty }
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn gen_consume_args(&self) -> Vec<proc_macro2::TokenStream> {
|
||||
self.args
|
||||
.iter()
|
||||
.map(|a| {
|
||||
let pat = &a.pat;
|
||||
|
||||
if let Some((_, ident)) = a.borrow_type() {
|
||||
if ident == "Ref" {
|
||||
quote! { #pat.param().borrow() }
|
||||
} else {
|
||||
quote! { #pat.borrow_mut() }
|
||||
}
|
||||
} else {
|
||||
quote! { #pat }
|
||||
}
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
}
|
||||
|
||||
impl syn::parse::Parse for InterfaceMethod {
|
||||
fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
|
||||
let docs = input.call(syn::Attribute::parse_outer)?;
|
||||
let visibility = input.parse::<syn::Visibility>()?;
|
||||
let method = input.parse::<syn::TraitItemFn>()?;
|
||||
unexpected_token!(docs.iter().find(|a| !a.path().is_ident("doc")), "attribute");
|
||||
unexpected_token!(method.default, "default method implementation");
|
||||
let sig = method.sig;
|
||||
unexpected_token!(sig.abi, "abi declaration");
|
||||
unexpected_token!(sig.asyncness, "async declaration");
|
||||
unexpected_token!(sig.generics.params.iter().next(), "generics declaration");
|
||||
unexpected_token!(sig.constness, "const declaration");
|
||||
expected_token!(
|
||||
sig.receiver(),
|
||||
"the method to have &self as its first argument"
|
||||
);
|
||||
unexpected_token!(sig.variadic, "variadic args");
|
||||
let args = sig
|
||||
.inputs
|
||||
.into_iter()
|
||||
.filter_map(|a| match a {
|
||||
syn::FnArg::Receiver(_) => None,
|
||||
syn::FnArg::Typed(p) => Some(p),
|
||||
})
|
||||
.map(|p| {
|
||||
Ok(InterfaceMethodArg {
|
||||
ty: p.ty,
|
||||
pat: p.pat,
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<InterfaceMethodArg>, syn::Error>>()?;
|
||||
|
||||
let ret = sig.output;
|
||||
Ok(InterfaceMethod {
|
||||
name: sig.ident,
|
||||
visibility,
|
||||
args,
|
||||
ret,
|
||||
docs,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// An argument to an interface method
|
||||
struct InterfaceMethodArg {
|
||||
/// The type of the argument
|
||||
pub ty: Box<syn::Type>,
|
||||
/// The name of the argument
|
||||
pub pat: Box<syn::Pat>,
|
||||
}
|
||||
|
||||
impl InterfaceMethodArg {
|
||||
fn borrow_type(&self) -> Option<(syn::Type, String)> {
|
||||
if let syn::Type::Path(path) = &*self.ty {
|
||||
if let Some(segment) = path.path.segments.last() {
|
||||
let ident = segment.ident.to_string();
|
||||
if matches!(ident.as_str(), "Ref" | "OutRef") {
|
||||
if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
|
||||
if args.args.len() == 1 {
|
||||
if let Some(syn::GenericArgument::Type(ty)) = args.args.first() {
|
||||
return Some((ty.clone(), ident));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
1
third_party/rust/windows-result/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/windows-result/.cargo-checksum.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"files":{"Cargo.toml":"5b207ca32f201bf44d5049ffdf90114c161bf103a2c79564e471c36d001565e1","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"0b5595048105c4e66cbc8ce38a551a0c7f28c0c4c69670e696a32df0e5aec9f5","src/bindings.rs":"13e2ec0239e501aae80277cbcdc666a1a671b41b8a4ef91a07f9cb56bd490ecb","src/bstr.rs":"651542aaaa71c11eb129263fe1966f592823ce5717ee937aa7ae23f6b0e45b91","src/com.rs":"3111c836c9a2cabcf01b06fc65af474a1e071d9c887db178105c2b52ec78bdd5","src/error.rs":"6c3d05bb2177791bff427eeaea204462202bb3ed2dc8727babdfefc4f1b3e84f","src/hresult.rs":"2a0f9f532e5e715d316735f626c1cf9e895ca1cc0aa65fedeeb01953028c4573","src/lib.rs":"985e3b67988b97ddd0358189a3d1ac9ea346b067787fae981ac3166ce04b2674","src/strings.rs":"fba5cda8e1d5ce430cfff8f9195a5cc4d7f880262715469583e8ec835a51ea8a"},"package":"1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"}
|
||||
54
third_party/rust/windows-result/Cargo.toml
vendored
Normal file
54
third_party/rust/windows-result/Cargo.toml
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.60"
|
||||
name = "windows-result"
|
||||
version = "0.2.0"
|
||||
authors = ["Microsoft"]
|
||||
build = false
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "Windows error handling"
|
||||
readme = "readme.md"
|
||||
categories = ["os::windows-apis"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/microsoft/windows-rs"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "x86_64-pc-windows-msvc"
|
||||
targets = []
|
||||
|
||||
[lib]
|
||||
name = "windows_result"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies.windows-targets]
|
||||
version = "0.52.6"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
|
||||
[lints.rust]
|
||||
missing_docs = "warn"
|
||||
|
||||
[lints.rust.rust_2018_idioms]
|
||||
level = "warn"
|
||||
priority = -1
|
||||
|
||||
[lints.rust.unexpected_cfgs]
|
||||
level = "warn"
|
||||
priority = 0
|
||||
check-cfg = ["cfg(windows_raw_dylib, windows_debugger_visualizer, windows_slim_errors)"]
|
||||
201
third_party/rust/windows-result/license-apache-2.0
vendored
Normal file
201
third_party/rust/windows-result/license-apache-2.0
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
21
third_party/rust/windows-result/license-mit
vendored
Normal file
21
third_party/rust/windows-result/license-mit
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
32
third_party/rust/windows-result/readme.md
vendored
Normal file
32
third_party/rust/windows-result/readme.md
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
## Windows error handling
|
||||
|
||||
The [windows-result](https://crates.io/crates/windows-result) crate provides efficient Windows error handling and propagation with support for Win32, COM, and WinRT APIs.
|
||||
|
||||
* [Getting started](https://kennykerr.ca/rust-getting-started/)
|
||||
* [Samples](https://github.com/microsoft/windows-rs/tree/0.58.0/crates/samples)
|
||||
* [Releases](https://github.com/microsoft/windows-rs/releases)
|
||||
|
||||
Start by adding the following to your Cargo.toml file:
|
||||
|
||||
```toml
|
||||
[dependencies.windows-result]
|
||||
version = "0.2"
|
||||
```
|
||||
|
||||
Use the `HRESULT`, `Error`, and specialized `Result` types as needed:
|
||||
|
||||
```rust
|
||||
use windows_result::*;
|
||||
|
||||
const S_OK: HRESULT = HRESULT(0);
|
||||
const ERROR_CANCELLED: u32 = 1223;
|
||||
const E_CANCELLED: HRESULT = HRESULT::from_win32(ERROR_CANCELLED);
|
||||
|
||||
fn main() -> Result<()> {
|
||||
S_OK.ok()?;
|
||||
let e = Error::new(E_CANCELLED, "test message");
|
||||
assert_eq!(e.code(), E_CANCELLED);
|
||||
assert_eq!(e.message(), "test message");
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
89
third_party/rust/windows-result/src/bindings.rs
vendored
Normal file
89
third_party/rust/windows-result/src/bindings.rs
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
#![allow(
|
||||
non_snake_case,
|
||||
non_upper_case_globals,
|
||||
non_camel_case_types,
|
||||
dead_code,
|
||||
clippy::all
|
||||
)]
|
||||
windows_targets::link!("api-ms-win-core-winrt-error-l1-1-0.dll" "system" fn RoOriginateErrorW(error : HRESULT, cchmax : u32, message : PCWSTR) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn FormatMessageW(dwflags : FORMAT_MESSAGE_OPTIONS, lpsource : *const core::ffi::c_void, dwmessageid : u32, dwlanguageid : u32, lpbuffer : PWSTR, nsize : u32, arguments : *const *const i8) -> u32);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetLastError() -> WIN32_ERROR);
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap : HANDLE, dwflags : HEAP_FLAGS, lpmem : *const core::ffi::c_void) -> BOOL);
|
||||
windows_targets::link!("kernel32.dll" "system" fn LoadLibraryExA(lplibfilename : PCSTR, hfile : HANDLE, dwflags : LOAD_LIBRARY_FLAGS) -> HMODULE);
|
||||
windows_targets::link!("oleaut32.dll" "system" fn GetErrorInfo(dwreserved : u32, pperrinfo : *mut * mut core::ffi::c_void) -> HRESULT);
|
||||
windows_targets::link!("oleaut32.dll" "system" fn SetErrorInfo(dwreserved : u32, perrinfo : * mut core::ffi::c_void) -> HRESULT);
|
||||
windows_targets::link!("oleaut32.dll" "system" fn SysFreeString(bstrstring : BSTR));
|
||||
windows_targets::link!("oleaut32.dll" "system" fn SysStringLen(pbstr : BSTR) -> u32);
|
||||
pub type BOOL = i32;
|
||||
pub type BSTR = *const u16;
|
||||
pub const ERROR_INVALID_DATA: WIN32_ERROR = 13u32;
|
||||
pub const ERROR_NO_UNICODE_TRANSLATION: WIN32_ERROR = 1113u32;
|
||||
pub const E_UNEXPECTED: HRESULT = 0x8000FFFF_u32 as _;
|
||||
pub const FORMAT_MESSAGE_ALLOCATE_BUFFER: FORMAT_MESSAGE_OPTIONS = 256u32;
|
||||
pub const FORMAT_MESSAGE_FROM_HMODULE: FORMAT_MESSAGE_OPTIONS = 2048u32;
|
||||
pub const FORMAT_MESSAGE_FROM_SYSTEM: FORMAT_MESSAGE_OPTIONS = 4096u32;
|
||||
pub const FORMAT_MESSAGE_IGNORE_INSERTS: FORMAT_MESSAGE_OPTIONS = 512u32;
|
||||
pub type FORMAT_MESSAGE_OPTIONS = u32;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct GUID {
|
||||
pub data1: u32,
|
||||
pub data2: u16,
|
||||
pub data3: u16,
|
||||
pub data4: [u8; 8],
|
||||
}
|
||||
impl GUID {
|
||||
pub const fn from_u128(uuid: u128) -> Self {
|
||||
Self {
|
||||
data1: (uuid >> 96) as u32,
|
||||
data2: (uuid >> 80 & 0xffff) as u16,
|
||||
data3: (uuid >> 64 & 0xffff) as u16,
|
||||
data4: (uuid as u64).to_be_bytes(),
|
||||
}
|
||||
}
|
||||
}
|
||||
pub type HANDLE = *mut core::ffi::c_void;
|
||||
pub type HEAP_FLAGS = u32;
|
||||
pub type HMODULE = *mut core::ffi::c_void;
|
||||
pub type HRESULT = i32;
|
||||
pub const IID_IErrorInfo: GUID = GUID::from_u128(0x1cf2b120_547d_101b_8e65_08002b2bd119);
|
||||
#[repr(C)]
|
||||
pub struct IErrorInfo_Vtbl {
|
||||
pub base__: IUnknown_Vtbl,
|
||||
pub GetGUID: unsafe extern "system" fn(*mut core::ffi::c_void, *mut GUID) -> HRESULT,
|
||||
pub GetSource: unsafe extern "system" fn(*mut core::ffi::c_void, *mut BSTR) -> HRESULT,
|
||||
pub GetDescription: unsafe extern "system" fn(*mut core::ffi::c_void, *mut BSTR) -> HRESULT,
|
||||
pub GetHelpFile: unsafe extern "system" fn(*mut core::ffi::c_void, *mut BSTR) -> HRESULT,
|
||||
pub GetHelpContext: unsafe extern "system" fn(*mut core::ffi::c_void, *mut u32) -> HRESULT,
|
||||
}
|
||||
pub const IID_IRestrictedErrorInfo: GUID = GUID::from_u128(0x82ba7092_4c88_427d_a7bc_16dd93feb67e);
|
||||
#[repr(C)]
|
||||
pub struct IRestrictedErrorInfo_Vtbl {
|
||||
pub base__: IUnknown_Vtbl,
|
||||
pub GetErrorDetails: unsafe extern "system" fn(
|
||||
*mut core::ffi::c_void,
|
||||
*mut BSTR,
|
||||
*mut HRESULT,
|
||||
*mut BSTR,
|
||||
*mut BSTR,
|
||||
) -> HRESULT,
|
||||
pub GetReference: unsafe extern "system" fn(*mut core::ffi::c_void, *mut BSTR) -> HRESULT,
|
||||
}
|
||||
pub const IID_IUnknown: GUID = GUID::from_u128(0x00000000_0000_0000_c000_000000000046);
|
||||
#[repr(C)]
|
||||
pub struct IUnknown_Vtbl {
|
||||
pub QueryInterface: unsafe extern "system" fn(
|
||||
this: *mut core::ffi::c_void,
|
||||
iid: *const GUID,
|
||||
interface: *mut *mut core::ffi::c_void,
|
||||
) -> HRESULT,
|
||||
pub AddRef: unsafe extern "system" fn(this: *mut core::ffi::c_void) -> u32,
|
||||
pub Release: unsafe extern "system" fn(this: *mut core::ffi::c_void) -> u32,
|
||||
}
|
||||
pub type LOAD_LIBRARY_FLAGS = u32;
|
||||
pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: LOAD_LIBRARY_FLAGS = 4096u32;
|
||||
pub type PCSTR = *const u8;
|
||||
pub type PCWSTR = *const u16;
|
||||
pub type PWSTR = *mut u16;
|
||||
pub type WIN32_ERROR = u32;
|
||||
50
third_party/rust/windows-result/src/bstr.rs
vendored
Normal file
50
third_party/rust/windows-result/src/bstr.rs
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
use super::*;
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct BasicString(*const u16);
|
||||
|
||||
impl BasicString {
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
if self.0.is_null() {
|
||||
0
|
||||
} else {
|
||||
unsafe { SysStringLen(self.0) as usize }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_wide(&self) -> &[u16] {
|
||||
let len = self.len();
|
||||
if len != 0 {
|
||||
unsafe { core::slice::from_raw_parts(self.as_ptr(), len) }
|
||||
} else {
|
||||
&[]
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_ptr(&self) -> *const u16 {
|
||||
if !self.is_empty() {
|
||||
self.0
|
||||
} else {
|
||||
const EMPTY: [u16; 1] = [0];
|
||||
EMPTY.as_ptr()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for BasicString {
|
||||
fn default() -> Self {
|
||||
Self(core::ptr::null_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BasicString {
|
||||
fn drop(&mut self) {
|
||||
if !self.0.is_null() {
|
||||
unsafe { SysFreeString(self.0) }
|
||||
}
|
||||
}
|
||||
}
|
||||
54
third_party/rust/windows-result/src/com.rs
vendored
Normal file
54
third_party/rust/windows-result/src/com.rs
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
use super::*;
|
||||
|
||||
#[doc(hidden)]
|
||||
#[macro_export]
|
||||
macro_rules! com_call {
|
||||
($vtbl:ty, $this:ident.$method:ident($($args:tt)*)) => {
|
||||
((&**($this.as_raw() as *mut *mut $vtbl)).$method)($this.as_raw(), $($args)*)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
pub struct ComPtr(core::ptr::NonNull<core::ffi::c_void>);
|
||||
|
||||
impl ComPtr {
|
||||
pub fn as_raw(&self) -> *mut core::ffi::c_void {
|
||||
unsafe { core::mem::transmute_copy(self) }
|
||||
}
|
||||
|
||||
pub fn cast(&self, iid: &GUID) -> Option<Self> {
|
||||
let mut result = None;
|
||||
unsafe {
|
||||
com_call!(
|
||||
IUnknown_Vtbl,
|
||||
self.QueryInterface(iid, &mut result as *mut _ as _)
|
||||
);
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for ComPtr {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.cast(&IID_IUnknown).unwrap().0 == other.cast(&IID_IUnknown).unwrap().0
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ComPtr {}
|
||||
|
||||
impl Clone for ComPtr {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe {
|
||||
com_call!(IUnknown_Vtbl, self.AddRef());
|
||||
}
|
||||
Self(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ComPtr {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
com_call!(IUnknown_Vtbl, self.Release());
|
||||
}
|
||||
}
|
||||
}
|
||||
396
third_party/rust/windows-result/src/error.rs
vendored
Normal file
396
third_party/rust/windows-result/src/error.rs
vendored
Normal file
@@ -0,0 +1,396 @@
|
||||
use super::*;
|
||||
use core::num::NonZeroI32;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use core::mem::size_of;
|
||||
|
||||
/// An error object consists of both an error code and optional detailed error information for debugging.
|
||||
///
|
||||
/// # Extended error info and the `windows_slim_errors` configuration option
|
||||
///
|
||||
/// `Error` contains an [`HRESULT`] value that describes the error, as well as an optional
|
||||
/// `IErrorInfo` COM object. The `IErrorInfo` object is a COM object that can provide detailed information
|
||||
/// about an error, such as a text string, a `ProgID` of the originator, etc. If the error object
|
||||
/// was originated in an WinRT component, then additional information such as a stack track may be
|
||||
/// captured.
|
||||
///
|
||||
/// However, many systems based on COM do not use `IErrorInfo`. For these systems, the optional error
|
||||
/// info within `Error` has no benefits, but has substantial costs because it increases the size of
|
||||
/// the `Error` object, which also increases the size of `Result<T>`.
|
||||
///
|
||||
/// This error information can be disabled at compile time by setting `RUSTFLAGS=--cfg=windows_slim_errors`.
|
||||
/// This removes the `IErrorInfo` support within the [`Error`] type, which has these benefits:
|
||||
///
|
||||
/// * It reduces the size of [`Error`] to 4 bytes (the size of [`HRESULT`]).
|
||||
///
|
||||
/// * It reduces the size of `Result<(), Error>` to 4 bytes, allowing it to be returned in a single
|
||||
/// machine register.
|
||||
///
|
||||
/// * The `Error` (and `Result<T, Error>`) types no longer have a [`Drop`] impl. This removes the need
|
||||
/// for lifetime checking and running drop code when [`Error`] and [`Result`] go out of scope. This
|
||||
/// significantly reduces code size for codebase that make extensive use of [`Error`].
|
||||
///
|
||||
/// Of course, these benefits come with a cost; you lose extended error information for those
|
||||
/// COM objects that support it.
|
||||
///
|
||||
/// This is controlled by a `--cfg` option rather than a Cargo feature because this compilation
|
||||
/// option sets a policy that applies to an entire graph of crates. Individual crates that take a
|
||||
/// dependency on the `windows-result` crate are not in a good position to decide whether they want
|
||||
/// slim errors or full errors. Cargo features are meant to be additive, but specifying the size
|
||||
/// and contents of `Error` is not a feature so much as a whole-program policy decision.
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// * [`IErrorInfo`](https://learn.microsoft.com/en-us/windows/win32/api/oaidl/nn-oaidl-ierrorinfo)
|
||||
#[derive(Clone)]
|
||||
pub struct Error {
|
||||
/// The `HRESULT` error code, but represented using [`NonZeroI32`]. [`NonZeroI32`] provides
|
||||
/// a "niche" to the Rust compiler, which is a space-saving optimization. This allows the
|
||||
/// compiler to use more compact representation for enum variants (such as [`Result`]) that
|
||||
/// contain instances of [`Error`].
|
||||
code: NonZeroI32,
|
||||
|
||||
/// Contains details about the error, such as error text.
|
||||
info: ErrorInfo,
|
||||
}
|
||||
|
||||
/// We remap S_OK to this error because the S_OK representation (zero) is reserved for niche
|
||||
/// optimizations.
|
||||
const S_EMPTY_ERROR: NonZeroI32 = const_nonzero_i32(u32::from_be_bytes(*b"S_OK") as i32);
|
||||
|
||||
/// Converts an HRESULT into a NonZeroI32. If the input is S_OK (zero), then this is converted to
|
||||
/// S_EMPTY_ERROR. This is necessary because NonZeroI32, as the name implies, cannot represent the
|
||||
/// value zero. So we remap it to a value no one should be using, during storage.
|
||||
const fn const_nonzero_i32(i: i32) -> NonZeroI32 {
|
||||
if let Some(nz) = NonZeroI32::new(i) {
|
||||
nz
|
||||
} else {
|
||||
panic!();
|
||||
}
|
||||
}
|
||||
|
||||
fn nonzero_hresult(hr: HRESULT) -> NonZeroI32 {
|
||||
if let Some(nz) = NonZeroI32::new(hr.0) {
|
||||
nz
|
||||
} else {
|
||||
S_EMPTY_ERROR
|
||||
}
|
||||
}
|
||||
|
||||
impl Error {
|
||||
/// Creates an error object without any failure information.
|
||||
pub const fn empty() -> Self {
|
||||
Self {
|
||||
code: S_EMPTY_ERROR,
|
||||
info: ErrorInfo::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new error object, capturing the stack and other information about the
|
||||
/// point of failure.
|
||||
pub fn new<T: AsRef<str>>(code: HRESULT, message: T) -> Self {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let message: &str = message.as_ref();
|
||||
if message.is_empty() {
|
||||
Self::from_hresult(code)
|
||||
} else {
|
||||
ErrorInfo::originate_error(code, message);
|
||||
code.into()
|
||||
}
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
let _ = message;
|
||||
Self::from_hresult(code)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new error object with an error code, but without additional error information.
|
||||
pub fn from_hresult(code: HRESULT) -> Self {
|
||||
Self {
|
||||
code: nonzero_hresult(code),
|
||||
info: ErrorInfo::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new `Error` from the Win32 error code returned by `GetLastError()`.
|
||||
pub fn from_win32() -> Self {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let error = unsafe { GetLastError() };
|
||||
Self::from_hresult(HRESULT::from_win32(error))
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
/// The error code describing the error.
|
||||
pub const fn code(&self) -> HRESULT {
|
||||
if self.code.get() == S_EMPTY_ERROR.get() {
|
||||
HRESULT(0)
|
||||
} else {
|
||||
HRESULT(self.code.get())
|
||||
}
|
||||
}
|
||||
|
||||
/// The error message describing the error.
|
||||
pub fn message(&self) -> String {
|
||||
if let Some(message) = self.info.message() {
|
||||
return message;
|
||||
}
|
||||
|
||||
// Otherwise fallback to a generic error code description.
|
||||
self.code().message()
|
||||
}
|
||||
|
||||
/// The error object describing the error.
|
||||
#[cfg(windows)]
|
||||
pub fn as_ptr(&self) -> *mut core::ffi::c_void {
|
||||
self.info.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
impl From<Error> for HRESULT {
|
||||
fn from(error: Error) -> Self {
|
||||
let code = error.code();
|
||||
error.info.into_thread();
|
||||
code
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HRESULT> for Error {
|
||||
fn from(code: HRESULT) -> Self {
|
||||
Self {
|
||||
code: nonzero_hresult(code),
|
||||
info: ErrorInfo::from_thread(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<Error> for std::io::Error {
|
||||
fn from(from: Error) -> Self {
|
||||
Self::from_raw_os_error(from.code().0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<std::io::Error> for Error {
|
||||
fn from(from: std::io::Error) -> Self {
|
||||
match from.raw_os_error() {
|
||||
Some(status) => HRESULT::from_win32(status as u32).into(),
|
||||
None => HRESULT(E_UNEXPECTED).into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<alloc::string::FromUtf16Error> for Error {
|
||||
fn from(_: alloc::string::FromUtf16Error) -> Self {
|
||||
Self::from_hresult(HRESULT::from_win32(ERROR_NO_UNICODE_TRANSLATION))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<alloc::string::FromUtf8Error> for Error {
|
||||
fn from(_: alloc::string::FromUtf8Error) -> Self {
|
||||
Self::from_hresult(HRESULT::from_win32(ERROR_NO_UNICODE_TRANSLATION))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<core::num::TryFromIntError> for Error {
|
||||
fn from(_: core::num::TryFromIntError) -> Self {
|
||||
Self::from_hresult(HRESULT::from_win32(ERROR_INVALID_DATA))
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for Error {
|
||||
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
let mut debug = fmt.debug_struct("Error");
|
||||
debug
|
||||
.field("code", &self.code())
|
||||
.field("message", &self.message())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for Error {
|
||||
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
let message = self.message();
|
||||
if message.is_empty() {
|
||||
core::write!(fmt, "{}", self.code())
|
||||
} else {
|
||||
core::write!(fmt, "{} ({})", self.message(), self.code())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::hash::Hash for Error {
|
||||
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
|
||||
self.code.hash(state);
|
||||
// We do not hash the error info.
|
||||
}
|
||||
}
|
||||
|
||||
// Equality tests only the HRESULT, not the error info (if any).
|
||||
impl PartialEq for Error {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.code == other.code
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Error {}
|
||||
|
||||
impl PartialOrd for Error {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for Error {
|
||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
|
||||
self.code.cmp(&other.code)
|
||||
}
|
||||
}
|
||||
|
||||
use error_info::*;
|
||||
|
||||
#[cfg(all(windows, not(windows_slim_errors)))]
|
||||
mod error_info {
|
||||
use super::*;
|
||||
use crate::com::ComPtr;
|
||||
|
||||
/// This type stores error detail, represented by a COM `IErrorInfo` object.
|
||||
///
|
||||
/// # References
|
||||
///
|
||||
/// * [`IErrorInfo`](https://learn.microsoft.com/en-us/windows/win32/api/oaidl/nn-oaidl-ierrorinfo)
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct ErrorInfo {
|
||||
pub(super) ptr: Option<ComPtr>,
|
||||
}
|
||||
|
||||
impl ErrorInfo {
|
||||
pub(crate) const fn empty() -> Self {
|
||||
Self { ptr: None }
|
||||
}
|
||||
|
||||
pub(crate) fn from_thread() -> Self {
|
||||
unsafe {
|
||||
let mut ptr = core::mem::MaybeUninit::zeroed();
|
||||
crate::bindings::GetErrorInfo(0, ptr.as_mut_ptr() as *mut _);
|
||||
Self {
|
||||
ptr: ptr.assume_init(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_thread(self) {
|
||||
if let Some(ptr) = self.ptr {
|
||||
unsafe {
|
||||
crate::bindings::SetErrorInfo(0, ptr.as_raw());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn originate_error(code: HRESULT, message: &str) {
|
||||
let message: Vec<_> = message.encode_utf16().collect();
|
||||
unsafe {
|
||||
RoOriginateErrorW(code.0, message.len() as u32, message.as_ptr());
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn message(&self) -> Option<String> {
|
||||
use crate::bstr::BasicString;
|
||||
|
||||
let ptr = self.ptr.as_ref()?;
|
||||
|
||||
let mut message = BasicString::default();
|
||||
|
||||
// First attempt to retrieve the restricted error information.
|
||||
if let Some(info) = ptr.cast(&IID_IRestrictedErrorInfo) {
|
||||
let mut fallback = BasicString::default();
|
||||
let mut code = 0;
|
||||
|
||||
unsafe {
|
||||
com_call!(
|
||||
IRestrictedErrorInfo_Vtbl,
|
||||
info.GetErrorDetails(
|
||||
&mut fallback as *mut _ as _,
|
||||
&mut code,
|
||||
&mut message as *mut _ as _,
|
||||
&mut BasicString::default() as *mut _ as _
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if message.is_empty() {
|
||||
message = fallback
|
||||
};
|
||||
}
|
||||
|
||||
// Next attempt to retrieve the regular error information.
|
||||
if message.is_empty() {
|
||||
unsafe {
|
||||
com_call!(
|
||||
IErrorInfo_Vtbl,
|
||||
ptr.GetDescription(&mut message as *mut _ as _)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Some(String::from_utf16_lossy(wide_trim_end(message.as_wide())))
|
||||
}
|
||||
|
||||
pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
|
||||
if let Some(info) = self.ptr.as_ref() {
|
||||
info.as_raw()
|
||||
} else {
|
||||
core::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for ErrorInfo {}
|
||||
unsafe impl Sync for ErrorInfo {}
|
||||
}
|
||||
|
||||
#[cfg(not(all(windows, not(windows_slim_errors))))]
|
||||
mod error_info {
|
||||
use super::*;
|
||||
|
||||
// We use this name so that the NatVis <Type> element for ErrorInfo does *not* match this type.
|
||||
// This prevents the NatVis description from failing to load.
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct EmptyErrorInfo;
|
||||
|
||||
pub(crate) use EmptyErrorInfo as ErrorInfo;
|
||||
|
||||
impl EmptyErrorInfo {
|
||||
pub(crate) const fn empty() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
pub(crate) fn from_thread() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
pub(crate) fn into_thread(self) {}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub(crate) fn originate_error(_code: HRESULT, _message: &str) {}
|
||||
|
||||
pub(crate) fn message(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub(crate) fn as_ptr(&self) -> *mut core::ffi::c_void {
|
||||
core::ptr::null_mut()
|
||||
}
|
||||
}
|
||||
}
|
||||
154
third_party/rust/windows-result/src/hresult.rs
vendored
Normal file
154
third_party/rust/windows-result/src/hresult.rs
vendored
Normal file
@@ -0,0 +1,154 @@
|
||||
use super::*;
|
||||
|
||||
/// An error code value returned by most COM functions.
|
||||
#[repr(transparent)]
|
||||
#[derive(Copy, Clone, Default, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[must_use]
|
||||
#[allow(non_camel_case_types)]
|
||||
pub struct HRESULT(pub i32);
|
||||
|
||||
impl HRESULT {
|
||||
/// Returns [`true`] if `self` is a success code.
|
||||
#[inline]
|
||||
pub const fn is_ok(self) -> bool {
|
||||
self.0 >= 0
|
||||
}
|
||||
|
||||
/// Returns [`true`] if `self` is a failure code.
|
||||
#[inline]
|
||||
pub const fn is_err(self) -> bool {
|
||||
!self.is_ok()
|
||||
}
|
||||
|
||||
/// Asserts that `self` is a success code.
|
||||
///
|
||||
/// This will invoke the [`panic!`] macro if `self` is a failure code and display
|
||||
/// the [`HRESULT`] value for diagnostics.
|
||||
#[inline]
|
||||
#[track_caller]
|
||||
pub fn unwrap(self) {
|
||||
assert!(self.is_ok(), "HRESULT 0x{:X}", self.0);
|
||||
}
|
||||
|
||||
/// Converts the [`HRESULT`] to [`Result<()>`][Result<_>].
|
||||
#[inline]
|
||||
pub fn ok(self) -> Result<()> {
|
||||
if self.is_ok() {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(self.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Calls `op` if `self` is a success code, otherwise returns [`HRESULT`]
|
||||
/// converted to [`Result<T>`].
|
||||
#[inline]
|
||||
pub fn map<F, T>(self, op: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce() -> T,
|
||||
{
|
||||
self.ok()?;
|
||||
Ok(op())
|
||||
}
|
||||
|
||||
/// Calls `op` if `self` is a success code, otherwise returns [`HRESULT`]
|
||||
/// converted to [`Result<T>`].
|
||||
#[inline]
|
||||
pub fn and_then<F, T>(self, op: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce() -> Result<T>,
|
||||
{
|
||||
self.ok()?;
|
||||
op()
|
||||
}
|
||||
|
||||
/// The error message describing the error.
|
||||
pub fn message(self) -> String {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let mut message = HeapString::default();
|
||||
let mut code = self.0;
|
||||
let mut module = core::ptr::null_mut();
|
||||
|
||||
let mut flags = FORMAT_MESSAGE_ALLOCATE_BUFFER
|
||||
| FORMAT_MESSAGE_FROM_SYSTEM
|
||||
| FORMAT_MESSAGE_IGNORE_INSERTS;
|
||||
|
||||
unsafe {
|
||||
if self.0 & 0x1000_0000 == 0x1000_0000 {
|
||||
code ^= 0x1000_0000;
|
||||
flags |= FORMAT_MESSAGE_FROM_HMODULE;
|
||||
|
||||
module = LoadLibraryExA(
|
||||
b"ntdll.dll\0".as_ptr(),
|
||||
core::ptr::null_mut(),
|
||||
LOAD_LIBRARY_SEARCH_DEFAULT_DIRS,
|
||||
);
|
||||
}
|
||||
|
||||
let size = FormatMessageW(
|
||||
flags,
|
||||
module as _,
|
||||
code as _,
|
||||
0,
|
||||
&mut message.0 as *mut _ as *mut _,
|
||||
0,
|
||||
core::ptr::null(),
|
||||
);
|
||||
|
||||
if !message.0.is_null() && size > 0 {
|
||||
String::from_utf16_lossy(wide_trim_end(core::slice::from_raw_parts(
|
||||
message.0,
|
||||
size as usize,
|
||||
)))
|
||||
} else {
|
||||
String::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
{
|
||||
return alloc::format!("0x{:08x}", self.0 as u32);
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps a Win32 error code to an HRESULT value.
|
||||
pub const fn from_win32(error: u32) -> Self {
|
||||
Self(if error as i32 <= 0 {
|
||||
error
|
||||
} else {
|
||||
(error & 0x0000_FFFF) | (7 << 16) | 0x8000_0000
|
||||
} as i32)
|
||||
}
|
||||
|
||||
/// Maps an NT error code to an HRESULT value.
|
||||
pub const fn from_nt(error: i32) -> Self {
|
||||
Self(if error >= 0 {
|
||||
error
|
||||
} else {
|
||||
error | 0x1000_0000
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> From<Result<T>> for HRESULT {
|
||||
fn from(result: Result<T>) -> Self {
|
||||
if let Err(error) = result {
|
||||
return error.into();
|
||||
}
|
||||
HRESULT(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for HRESULT {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.write_fmt(format_args!("{:#010X}", self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for HRESULT {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
f.write_fmt(format_args!("HRESULT({})", self))
|
||||
}
|
||||
}
|
||||
38
third_party/rust/windows-result/src/lib.rs
vendored
Normal file
38
third_party/rust/windows-result/src/lib.rs
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/*!
|
||||
Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs>
|
||||
*/
|
||||
|
||||
#![cfg_attr(
|
||||
windows_debugger_visualizer,
|
||||
debugger_visualizer(natvis_file = "../.natvis")
|
||||
)]
|
||||
#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
|
||||
#![cfg_attr(not(windows), allow(unused_imports))]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use alloc::{string::String, vec::Vec};
|
||||
|
||||
mod bindings;
|
||||
use bindings::*;
|
||||
|
||||
#[cfg(all(windows, not(windows_slim_errors)))]
|
||||
mod com;
|
||||
|
||||
#[cfg(windows)]
|
||||
mod strings;
|
||||
#[cfg(windows)]
|
||||
use strings::*;
|
||||
|
||||
#[cfg(all(windows, not(windows_slim_errors)))]
|
||||
mod bstr;
|
||||
|
||||
mod error;
|
||||
pub use error::*;
|
||||
|
||||
mod hresult;
|
||||
pub use hresult::HRESULT;
|
||||
|
||||
/// A specialized [`Result`] type that provides Windows error information.
|
||||
pub type Result<T> = core::result::Result<T, Error>;
|
||||
29
third_party/rust/windows-result/src/strings.rs
vendored
Normal file
29
third_party/rust/windows-result/src/strings.rs
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
use super::*;
|
||||
|
||||
pub struct HeapString(pub *mut u16);
|
||||
|
||||
impl Default for HeapString {
|
||||
fn default() -> Self {
|
||||
Self(core::ptr::null_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for HeapString {
|
||||
fn drop(&mut self) {
|
||||
if !self.0.is_null() {
|
||||
unsafe {
|
||||
HeapFree(GetProcessHeap(), 0, self.0 as _);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wide_trim_end(mut wide: &[u16]) -> &[u16] {
|
||||
while let Some(last) = wide.last() {
|
||||
match last {
|
||||
32 | 9..=13 => wide = &wide[..wide.len() - 1],
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
wide
|
||||
}
|
||||
1
third_party/rust/windows-strings/.cargo-checksum.json
vendored
Normal file
1
third_party/rust/windows-strings/.cargo-checksum.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"files":{"Cargo.toml":"32a1010e66211d4fb11ce57a26770d00e095287dbd181c4dfb709d0c059dbd19","license-apache-2.0":"c16f8dcf1a368b83be78d826ea23de4079fe1b4469a0ab9ee20563f37ff3d44b","license-mit":"c2cfccb812fe482101a8f04597dfc5a9991a6b2748266c47ac91b6a5aae15383","readme.md":"3e1748347e92c36f13f857141779c447faa7e2cd8e8a0d1f9dfe155467f7637e","src/bindings.rs":"ff9b855659617081e57cb702b830e09e44dfcc4cc1245ef2c9096bae987d12b0","src/bstr.rs":"2fcd125475d865390635c387f0a95508fd0ea8235ed89cb8963a8c85d9a05aaf","src/decode.rs":"cecdb73a3b54fb8f3d24a245dddbe790a5e7889771e5c3301cbc5ac375abc7bd","src/hstring.rs":"563c38bbfd0309d9d1ed46982d47c307adbd4b1996edb416c3c21d758d0588f9","src/hstring_builder.rs":"baec1f7c7a7e765dc7abfbfea2aa640f1d73c0427372439bc7b7ab18de9c4d05","src/hstring_header.rs":"3752d9cdf4b9520d360068c84efc6586e3fd28d048cd554b63dba99a2db62117","src/lib.rs":"1ef152a7c2539a80fdef923285cbe1db1a196f6bb1a0b3492609fce64ba90e81","src/literals.rs":"08a5ff6547a9ce50d27ab910cb9d8f8a3b647a412bf320f49ea4a124265157d2","src/pcstr.rs":"832f18aea1b97eb12ecab7e58a4f5f16a22f118a4d9d66d4bdb84c83c2fd3d58","src/pcwstr.rs":"67f619fe360dbdfede4ddb5502fb0a7ef7bd68c787d873c6cf0634eff2bd5860","src/pstr.rs":"34b4b2035330d192e29914f68a1b9096387562e0bf2e1d4bef2937a9fcce7734","src/pwstr.rs":"d4701cd606421100b896d6b0cc09117df0f2e59f47e95d91eb178dfd431c89fe","src/ref_count.rs":"e1617f090d56948719730c81e34449c3d36f288b86a74182719a291c340f65d6"},"package":"4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"}
|
||||
58
third_party/rust/windows-strings/Cargo.toml
vendored
Normal file
58
third_party/rust/windows-strings/Cargo.toml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies.
|
||||
#
|
||||
# If you are reading this file be aware that the original Cargo.toml
|
||||
# will likely look very different (and much more reasonable).
|
||||
# See Cargo.toml.orig for the original contents.
|
||||
|
||||
[package]
|
||||
edition = "2021"
|
||||
rust-version = "1.60"
|
||||
name = "windows-strings"
|
||||
version = "0.1.0"
|
||||
authors = ["Microsoft"]
|
||||
build = false
|
||||
autobins = false
|
||||
autoexamples = false
|
||||
autotests = false
|
||||
autobenches = false
|
||||
description = "Rust for Windows"
|
||||
readme = "readme.md"
|
||||
categories = ["os::windows-apis"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/microsoft/windows-rs"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
default-target = "x86_64-pc-windows-msvc"
|
||||
targets = []
|
||||
|
||||
[lib]
|
||||
name = "windows_strings"
|
||||
path = "src/lib.rs"
|
||||
|
||||
[dependencies.windows-result]
|
||||
version = "0.2.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.windows-targets]
|
||||
version = "0.52.6"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
|
||||
[lints.rust]
|
||||
missing_docs = "warn"
|
||||
|
||||
[lints.rust.rust_2018_idioms]
|
||||
level = "warn"
|
||||
priority = -1
|
||||
|
||||
[lints.rust.unexpected_cfgs]
|
||||
level = "warn"
|
||||
priority = 0
|
||||
check-cfg = ["cfg(windows_raw_dylib, windows_debugger_visualizer, windows_slim_errors)"]
|
||||
201
third_party/rust/windows-strings/license-apache-2.0
vendored
Normal file
201
third_party/rust/windows-strings/license-apache-2.0
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
21
third_party/rust/windows-strings/license-mit
vendored
Normal file
21
third_party/rust/windows-strings/license-mit
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) Microsoft Corporation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
||||
36
third_party/rust/windows-strings/readme.md
vendored
Normal file
36
third_party/rust/windows-strings/readme.md
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
## Windows string types
|
||||
|
||||
The [windows-strings](https://crates.io/crates/windows-strings) crate provides common Windows string types used by various Windows APIs.
|
||||
|
||||
* [Getting started](https://kennykerr.ca/rust-getting-started/)
|
||||
* [Samples](https://github.com/microsoft/windows-rs/tree/0.58.0/crates/samples)
|
||||
* [Releases](https://github.com/microsoft/windows-rs/releases)
|
||||
|
||||
Start by adding the following to your Cargo.toml file:
|
||||
|
||||
```toml
|
||||
[dependencies.windows-strings]
|
||||
version = "0.1"
|
||||
```
|
||||
|
||||
Use the Windows string types as needed:
|
||||
|
||||
```rust
|
||||
use windows_strings::*;
|
||||
|
||||
const A: PCSTR = s!("ansi");
|
||||
const W: PCWSTR = w!("wide");
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let b = BSTR::from("bstr");
|
||||
let h = HSTRING::from("hstring");
|
||||
|
||||
assert_eq!(b, "bstr");
|
||||
assert_eq!(h, "hstring");
|
||||
|
||||
assert_eq!(unsafe { A.to_string()? }, "ansi");
|
||||
assert_eq!(unsafe { W.to_string()? }, "wide");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
20
third_party/rust/windows-strings/src/bindings.rs
vendored
Normal file
20
third_party/rust/windows-strings/src/bindings.rs
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
#![allow(
|
||||
non_snake_case,
|
||||
non_upper_case_globals,
|
||||
non_camel_case_types,
|
||||
dead_code,
|
||||
clippy::all
|
||||
)]
|
||||
windows_targets::link!("kernel32.dll" "system" fn GetProcessHeap() -> HANDLE);
|
||||
windows_targets::link!("kernel32.dll" "system" fn HeapAlloc(hheap : HANDLE, dwflags : HEAP_FLAGS, dwbytes : usize) -> *mut core::ffi::c_void);
|
||||
windows_targets::link!("kernel32.dll" "system" fn HeapFree(hheap : HANDLE, dwflags : HEAP_FLAGS, lpmem : *const core::ffi::c_void) -> BOOL);
|
||||
windows_targets::link!("oleaut32.dll" "system" fn SysAllocStringLen(strin : PCWSTR, ui : u32) -> BSTR);
|
||||
windows_targets::link!("oleaut32.dll" "system" fn SysFreeString(bstrstring : BSTR));
|
||||
windows_targets::link!("oleaut32.dll" "system" fn SysStringLen(pbstr : BSTR) -> u32);
|
||||
pub type BOOL = i32;
|
||||
pub type BSTR = *const u16;
|
||||
pub const E_OUTOFMEMORY: HRESULT = 0x8007000E_u32 as _;
|
||||
pub type HANDLE = *mut core::ffi::c_void;
|
||||
pub type HEAP_FLAGS = u32;
|
||||
pub type HRESULT = i32;
|
||||
pub type PCWSTR = *const u16;
|
||||
176
third_party/rust/windows-strings/src/bstr.rs
vendored
Normal file
176
third_party/rust/windows-strings/src/bstr.rs
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
use super::*;
|
||||
|
||||
/// A BSTR string ([BSTR](https://learn.microsoft.com/en-us/previous-versions/windows/desktop/automat/string-manipulation-functions))
|
||||
/// is a length-prefixed wide string.
|
||||
#[repr(transparent)]
|
||||
pub struct BSTR(*const u16);
|
||||
|
||||
impl BSTR {
|
||||
/// Create an empty `BSTR`.
|
||||
///
|
||||
/// This function does not allocate memory.
|
||||
pub const fn new() -> Self {
|
||||
Self(core::ptr::null_mut())
|
||||
}
|
||||
|
||||
/// Returns `true` if the string is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// Returns the length of the string.
|
||||
pub fn len(&self) -> usize {
|
||||
if self.0.is_null() {
|
||||
0
|
||||
} else {
|
||||
unsafe { bindings::SysStringLen(self.0) as usize }
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the string as 16-bit wide characters (wchars).
|
||||
pub fn as_wide(&self) -> &[u16] {
|
||||
unsafe { core::slice::from_raw_parts(self.as_ptr(), self.len()) }
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the `BSTR` buffer.
|
||||
pub fn as_ptr(&self) -> *const u16 {
|
||||
if !self.is_empty() {
|
||||
self.0
|
||||
} else {
|
||||
const EMPTY: [u16; 1] = [0];
|
||||
EMPTY.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a `BSTR` from a slice of 16 bit characters (wchars).
|
||||
pub fn from_wide(value: &[u16]) -> Result<Self> {
|
||||
if value.is_empty() {
|
||||
return Ok(Self::new());
|
||||
}
|
||||
|
||||
let result = unsafe {
|
||||
Self(bindings::SysAllocStringLen(
|
||||
value.as_ptr(),
|
||||
value.len().try_into()?,
|
||||
))
|
||||
};
|
||||
|
||||
if result.is_empty() {
|
||||
Err(Error::from_hresult(HRESULT(bindings::E_OUTOFMEMORY)))
|
||||
} else {
|
||||
Ok(result)
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn from_raw(raw: *const u16) -> Self {
|
||||
Self(raw)
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
#[doc(hidden)]
|
||||
pub fn into_raw(self) -> *const u16 {
|
||||
unsafe { core::mem::transmute(self) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for BSTR {
|
||||
fn clone(&self) -> Self {
|
||||
Self::from_wide(self.as_wide()).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for BSTR {
|
||||
fn from(value: &str) -> Self {
|
||||
let value: alloc::vec::Vec<u16> = value.encode_utf16().collect();
|
||||
Self::from_wide(&value).unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for BSTR {
|
||||
fn from(value: String) -> Self {
|
||||
value.as_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&String> for BSTR {
|
||||
fn from(value: &String) -> Self {
|
||||
value.as_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a BSTR> for String {
|
||||
type Error = alloc::string::FromUtf16Error;
|
||||
|
||||
fn try_from(value: &BSTR) -> core::result::Result<Self, Self::Error> {
|
||||
String::from_utf16(value.as_wide())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<BSTR> for String {
|
||||
type Error = alloc::string::FromUtf16Error;
|
||||
|
||||
fn try_from(value: BSTR) -> core::result::Result<Self, Self::Error> {
|
||||
String::try_from(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for BSTR {
|
||||
fn default() -> Self {
|
||||
Self(core::ptr::null_mut())
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Display for BSTR {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
core::write!(
|
||||
f,
|
||||
"{}",
|
||||
Decode(|| core::char::decode_utf16(self.as_wide().iter().cloned()))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for BSTR {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
core::write!(f, "{}", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for BSTR {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.as_wide() == other.as_wide()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for BSTR {}
|
||||
|
||||
impl PartialEq<BSTR> for &str {
|
||||
fn eq(&self, other: &BSTR) -> bool {
|
||||
other == self
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<BSTR> for String {
|
||||
fn eq(&self, other: &BSTR) -> bool {
|
||||
other == self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsRef<str> + ?Sized> PartialEq<T> for BSTR {
|
||||
fn eq(&self, other: &T) -> bool {
|
||||
self.as_wide()
|
||||
.iter()
|
||||
.copied()
|
||||
.eq(other.as_ref().encode_utf16())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for BSTR {
|
||||
fn drop(&mut self) {
|
||||
if !self.0.is_null() {
|
||||
unsafe { bindings::SysFreeString(self.0) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +1,28 @@
|
||||
mod bstr;
|
||||
mod hstring;
|
||||
mod literals;
|
||||
mod pcstr;
|
||||
mod pcwstr;
|
||||
mod pstr;
|
||||
mod pwstr;
|
||||
|
||||
pub use bstr::*;
|
||||
pub use hstring::*;
|
||||
#[doc(hidden)]
|
||||
pub use literals::*;
|
||||
pub use pcstr::*;
|
||||
pub use pcwstr::*;
|
||||
pub use pstr::*;
|
||||
pub use pwstr::*;
|
||||
|
||||
use super::*;
|
||||
|
||||
extern "C" {
|
||||
#[doc(hidden)]
|
||||
pub fn strlen(s: PCSTR) -> usize;
|
||||
#[doc(hidden)]
|
||||
pub fn wcslen(s: PCWSTR) -> usize;
|
||||
}
|
||||
|
||||
/// An internal helper for decoding an iterator of chars and displaying them
|
||||
#[doc(hidden)]
|
||||
pub struct Decode<F>(pub F);
|
||||
|
||||
impl<F, R, E> std::fmt::Display for Decode<F>
|
||||
impl<F, R, E> core::fmt::Display for Decode<F>
|
||||
where
|
||||
F: Clone + FnOnce() -> R,
|
||||
R: IntoIterator<Item = std::result::Result<char, E>>,
|
||||
R: IntoIterator<Item = core::result::Result<char, E>>,
|
||||
{
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
use std::fmt::Write;
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
use core::fmt::Write;
|
||||
let iter = self.0.clone();
|
||||
for c in iter().into_iter() {
|
||||
f.write_char(c.unwrap_or(std::char::REPLACEMENT_CHARACTER))?
|
||||
f.write_char(c.unwrap_or(core::char::REPLACEMENT_CHARACTER))?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Mirror of `std::char::decode_utf16` for utf-8.
|
||||
fn decode_utf8(mut buffer: &[u8]) -> impl Iterator<Item = std::result::Result<char, std::str::Utf8Error>> + '_ {
|
||||
pub fn decode_utf8(
|
||||
mut buffer: &[u8],
|
||||
) -> impl Iterator<Item = core::result::Result<char, core::str::Utf8Error>> + '_ {
|
||||
let mut current = "".chars();
|
||||
let mut previous_error = None;
|
||||
std::iter::from_fn(move || {
|
||||
core::iter::from_fn(move || {
|
||||
loop {
|
||||
match (current.next(), previous_error) {
|
||||
(Some(c), _) => return Some(Ok(c)),
|
||||
@@ -59,7 +34,7 @@ fn decode_utf8(mut buffer: &[u8]) -> impl Iterator<Item = std::result::Result<ch
|
||||
// We're completely done
|
||||
(None, None) if buffer.is_empty() => return None,
|
||||
(None, None) => {
|
||||
match std::str::from_utf8(buffer) {
|
||||
match core::str::from_utf8(buffer) {
|
||||
Ok(s) => {
|
||||
current = s.chars();
|
||||
buffer = &[];
|
||||
@@ -72,7 +47,7 @@ fn decode_utf8(mut buffer: &[u8]) -> impl Iterator<Item = std::result::Result<ch
|
||||
|
||||
// Set the current iterator to the valid section and indicate previous error
|
||||
// SAFETY: `valid` is known to be valid utf-8 from error
|
||||
current = unsafe { std::str::from_utf8_unchecked(valid) }.chars();
|
||||
current = unsafe { core::str::from_utf8_unchecked(valid) }.chars();
|
||||
previous_error = Some(e);
|
||||
}
|
||||
}
|
||||
404
third_party/rust/windows-strings/src/hstring.rs
vendored
Normal file
404
third_party/rust/windows-strings/src/hstring.rs
vendored
Normal file
@@ -0,0 +1,404 @@
|
||||
use super::*;
|
||||
|
||||
/// An ([HSTRING](https://docs.microsoft.com/en-us/windows/win32/winrt/hstring))
|
||||
/// is a reference-counted and immutable UTF-16 string type.
|
||||
#[repr(transparent)]
|
||||
pub struct HSTRING(pub(crate) *mut HStringHeader);
|
||||
|
||||
impl HSTRING {
|
||||
/// Create an empty `HSTRING`.
|
||||
///
|
||||
/// This function does not allocate memory.
|
||||
pub const fn new() -> Self {
|
||||
Self(core::ptr::null_mut())
|
||||
}
|
||||
|
||||
/// Returns `true` if the string is empty.
|
||||
pub fn is_empty(&self) -> bool {
|
||||
// An empty HSTRING is represented by a null pointer.
|
||||
self.0.is_null()
|
||||
}
|
||||
|
||||
/// Returns the length of the string. The length is measured in `u16`s (UTF-16 code units), not including the terminating null character.
|
||||
pub fn len(&self) -> usize {
|
||||
if let Some(header) = self.as_header() {
|
||||
header.len as usize
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the string as 16-bit wide characters (wchars).
|
||||
pub fn as_wide(&self) -> &[u16] {
|
||||
unsafe { core::slice::from_raw_parts(self.as_ptr(), self.len()) }
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the `HSTRING` buffer.
|
||||
pub fn as_ptr(&self) -> *const u16 {
|
||||
if let Some(header) = self.as_header() {
|
||||
header.data
|
||||
} else {
|
||||
const EMPTY: [u16; 1] = [0];
|
||||
EMPTY.as_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a `HSTRING` from a slice of 16 bit characters (wchars).
|
||||
pub fn from_wide(value: &[u16]) -> Result<Self> {
|
||||
unsafe { Self::from_wide_iter(value.iter().copied(), value.len()) }
|
||||
}
|
||||
|
||||
/// Get the contents of this `HSTRING` as a String lossily.
|
||||
pub fn to_string_lossy(&self) -> String {
|
||||
String::from_utf16_lossy(self.as_wide())
|
||||
}
|
||||
|
||||
/// Get the contents of this `HSTRING` as a OsString.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn to_os_string(&self) -> std::ffi::OsString {
|
||||
std::os::windows::ffi::OsStringExt::from_wide(self.as_wide())
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// len must not be less than the number of items in the iterator.
|
||||
unsafe fn from_wide_iter<I: Iterator<Item = u16>>(iter: I, len: usize) -> Result<Self> {
|
||||
if len == 0 {
|
||||
return Ok(Self::new());
|
||||
}
|
||||
|
||||
let ptr = HStringHeader::alloc(len.try_into()?)?;
|
||||
|
||||
// Place each utf-16 character into the buffer and
|
||||
// increase len as we go along.
|
||||
for (index, wide) in iter.enumerate() {
|
||||
debug_assert!(index < len);
|
||||
|
||||
(*ptr).data.add(index).write(wide);
|
||||
(*ptr).len = index as u32 + 1;
|
||||
}
|
||||
|
||||
// Write a 0 byte to the end of the buffer.
|
||||
(*ptr).data.offset((*ptr).len as isize).write(0);
|
||||
Ok(Self(ptr))
|
||||
}
|
||||
|
||||
fn as_header(&self) -> Option<&HStringHeader> {
|
||||
unsafe { self.0.as_ref() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for HSTRING {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for HSTRING {
|
||||
fn clone(&self) -> Self {
|
||||
if let Some(header) = self.as_header() {
|
||||
Self(header.duplicate().unwrap())
|
||||
} else {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for HSTRING {
|
||||
fn drop(&mut self) {
|
||||
if let Some(header) = self.as_header() {
|
||||
// HSTRING_REFERENCE_FLAG indicates a string backed by static or stack memory that is
|
||||
// thus not reference-counted and does not need to be freed.
|
||||
unsafe {
|
||||
if header.flags & HSTRING_REFERENCE_FLAG == 0 && header.count.release() == 0 {
|
||||
HStringHeader::free(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Send for HSTRING {}
|
||||
unsafe impl Sync for HSTRING {}
|
||||
|
||||
impl core::fmt::Display for HSTRING {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
Decode(|| core::char::decode_utf16(self.as_wide().iter().cloned()))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::fmt::Debug for HSTRING {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "\"{}\"", self)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for HSTRING {
|
||||
fn from(value: &str) -> Self {
|
||||
unsafe { Self::from_wide_iter(value.encode_utf16(), value.len()).unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for HSTRING {
|
||||
fn from(value: String) -> Self {
|
||||
value.as_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&String> for HSTRING {
|
||||
fn from(value: &String) -> Self {
|
||||
value.as_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<&std::path::Path> for HSTRING {
|
||||
fn from(value: &std::path::Path) -> Self {
|
||||
value.as_os_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<&std::ffi::OsStr> for HSTRING {
|
||||
fn from(value: &std::ffi::OsStr) -> Self {
|
||||
unsafe {
|
||||
Self::from_wide_iter(
|
||||
std::os::windows::ffi::OsStrExt::encode_wide(value),
|
||||
value.len(),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<std::ffi::OsString> for HSTRING {
|
||||
fn from(value: std::ffi::OsString) -> Self {
|
||||
value.as_os_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<&std::ffi::OsString> for HSTRING {
|
||||
fn from(value: &std::ffi::OsString) -> Self {
|
||||
value.as_os_str().into()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for HSTRING {}
|
||||
|
||||
impl Ord for HSTRING {
|
||||
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
|
||||
self.as_wide().cmp(other.as_wide())
|
||||
}
|
||||
}
|
||||
|
||||
impl core::hash::Hash for HSTRING {
|
||||
fn hash<H: core::hash::Hasher>(&self, hasher: &mut H) {
|
||||
self.as_wide().hash(hasher)
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for HSTRING {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for HSTRING {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
*self.as_wide() == *other.as_wide()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<String> for HSTRING {
|
||||
fn eq(&self, other: &String) -> bool {
|
||||
*self == **other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<String> for &HSTRING {
|
||||
fn eq(&self, other: &String) -> bool {
|
||||
**self == **other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&String> for HSTRING {
|
||||
fn eq(&self, other: &&String) -> bool {
|
||||
*self == ***other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for HSTRING {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
self.as_wide().iter().copied().eq(other.encode_utf16())
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<str> for &HSTRING {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&str> for HSTRING {
|
||||
fn eq(&self, other: &&str) -> bool {
|
||||
*self == **other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<HSTRING> for str {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == *self
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<HSTRING> for &str {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == **self
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&HSTRING> for str {
|
||||
fn eq(&self, other: &&HSTRING) -> bool {
|
||||
**other == *self
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<HSTRING> for String {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == **self
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<HSTRING> for &String {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == ***self
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<&HSTRING> for String {
|
||||
fn eq(&self, other: &&HSTRING) -> bool {
|
||||
**other == **self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl PartialEq<std::ffi::OsString> for HSTRING {
|
||||
fn eq(&self, other: &std::ffi::OsString) -> bool {
|
||||
*self == **other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl PartialEq<std::ffi::OsString> for &HSTRING {
|
||||
fn eq(&self, other: &std::ffi::OsString) -> bool {
|
||||
**self == **other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl PartialEq<&std::ffi::OsString> for HSTRING {
|
||||
fn eq(&self, other: &&std::ffi::OsString) -> bool {
|
||||
*self == ***other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl PartialEq<std::ffi::OsStr> for HSTRING {
|
||||
fn eq(&self, other: &std::ffi::OsStr) -> bool {
|
||||
self.as_wide()
|
||||
.iter()
|
||||
.copied()
|
||||
.eq(std::os::windows::ffi::OsStrExt::encode_wide(other))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl PartialEq<std::ffi::OsStr> for &HSTRING {
|
||||
fn eq(&self, other: &std::ffi::OsStr) -> bool {
|
||||
**self == *other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl PartialEq<&std::ffi::OsStr> for HSTRING {
|
||||
fn eq(&self, other: &&std::ffi::OsStr) -> bool {
|
||||
*self == **other
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl PartialEq<HSTRING> for std::ffi::OsStr {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == *self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl PartialEq<HSTRING> for &std::ffi::OsStr {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == **self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl PartialEq<&HSTRING> for std::ffi::OsStr {
|
||||
fn eq(&self, other: &&HSTRING) -> bool {
|
||||
**other == *self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl PartialEq<HSTRING> for std::ffi::OsString {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == **self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl PartialEq<HSTRING> for &std::ffi::OsString {
|
||||
fn eq(&self, other: &HSTRING) -> bool {
|
||||
*other == ***self
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl PartialEq<&HSTRING> for std::ffi::OsString {
|
||||
fn eq(&self, other: &&HSTRING) -> bool {
|
||||
**other == **self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a HSTRING> for String {
|
||||
type Error = alloc::string::FromUtf16Error;
|
||||
|
||||
fn try_from(hstring: &HSTRING) -> core::result::Result<Self, Self::Error> {
|
||||
String::from_utf16(hstring.as_wide())
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<HSTRING> for String {
|
||||
type Error = alloc::string::FromUtf16Error;
|
||||
|
||||
fn try_from(hstring: HSTRING) -> core::result::Result<Self, Self::Error> {
|
||||
String::try_from(&hstring)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl<'a> From<&'a HSTRING> for std::ffi::OsString {
|
||||
fn from(hstring: &HSTRING) -> Self {
|
||||
hstring.to_os_string()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl From<HSTRING> for std::ffi::OsString {
|
||||
fn from(hstring: HSTRING) -> Self {
|
||||
Self::from(&hstring)
|
||||
}
|
||||
}
|
||||
89
third_party/rust/windows-strings/src/hstring_builder.rs
vendored
Normal file
89
third_party/rust/windows-strings/src/hstring_builder.rs
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
use super::*;
|
||||
|
||||
/// An [HSTRING] builder that supports preallocating the `HSTRING` to avoid extra allocations and copies.
|
||||
///
|
||||
/// This is similar to the `WindowsPreallocateStringBuffer` function but implemented directly in Rust for efficiency.
|
||||
/// It is implemented as a separate type since [HSTRING] values are immutable.
|
||||
pub struct HStringBuilder(*mut HStringHeader);
|
||||
|
||||
impl HStringBuilder {
|
||||
/// Creates a preallocated `HSTRING` value.
|
||||
pub fn new(len: usize) -> Result<Self> {
|
||||
let header = HStringHeader::alloc(len.try_into()?)?;
|
||||
|
||||
if len > 0 {
|
||||
unsafe { core::ptr::write_bytes((*header).data, 0, len) };
|
||||
}
|
||||
|
||||
Ok(Self(header))
|
||||
}
|
||||
|
||||
/// Shortens the string by removing any trailing 0 characters.
|
||||
pub fn trim_end(&mut self) {
|
||||
if let Some(header) = self.as_header_mut() {
|
||||
while header.len > 0
|
||||
&& unsafe { header.data.offset(header.len as isize - 1).read() == 0 }
|
||||
{
|
||||
header.len -= 1;
|
||||
}
|
||||
|
||||
if header.len == 0 {
|
||||
unsafe {
|
||||
HStringHeader::free(self.0);
|
||||
}
|
||||
self.0 = core::ptr::null_mut();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn as_header(&self) -> Option<&HStringHeader> {
|
||||
unsafe { self.0.as_ref() }
|
||||
}
|
||||
|
||||
fn as_header_mut(&mut self) -> Option<&mut HStringHeader> {
|
||||
unsafe { self.0.as_mut() }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HStringBuilder> for HSTRING {
|
||||
fn from(value: HStringBuilder) -> Self {
|
||||
if let Some(header) = value.as_header() {
|
||||
unsafe { header.data.offset(header.len as isize).write(0) };
|
||||
let result = Self(value.0);
|
||||
core::mem::forget(value);
|
||||
result
|
||||
} else {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::Deref for HStringBuilder {
|
||||
type Target = [u16];
|
||||
|
||||
fn deref(&self) -> &[u16] {
|
||||
if let Some(header) = self.as_header() {
|
||||
unsafe { core::slice::from_raw_parts(header.data, header.len as usize) }
|
||||
} else {
|
||||
&[]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::DerefMut for HStringBuilder {
|
||||
fn deref_mut(&mut self) -> &mut [u16] {
|
||||
if let Some(header) = self.as_header() {
|
||||
unsafe { core::slice::from_raw_parts_mut(header.data, header.len as usize) }
|
||||
} else {
|
||||
&mut []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for HStringBuilder {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
HStringHeader::free(self.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
68
third_party/rust/windows-strings/src/hstring_header.rs
vendored
Normal file
68
third_party/rust/windows-strings/src/hstring_header.rs
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
use super::*;
|
||||
|
||||
pub const HSTRING_REFERENCE_FLAG: u32 = 1;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct HStringHeader {
|
||||
pub flags: u32,
|
||||
pub len: u32,
|
||||
pub _0: u32,
|
||||
pub _1: u32,
|
||||
pub data: *mut u16,
|
||||
pub count: RefCount,
|
||||
pub buffer_start: u16,
|
||||
}
|
||||
|
||||
impl HStringHeader {
|
||||
pub fn alloc(len: u32) -> Result<*mut Self> {
|
||||
if len == 0 {
|
||||
return Ok(core::ptr::null_mut());
|
||||
}
|
||||
|
||||
// Allocate enough space for header and two bytes per character.
|
||||
// The space for the terminating null character is already accounted for inside of `HStringHeader`.
|
||||
let bytes = core::mem::size_of::<Self>() + 2 * len as usize;
|
||||
|
||||
let header =
|
||||
unsafe { bindings::HeapAlloc(bindings::GetProcessHeap(), 0, bytes) } as *mut Self;
|
||||
|
||||
if header.is_null() {
|
||||
return Err(Error::from_hresult(HRESULT(bindings::E_OUTOFMEMORY)));
|
||||
}
|
||||
|
||||
unsafe {
|
||||
// Use `ptr::write` (since `header` is unintialized). `HStringHeader` is safe to be all zeros.
|
||||
header.write(core::mem::MaybeUninit::<Self>::zeroed().assume_init());
|
||||
(*header).len = len;
|
||||
(*header).count = RefCount::new(1);
|
||||
(*header).data = &mut (*header).buffer_start;
|
||||
}
|
||||
|
||||
Ok(header)
|
||||
}
|
||||
|
||||
pub unsafe fn free(header: *mut Self) {
|
||||
if header.is_null() {
|
||||
return;
|
||||
}
|
||||
|
||||
bindings::HeapFree(bindings::GetProcessHeap(), 0, header as *mut _);
|
||||
}
|
||||
|
||||
pub fn duplicate(&self) -> Result<*mut Self> {
|
||||
if self.flags & HSTRING_REFERENCE_FLAG == 0 {
|
||||
// If this is not a "fast pass" string then simply increment the reference count.
|
||||
self.count.add_ref();
|
||||
Ok(self as *const Self as *mut Self)
|
||||
} else {
|
||||
// Otherwise, allocate a new string and copy the value into the new string.
|
||||
let copy = Self::alloc(self.len)?;
|
||||
// SAFETY: since we are duplicating the string it is safe to copy all data from self to the initialized `copy`.
|
||||
// We copy `len + 1` characters since `len` does not account for the terminating null character.
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(self.data, (*copy).data, self.len as usize + 1);
|
||||
}
|
||||
Ok(copy)
|
||||
}
|
||||
}
|
||||
}
|
||||
56
third_party/rust/windows-strings/src/lib.rs
vendored
Normal file
56
third_party/rust/windows-strings/src/lib.rs
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/*!
|
||||
Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs>
|
||||
*/
|
||||
|
||||
#![cfg(windows)]
|
||||
#![allow(non_snake_case)]
|
||||
#![cfg_attr(
|
||||
windows_debugger_visualizer,
|
||||
debugger_visualizer(natvis_file = "../.natvis")
|
||||
)]
|
||||
#![cfg_attr(all(not(feature = "std")), no_std)]
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::string::String;
|
||||
|
||||
pub use windows_result::Result;
|
||||
use windows_result::*;
|
||||
|
||||
mod bstr;
|
||||
pub use bstr::*;
|
||||
|
||||
mod hstring;
|
||||
pub use hstring::*;
|
||||
|
||||
mod hstring_builder;
|
||||
pub use hstring_builder::*;
|
||||
|
||||
mod hstring_header;
|
||||
use hstring_header::*;
|
||||
|
||||
mod bindings;
|
||||
|
||||
mod decode;
|
||||
use decode::*;
|
||||
|
||||
mod ref_count;
|
||||
use ref_count::*;
|
||||
|
||||
mod literals;
|
||||
pub use literals::*;
|
||||
|
||||
mod pcstr;
|
||||
pub use pcstr::*;
|
||||
|
||||
mod pcwstr;
|
||||
pub use pcwstr::*;
|
||||
|
||||
mod pstr;
|
||||
pub use pstr::*;
|
||||
|
||||
mod pwstr;
|
||||
pub use pwstr::*;
|
||||
|
||||
extern "C" {
|
||||
fn strlen(s: PCSTR) -> usize;
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
#[macro_export]
|
||||
macro_rules! s {
|
||||
($s:literal) => {
|
||||
$crate::PCSTR::from_raw(::std::concat!($s, '\0').as_ptr())
|
||||
$crate::PCSTR::from_raw(::core::concat!($s, '\0').as_ptr())
|
||||
};
|
||||
}
|
||||
|
||||
@@ -41,16 +41,26 @@ macro_rules! h {
|
||||
($s:literal) => {{
|
||||
const INPUT: &[u8] = $s.as_bytes();
|
||||
const OUTPUT_LEN: usize = $crate::utf16_len(INPUT) + 1;
|
||||
#[allow(clippy::declare_interior_mutable_const)]
|
||||
const RESULT: $crate::HSTRING = {
|
||||
if OUTPUT_LEN == 1 {
|
||||
unsafe { ::std::mem::transmute(::std::ptr::null::<u16>()) }
|
||||
} else {
|
||||
const OUTPUT: $crate::PCWSTR = $crate::w!($s);
|
||||
const HEADER: $crate::HSTRING_HEADER = $crate::HSTRING_HEADER { flags: 0x11, len: (OUTPUT_LEN - 1) as u32, padding1: 0, padding2: 0, ptr: OUTPUT.as_ptr() };
|
||||
const HEADER: $crate::HSTRING_HEADER = $crate::HSTRING_HEADER {
|
||||
flags: 0x11,
|
||||
len: (OUTPUT_LEN - 1) as u32,
|
||||
padding1: 0,
|
||||
padding2: 0,
|
||||
ptr: OUTPUT.as_ptr(),
|
||||
};
|
||||
// SAFETY: an `HSTRING` is exactly equivalent to a pointer to an `HSTRING_HEADER`
|
||||
unsafe { ::std::mem::transmute::<&$crate::HSTRING_HEADER, $crate::HSTRING>(&HEADER) }
|
||||
unsafe {
|
||||
::std::mem::transmute::<&$crate::HSTRING_HEADER, $crate::HSTRING>(&HEADER)
|
||||
}
|
||||
}
|
||||
};
|
||||
#[allow(clippy::borrow_interior_mutable_const)]
|
||||
&RESULT
|
||||
}};
|
||||
}
|
||||
@@ -110,7 +120,8 @@ pub const fn decode_utf8_char(bytes: &[u8], mut pos: usize) -> Option<(u32, usiz
|
||||
if (ch2 & 0xc0) != 0x80 || (ch3 & 0xc0) != 0x80 || (ch4 & 0xc0) != 0x80 {
|
||||
return None;
|
||||
}
|
||||
let result = ((ch & 0x07) << 18) | ((ch2 & 0x3f) << 12) | ((ch3 & 0x3f) << 6) | (ch4 & 0x3f);
|
||||
let result =
|
||||
((ch & 0x07) << 18) | ((ch2 & 0x3f) << 12) | ((ch3 & 0x3f) << 6) | (ch4 & 0x3f);
|
||||
if result <= 0xffff || 0x10ffff < result {
|
||||
return None;
|
||||
}
|
||||
@@ -12,12 +12,12 @@ impl PCSTR {
|
||||
}
|
||||
|
||||
/// Construct a null `PCSTR`
|
||||
pub fn null() -> Self {
|
||||
Self(std::ptr::null())
|
||||
pub const fn null() -> Self {
|
||||
Self(core::ptr::null())
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the `PCSTR`
|
||||
pub fn as_ptr(&self) -> *const u8 {
|
||||
pub const fn as_ptr(&self) -> *const u8 {
|
||||
self.0
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ impl PCSTR {
|
||||
///
|
||||
/// The `PCSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
|
||||
pub unsafe fn as_bytes(&self) -> &[u8] {
|
||||
let len = super::strlen(*self);
|
||||
std::slice::from_raw_parts(self.0, len)
|
||||
let len = strlen(*self);
|
||||
core::slice::from_raw_parts(self.0, len)
|
||||
}
|
||||
|
||||
/// Copy the `PCSTR` into a Rust `String`.
|
||||
@@ -41,7 +41,7 @@ impl PCSTR {
|
||||
/// # Safety
|
||||
///
|
||||
/// See the safety information for `PCSTR::as_bytes`.
|
||||
pub unsafe fn to_string(&self) -> std::result::Result<String, std::string::FromUtf8Error> {
|
||||
pub unsafe fn to_string(&self) -> core::result::Result<String, alloc::string::FromUtf8Error> {
|
||||
String::from_utf8(self.as_bytes().into())
|
||||
}
|
||||
|
||||
@@ -50,24 +50,7 @@ impl PCSTR {
|
||||
/// # Safety
|
||||
///
|
||||
/// See the safety information for `PCSTR::as_bytes`.
|
||||
pub unsafe fn display(&self) -> impl std::fmt::Display + '_ {
|
||||
pub unsafe fn display(&self) -> impl core::fmt::Display + '_ {
|
||||
Decode(move || decode_utf8(self.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeKind for PCSTR {
|
||||
type TypeKind = CopyType;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn can_display() {
|
||||
// 💖 followed by an invalid byte sequence and then an incomplete one
|
||||
let s = [240, 159, 146, 150, 255, 240, 159, 0];
|
||||
let s = PCSTR::from_raw(s.as_ptr());
|
||||
assert_eq!("💖<EFBFBD>", format!("{}", unsafe { s.display() }));
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ impl PCWSTR {
|
||||
|
||||
/// Construct a null `PCWSTR`
|
||||
pub const fn null() -> Self {
|
||||
Self(std::ptr::null())
|
||||
Self(core::ptr::null())
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the `PCWSTR`
|
||||
@@ -26,14 +26,34 @@ impl PCWSTR {
|
||||
self.0.is_null()
|
||||
}
|
||||
|
||||
/// String length without the trailing 0
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `PCWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
|
||||
pub unsafe fn len(&self) -> usize {
|
||||
extern "C" {
|
||||
fn wcslen(s: *const u16) -> usize;
|
||||
}
|
||||
wcslen(self.0)
|
||||
}
|
||||
|
||||
/// Returns `true` if the string length is zero, and `false` otherwise.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `PCWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
|
||||
pub unsafe fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// String data without the trailing 0
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `PCWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
|
||||
pub unsafe fn as_wide(&self) -> &[u16] {
|
||||
let len = super::wcslen(*self);
|
||||
std::slice::from_raw_parts(self.0, len)
|
||||
core::slice::from_raw_parts(self.0, self.len())
|
||||
}
|
||||
|
||||
/// Copy the `PCWSTR` into a Rust `String`.
|
||||
@@ -41,7 +61,7 @@ impl PCWSTR {
|
||||
/// # Safety
|
||||
///
|
||||
/// See the safety information for `PCWSTR::as_wide`.
|
||||
pub unsafe fn to_string(&self) -> std::result::Result<String, std::string::FromUtf16Error> {
|
||||
pub unsafe fn to_string(&self) -> core::result::Result<String, alloc::string::FromUtf16Error> {
|
||||
String::from_utf16(self.as_wide())
|
||||
}
|
||||
|
||||
@@ -59,11 +79,7 @@ impl PCWSTR {
|
||||
/// # Safety
|
||||
///
|
||||
/// See the safety information for `PCWSTR::as_wide`.
|
||||
pub unsafe fn display(&self) -> impl std::fmt::Display + '_ {
|
||||
Decode(move || std::char::decode_utf16(self.as_wide().iter().cloned()))
|
||||
pub unsafe fn display(&self) -> impl core::fmt::Display + '_ {
|
||||
Decode(move || core::char::decode_utf16(self.as_wide().iter().cloned()))
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeKind for PCWSTR {
|
||||
type TypeKind = CopyType;
|
||||
}
|
||||
@@ -12,12 +12,12 @@ impl PSTR {
|
||||
}
|
||||
|
||||
/// Construct a null `PSTR`
|
||||
pub fn null() -> Self {
|
||||
Self(std::ptr::null_mut())
|
||||
pub const fn null() -> Self {
|
||||
Self(core::ptr::null_mut())
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the `PSTR`
|
||||
pub fn as_ptr(&self) -> *mut u8 {
|
||||
pub const fn as_ptr(&self) -> *mut u8 {
|
||||
self.0
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ impl PSTR {
|
||||
///
|
||||
/// The `PSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
|
||||
pub unsafe fn as_bytes(&self) -> &[u8] {
|
||||
let len = super::strlen(PCSTR::from_raw(self.0));
|
||||
std::slice::from_raw_parts(self.0, len)
|
||||
let len = strlen(PCSTR::from_raw(self.0));
|
||||
core::slice::from_raw_parts(self.0, len)
|
||||
}
|
||||
|
||||
/// Copy the `PSTR` into a Rust `String`.
|
||||
@@ -41,7 +41,7 @@ impl PSTR {
|
||||
/// # Safety
|
||||
///
|
||||
/// See the safety information for `PSTR::as_bytes`.
|
||||
pub unsafe fn to_string(&self) -> std::result::Result<String, std::string::FromUtf8Error> {
|
||||
pub unsafe fn to_string(&self) -> core::result::Result<String, alloc::string::FromUtf8Error> {
|
||||
String::from_utf8(self.as_bytes().into())
|
||||
}
|
||||
|
||||
@@ -50,11 +50,7 @@ impl PSTR {
|
||||
/// # Safety
|
||||
///
|
||||
/// See the safety information for `PSTR::as_bytes`.
|
||||
pub unsafe fn display(&self) -> impl std::fmt::Display + '_ {
|
||||
pub unsafe fn display(&self) -> impl core::fmt::Display + '_ {
|
||||
Decode(move || decode_utf8(self.as_bytes()))
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeKind for PSTR {
|
||||
type TypeKind = CopyType;
|
||||
}
|
||||
@@ -12,12 +12,12 @@ impl PWSTR {
|
||||
}
|
||||
|
||||
/// Construct a null `PWSTR`.
|
||||
pub fn null() -> Self {
|
||||
Self(std::ptr::null_mut())
|
||||
pub const fn null() -> Self {
|
||||
Self(core::ptr::null_mut())
|
||||
}
|
||||
|
||||
/// Returns a raw pointer to the `PWSTR`.
|
||||
pub fn as_ptr(&self) -> *mut u16 {
|
||||
pub const fn as_ptr(&self) -> *mut u16 {
|
||||
self.0
|
||||
}
|
||||
|
||||
@@ -26,14 +26,31 @@ impl PWSTR {
|
||||
self.0.is_null()
|
||||
}
|
||||
|
||||
/// String length without the trailing 0
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `PWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
|
||||
pub unsafe fn len(&self) -> usize {
|
||||
PCWSTR(self.0).len()
|
||||
}
|
||||
|
||||
/// Returns `true` if the string length is zero, and `false` otherwise.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `PWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
|
||||
pub unsafe fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
|
||||
/// String data without the trailing 0.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// The `PWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
|
||||
pub unsafe fn as_wide(&self) -> &[u16] {
|
||||
let len = super::wcslen(PCWSTR::from_raw(self.0));
|
||||
std::slice::from_raw_parts(self.0, len)
|
||||
core::slice::from_raw_parts(self.0, self.len())
|
||||
}
|
||||
|
||||
/// Copy the `PWSTR` into a Rust `String`.
|
||||
@@ -41,7 +58,7 @@ impl PWSTR {
|
||||
/// # Safety
|
||||
///
|
||||
/// See the safety information for `PWSTR::as_wide`.
|
||||
pub unsafe fn to_string(&self) -> std::result::Result<String, std::string::FromUtf16Error> {
|
||||
pub unsafe fn to_string(&self) -> core::result::Result<String, alloc::string::FromUtf16Error> {
|
||||
String::from_utf16(self.as_wide())
|
||||
}
|
||||
|
||||
@@ -59,11 +76,7 @@ impl PWSTR {
|
||||
/// # Safety
|
||||
///
|
||||
/// See the safety information for `PWSTR::as_wide`.
|
||||
pub unsafe fn display(&self) -> impl std::fmt::Display + '_ {
|
||||
Decode(move || std::char::decode_utf16(self.as_wide().iter().cloned()))
|
||||
pub unsafe fn display(&self) -> impl core::fmt::Display + '_ {
|
||||
Decode(move || core::char::decode_utf16(self.as_wide().iter().cloned()))
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeKind for PWSTR {
|
||||
type TypeKind = CopyType;
|
||||
}
|
||||
27
third_party/rust/windows-strings/src/ref_count.rs
vendored
Normal file
27
third_party/rust/windows-strings/src/ref_count.rs
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
use core::sync::atomic::{fence, AtomicI32, Ordering};
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Default)]
|
||||
pub struct RefCount(pub(crate) AtomicI32);
|
||||
|
||||
impl RefCount {
|
||||
pub fn new(count: u32) -> Self {
|
||||
Self(AtomicI32::new(count as i32))
|
||||
}
|
||||
|
||||
pub fn add_ref(&self) -> u32 {
|
||||
(self.0.fetch_add(1, Ordering::Relaxed) + 1) as u32
|
||||
}
|
||||
|
||||
pub fn release(&self) -> u32 {
|
||||
let remaining = self.0.fetch_sub(1, Ordering::Release) - 1;
|
||||
|
||||
match remaining.cmp(&0) {
|
||||
core::cmp::Ordering::Equal => fence(Ordering::Acquire),
|
||||
core::cmp::Ordering::Less => panic!("Object has been over-released."),
|
||||
core::cmp::Ordering::Greater => {}
|
||||
}
|
||||
|
||||
remaining as u32
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user