Coder Social home page Coder Social logo

winrt-rust's Introduction

winrt-rust

This project has been superseded by windows-rs, which is maintained by Microsoft. Please visit github.com/microsoft/windows-rs.

This crate provides type and method definitions to use the Windows Runtime (WinRT) APIs from Rust.

Status

This library is still subject to breaking changes, but it is already possible to use all APIs, including asynchronous ones (a completion handler can be passed as a closure). Creating custom WinRT classes using inheritance is not yet supported, so it is currently not possible to create user interfaces using XAML.

Prerequisites

Using this crate requires at least Rust 1.28. Additional nightly features (e.g. using specialization) can be enabled with the nightly Cargo feature.

Design

All definitions are automatically generated from WinMD metadata files. The module structure of the generated code reflects the namespace structure of the original definitions starting at winrt::windows (if the crate has not been renamed on import) for the Windows namespace.

All names have been adjusted to fit the Rust coding style, therefore module names are all in lower case and function names are converted to snake_case.

Since it takes a long time to compile all generated definitions (the generated files amount to more than 15 MB), Cargo features have been introduced that correspond to the WinMD files. For example, to use the definitions from Windows.Devices.winmd, use the feature windows-devices. There is no feature for definitions from Windows.Foundation.winmd, these are always available. Whenever a (method) definition references a type from a different WinMD file, it is also not available until you enable the corresponding features for all required type definitions.

With only the definitions from Windows.Foundation, this crates takes about 10 seconds to compile. With all features enabled (there is a shortcut feature all), compilation can take as long as 5 minutes, so it is highly recommended to enable features only as you need them.

Example

extern crate winrt;

use winrt::*; // import various helper types
use winrt::windows::system::diagnostics::*; // import namespace Windows.System.Diagnostics

fn main() {
    let infos = ProcessDiagnosticInfo::get_for_processes().unwrap().unwrap();
    println!("Currently executed processes ({}):", infos.get_size().unwrap());
    for p in &infos {
        let p = p.unwrap();
        let pid = p.get_process_id().unwrap();
        let exe = p.get_executable_file_name().unwrap();
        println!("[{}] {}", pid, exe);
    }
}

Because this example uses the Windows.System namespace, we have to enable the windows-system feature in Cargo.toml:

[dependencies.winrt]
version = "0.6.0"
features = ["windows-system"]

Running this example program should result in an output similar to the following:

Currently executed processes (132):
[4] System
[392] smss.exe
[520] csrss.exe
[604] wininit.exe
[612] csrss.exe
[708] winlogon.exe
...

WinRT and UWP

The Windows Runtime (WinRT) has been introduced in Windows 8 and provides the foundation for building Windows apps that run on different devices using different programming languages. The Universal Windows Platform (UWP) is an extension of WinRT, introduced in Windows 10, that allows using additional, more platform-specific APIs besides those provided by WinRT (according to MSDN). WinRT is not to be confused with the discontinued flavor of the Windows operating system for ARM devices, Windows RT.

Changelog

Version 0.6.0 was the last release of this project. It has been superseded by winrt-rs.

Version 0.6.0 (2019-06-10)

  • [Breaking] Implicit initialization for the runtime context. RuntimeContext no longer exists and was replaced by init_apartment (but it's usually not necessary to call it).
  • [Breaking] Improved snake case conversion for method names
  • [Breaking] Removed lang-compat feature
  • Use std::ptr::NonNull to enable size optimizaton of Option<ComPtr<...>>
  • Implement Send for HString
  • ⚠️ This will be the last version that uses the Rust 2015 Edition.

Version 0.5.1 (2018-09-10)

  • Regenerated bindings from latest Windows SDK

Version 0.5.0 (2018-03-30)

  • [Breaking] Wrappers are no longer marked as unsafe 🎉
  • [Breaking] Wrappers for methods that could return null will now return Result<Option<ComPtr<...>>> instead of Result<ComPtr<...>>.
  • [Breaking] Various improvements to how iterators are handled

Version 0.4.0 (2017-12-27)

  • [Breaking] Upgrade to winapi 0.3
  • [Breaking] Default constructors are now accessible via RtDefaultConstructible trait
  • [Breaking] Fixed and improved error handling (among other changes, blocking_get() now returns Result)
  • [Breaking] Output array parameters are now passed as mutable slices (&mut [T])
  • Provide access to IMemoryBufferByteAccess
  • Add another example (hexdump)

Version 0.3.0 (2017-07-21)

  • [Breaking] The self parameter for interface calls is now passed as &self instead of &mut self
  • [Breaking] Remove (empty) contract structs from generated code
  • Documentation improvements

Version 0.2.1 (2017-04-01)

  • Add blocking_get() for async operations
  • Add toast notification example

Version 0.2.0 (2017-03-10)

  • Factories and statics now actually work
  • [Breaking] Feature names use dash instead of underscore

Version 0.1.0 (2016-09-28)

  • First release

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

winrt-rust's People

Contributors

agashlin avatar boddlnagg avatar contextfree avatar maulingmonkey avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

winrt-rust's Issues

Get rid of drop flags in wrappers

Both HString and ComPtr<T> should be pointer sized, since they are wrapping a pointer, but actually are bigger because of drop flags. This is a problem for arrays/slices, because an array of HSTRINGs should be transmutable to an array of HStrings, and the same for ComPtr (element-wise conversion would be too expensive). This is why we currently expose raw types for arrays.

One possibility is #[unsafe_no_drop_flag], but this would not work on stable. Waiting for rust-lang/rust#34398 should also resolve the issue.

cannot compile toast_notify.rs

I was trying to build the toast example but all I got was this t-shirt - er, I mean, this error.
Looks like you're relying on code that is not published yet?

error[E0432]: unresolved import `winrt::windows::data::xml::dom::*`
 --> examples\toast_notify.rs:9:5
  |
9 | use winrt::windows::data::xml::dom::*;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Could not find `data` in `windows`

error[E0432]: unresolved import `winrt::windows::ui::notifications::*`
  --> examples\toast_notify.rs:10:5
   |
10 | use winrt::windows::ui::notifications::*;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Could not find `ui` in `windows`

error[E0433]: failed to resolve. Use of undeclared type or module `ToastNotificationManager`
  --> examples\toast_notify.rs:20:25
   |
20 |     let mut toast_xml = ToastNotificationManager::get_template_content(ToastTemplateType_ToastText02).unwrap();
   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use of undeclared type or module `ToastNotificationManager`

error[E0425]: cannot find value `ToastTemplateType_ToastText02` in this scope
  --> examples\toast_notify.rs:20:72
   |
20 |     let mut toast_xml = ToastNotificationManager::get_template_content(ToastTemplateType_ToastText02).unwrap();
   |                                                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope

error[E0412]: cannot find type `IXmlNode` in this scope
  --> examples\toast_notify.rs:25:150
   |
25 |     toast_text_elements.item(0).unwrap().append_child(&*toast_xml.create_text_node(&FastHString::new("Hello from Rust!")).unwrap().query_interface::<IXmlNode>().unwrap()).unwrap();
   |                                                                                                                                                      ^^^^^^^^ not found in this scope

error[E0412]: cannot find type `IXmlNode` in this scope
  --> examples\toast_notify.rs:26:157
   |
26 |     toast_text_elements.item(1).unwrap().append_child(&*toast_xml.create_text_node(&FastHString::new("This is some more text.")).unwrap().query_interface::<IXmlNode>().unwrap()).unwrap();
   |                                                                                                                                                             ^^^^^^^^ not found in this scope

error[E0433]: failed to resolve. Use of undeclared type or module `ToastNotification`
  --> examples\toast_notify.rs:32:17
   |
32 |     let toast = ToastNotification::create_toast_notification(&*toast_xml).unwrap();
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use of undeclared type or module `ToastNotification`

error[E0433]: failed to resolve. Use of undeclared type or module `ToastNotificationManager`
  --> examples\toast_notify.rs:35:5
   |
35 |     ToastNotificationManager::create_toast_notifier_with_id(&FastHString::new("myrustapp.exe")).unwrap().show(&*toast).unwrap();
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use of undeclared type or module `ToastNotificationManager`

error: aborting due to 8 previous errors

error: Could not compile `winrt`.

Some special cases are needed for the snake case conversion

Specifically I have in mind “JavaScript” as in the IsJavaScriptEnabled property of Windows.Web.UI.WebViewControlSettings, which currently becomes is_java_script_enabled but should rather be is_javascript_enabled, that being idiomatic.

I’m then vaguely guessing that there will be other special cases too. If there is already something in place for special-casing things, then this property should be added to it, and if not then such a capability should be added.

Benchmark (and potentially optimize) QueryInterface calls

Repeated calls to QueryInterface with the same parameters are guaranteed to return the same thing. The modern C++ projection uses a new compiler optimization to annotate the function as being pure so the compiler can eliminate such (virtual) calls that would otherwise have a high runtime overhead.

It is also explained here: https://www.youtube.com/watch?v=lm4IwfiJ3EU#t=50m03s

Maybe we can find (or build) a way to have the Rust compiler do a similar thing.

Autogenerate delegate (handler) implementations

The hard part about this is generic parameters: In my current proof-of-concept impl of AsyncOperationCompletedHandler<TResult>, I plug in a dummy type for TResult to get a non-generic constant VTable (because constants can't be generic in Rust – maybe it would be possible somehow with associated consts, but I couldn't get it to work and also we want to be able to build on stable).

This works only as long as the generic parameters only appear indirectly within the signature of Invoke, which is (*mut IAsyncOperation<TResult>, AsyncStatus) -> HRESULT in this case. The binary representation of *mut IAsyncOperation<TResult> is the same no matter what TResult is. However, as soon as generic parameters are used directly, which happens e.g. in EventHandler<T>(object sender, T args), this won't work and we need a truly generic VTable.

One way to solve this would be to dynamically allocate the VTable instead of having a constant pointer. Then it should also be possible to turn the handler function (i.e. the invoke field of AsyncOperationCompletedHandlerImpl etc.) into an unboxed closure. I don't know about performance implications, and maybe there is another (better?) way.

Can we autogenerate a SAFE high-level projection? How good of one?

  • Is COM/WinRT's reference counting enough to satisfy Rust's notion of memory safety? If so, how can we convince the compiler of this?
  • WinRT's "agile objects" and MTA-compatible objects (both declared in metadata) seem like an equivalent to Rust's Send and Share traits - can the projection rely on objects declared with this metadata to follow the rules of these traits or are there gotchas?
  • WinRT unfortunately doesn't have any explicit concept of immutability, which limits the usefulness of an autogenerated safe projection. My only idea here is that property getters might be reasonably assumed to satisfy "external immutability" and therefore be safely usable by read-only references. Can this be relied on in practice?
  • WinRT doesn't support non-nullable references either. Will we have to wrap everything in an option?
  • How damaging would it be to have a generator that relies on metadata "promises" that <100% of APIs keep? Can we whitelist or blacklist APIs from a safe autogen'd projection? How would poorly behaving APIs be discovered, or well behaving APIs be vetted?
  • If we do implement a safe high-level projection, should it + the unsafe low-level one be the only two, or should we provide an unsafe high-level projection as well?

Provide a way to deal with `null` return values

Since we can't be sure whether interface return values are never null, we probably have to check that and return an Option<ComPtr<...>> instead. We should try to make use of the null-pointer optimization here, so there will be no unnecessary overhead.

[Idea] On-demand code generation

I had an idea that might alleviate the pain of this crate's compile times (#26): Once we have a code generator in Rust (#50) – which would probably be quite fast (the current one written in C# is already quite fast) – we could run the code generator via procedural macro and that procedural macro could take use statements of WinRT types/modules as input. We would then generate only those pieces of the APIs that are needed for the used functionality (and required dependencies).

Users of winrt-rust would then usually have one module/file in their project with a content like this:

winrt! {
   use windows::foundation::{Uri, PropertyValue};
   use windows::devices::enumeration::DeviceInformation;
   use windows::devices::midi::*; // `*` could be allowed
}

... and that module becomes the "root" module for their personal stripped-down version of the generated projection sources. Which would probably compile by orders of magnitude faster.

This implies that the projections are always generated with whatever version of the metadata assemblies the user has installed. However, there's even a nice side-effect: We could add another annotation in the macro with which the user specifies the metadata assembly from which the code generator will read all the definitions. So one could integrate custom WinRT types, or request a specific version, etc.

Should running the codegen be part of the build process?

We need to figure out whether running the code generator should be part of building the library. If so, we should have a Cargo build script to run it as part of building winrt-rust.

So far, I'm inclined to say that we should have gen.rs checked into the repository and distribute it that way. This has the following advantages:

  • We can generate it from the most recent version of the winmd files. I think that those are backwards compatible, so you can always compile against the latest version and if you use a feature that is not available on your local OS version, it will fail at runtime. (This can also be considered a disadvantage: you will get compile-time errors when you first run codegen from your local winmds, which is arguably better than runtime errors).
  • You don't need a C# compiler and .NET runtime to build the project (might be good for cross-compilation from Linux if that ever becomes a thing)

UWP UI application in Rust

Is it possible to create a uwp app with a ui with this library? If so can an example for that use case be added? If not what's preventing this: technical issues or something else?

Make sure that you can match on enum values

I'm not sure if the current implementation strategy allows using match for enum values. Should work for the variants with and without associated constants. I'm too lazy to test this right now, so just close this if it already works.

Add Cargo feature flags to select Assemblies

Add a feature flag for each WinRT winmd file, like

"windows.applicationmodel" = []
"windows.data" = []
"windows.devices" = []
"windows.gaming" = []
"windows.globalization" = []
"windows.graphics" = []
"windows.management" = []
"windows.media" = []
"windows.networking" = []
"windows.perception" = []
"windows.security" = []
"windows.services" = []
"windows.storage" = []
"windows.system" = []
"windows.ui" = []
"windows.ui.xaml" = ["windows.ui"]
"windows.web" = []

Then, conditionally compile modules only if the containing assembly is selected and strip out (i.e. conditionally disable) any methods that depend on type definitions from other assemblies.
To keep the right VTables, we need to replace disabled methods with dummy methods, because VTable slots depend entirely on the order of declarations.

Support for array types

Array types in method parameters are currently (hopefully) correct in the raw VTable definitions, but not yet idiomatically represented in the wrapper methods. (Array parameters are taken as raw pointers and just forwarded directly.)

https://msdn.microsoft.com/en-us/library/hh700131.aspx shows how arrays are handled in C++/CX. Also have a look at vccorlib.h (part of Visual Studio installation) for the definitions of Platform::Array, etc.

Reconsider error handling

We currently return Result for every wrapped method, by inspecting the HRESULT that is returned from the wrapped call, which is the channel through which exceptions are returned in WinRT.

However, according to https://blogs.msdn.microsoft.com/oldnewthing/20190228-00/?p=101055 there's guidance that "Application code is not expected to catch exceptions thrown by Windows Runtime objects because they represent unrecoverable errors".

This means that we could also panic! in those cases, which would simplify the API.

However, some API methods don't respect that guidance (according to the same blogpost the reason is that they precede this guidance). New methods are being introduced with explicit error handling, but they do not yet exist everywhere.

Use `-` instead of `_` in feature names

I think the features in Cargo.toml should use dashes instead of underscores to match the style of winapi (v0.3), which also uses - for the seperator in feature names mapping to the structure of header files (see https://github.com/retep998/winapi-rs/blob/dev/Cargo.toml).

This is probably also more consistent with the rest of the crates ecosystem.

I originally chose _ because it is visually more similar to . (both are "at the bottom of the line"), but that's probably not a good reason.

Add statically checked access to other interfaces

Many classes implement other interfaces besides their main interface. For example, Windows.System.LauncherOptions implements ILauncherOptions, but also ILauncherViewOptions, ILauncherOptions2 and ILauncherOptions3. QueryInterface can be used to get implementations of these other interfaces, but can generally query arbitrary interfaces and might fail if the interface is not actually available, therefore it returns Result<>. We should add a way to query those interfaces that are known to be valid (from the metadata), which can then be returned directly.

Maybe this could make use of Rust's conversion traits. Ideally it could work automatically, so that an instance of ComPtr<LauncherOptions>, which allows calls to methods defined on ILauncherOptions through deref, could also allow calls to methods defined on the other interfaces.

Can't import winrt::windows::data or ::ui

rustc 1.18.0 (03fc9d622 2017-06-06)
cargo 0.19.0 (28d1d60d4 2017-05-16)

My Cargo.toml:

[package]
name = "hello_world"
version = "0.0.1"
authors = [ "Adam Baxter <[email protected]>" ]

[dependencies]
winrt = "0.2.1"

[features]
windows-ui = []
windows-data = []

main.rs:

extern crate winrt;
use winrt::*; // import various helper types
use winrt::windows::data::xml::dom::*;
use winrt::windows::ui::notifications::*;

fn main() {
    let rt = RuntimeContext::init();
	println!("Hello, world!");

} 

(to be replaced with a toast notification as soon as I can make it work)

PS C:\git\rust\hello> cargo build --verbose
       Fresh winapi v0.2.8
       Fresh winapi-build v0.1.1
       Fresh ole32-sys v0.2.0
       Fresh runtimeobject-sys v0.2.0
       Fresh oleaut32-sys v0.2.0
       Fresh winrt v0.2.1
   Compiling hello_world v0.0.1 (file:///C:/git/rust/hello)
     Running `rustc --crate-name hello_world src\main.rs --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=1d57d6994d17b2e4 -C extra-filename=-1d57d6994d17b2e4 --out-dir C:\git\rust\hello\target\debug\deps -L dependency=C:\git\rust\hello\target\debug\deps
--extern winrt=C:\git\rust\hello\target\debug\deps\libwinrt-9ac1a1eab3936cb9.rlib`
error[E0432]: unresolved import `winrt::windows::data::xml::dom::*`
 --> src\main.rs:3:5
  |
3 | use winrt::windows::data::xml::dom::*;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Could not find `data` in `windows`

error[E0432]: unresolved import `winrt::windows::ui::notifications::*`
 --> src\main.rs:4:5
  |
4 | use winrt::windows::ui::notifications::*;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Could not find `ui` in `windows`

error: aborting due to 2 previous errors

error: Could not compile `hello_world`.

Caused by:
  process didn't exit successfully: `rustc --crate-name hello_world src\main.rs --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=1d57d6994d17b2e4 -C extra-filename=-1d57d6994d17b2e4 --out-dir C:\git\rust\hello\target\debug\deps -L dependency=C:\git\rust\h
ello\target\debug\deps --extern winrt=C:\git\rust\hello\target\debug\deps\libwinrt-9ac1a1eab3936cb9.rlib` (exit code: 101)
PS C:\git\rust\hello>

Use ptr::NonNull in ComPtr

Because our ComPtr<T> can never contain null, it should use ptr::NonNull now that this is stable.
It should also be made repr(transparent) (see #46)

Handle [Flags] enums

Some enums have the [Flags] attribute, e.g. Windows.Storage.StorageOpenOptions (even though I don't understand its purpose in that case ...). We should implement the bitwise operators for them (or maybe use bitflags?).

Online documentation

The AppVeyor build (see #13) can automatically run rustdoc (probably cargo doc --no-deps is best, because we don't want docs for winapi included) and upload the documentation to GitHub pages (gh-pages branch).

`RuntimeContext` should not be `Send` or `Sync`

RuntimeContext is a wrapper around RoInitialize and RoUninitialize, which initialize (and uninitialize) the WinRT runtime per thread.

Calling RoUninitialize from a different thread than RoInitialize is not allowed.

To fix this, we can replace the inner () with PhantomData<*mut ()>, which is also a zero-size type and (by virtue of containing a pointer) is not automatically Send and Sync. In the future (i.e. when more stuff is stablized), we can explicitly do impl !Send for RuntimeContext.

Expose the DualApiPartition attribute

See https://msdn.microsoft.com/de-de/library/windows/desktop/mt695951(v=vs.85).aspx.
Probably the APIs that don't have the DualApiPartition attribute should be disabled by default, and enabled only via a feature flag. Currently they won't be of much use anyway, because I know of no way to create a real UWP app with Rust.

Notet that the attribute seems to be only applied to classes, so it's not clear what to to with the corresponding interfaces. Those that are marked ExclusiveTo should probably be handled in the same way.

RO_INIT_MULTITHREADED doesn’t work for everything

I have not taken the time to grasp the difference between the different RO_INIT_*THREADED values (I have done literally no research, and I won’t have a chance to until next week), but what I observe is that this code:

use winrt::{RtActivatable};
use winrt::windows::web::ui::interop::{WebViewControlProcess, WebViewControlProcessOptions};

let options = WebViewControlProcessOptions::get_activation_factory()
    .activate_instance()
    .query_interface()
    .unwrap();
WebViewControlProcess::create_with_options(&options);

(Ugh, is that activation factory business really how to do it? It took me a while to get that far, but I think it’s about right, which is very icky! But that’s by the bye.)

… failed with code 0x8000001D, which is RO_E_UNSUPPORTED_FROM_MTA, “Activating a single-threaded class from MTA is not supported.”

As soon as I replaced RuntimeContext::init() with RoInitialize(RO_INIT_SINGLETHREADED), it started working fine.

I do not know how all of this works with reference to #60—as I said, I know nothing at present about the different apartment models beyond the names and very vague intuitions. @rbtying, are you perchance an expert?

I know not whether it should switch to single-threaded, or take an argument to choose.

Generator is failing on Windows 10.0.17763

Build 17763 added the method Windows.Web.UI.Interop.WebViewControl.AddInitializeScript which I need, so I tried to run the generator, but it failed:

Unhandled Exception: System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
   at Generator.Generator.GetTypeDefinition(TypeReference t) in ...\winrt-rust\Generator\Generator.cs:line 74
   at Generator.Types.TypeHelpers.GetElementTypeName(Generator gen, ITypeRequestSource source, TypeReference t, TypeUsage usage) in ...\winrt-rust\Generator\Types\TypeHelpers.cs:line 139
   at Generator.Types.TypeHelpers.GetTypeName(Generator gen, ITypeRequestSource source, TypeReference t, TypeUsage usage) in ...\winrt-rust\Generator\Types\TypeHelpers.cs:line 73
   at Generator.Types.TypeHelpers.GetInputTypeName(Generator gen, ITypeRequestSource source, TypeReference t, InputKind kind) in ...\winrt-rust\Generator\Types\TypeHelpers.cs:line 192
   at Generator.Types.MethodDetailsCache.<>c__DisplayClass7_0.<MakeInputParameters>b__0(String name, Tuple`2 t) in ...\winrt-rust\Generator\Types\MethodDef.cs:line 22
   at System.Linq.Enumerable.<ZipIterator>d__61`3.MoveNext()
   at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at Generator.Types.MethodDetailsCache.MakeInputParameters(Generator generator, ITypeRequestSource source) in ...\winrt-rust\Generator\Types\MethodDef.cs:line 22
   at Generator.Types.ClassMethodDef..ctor(MethodDef method, ClassDef containingClass, Boolean isFactory) in ...\winrt-rust\Generator\Types\ClassMethodDef.cs:line 64
   at Generator.Types.ClassDef.CollectDependencies() in ...\winrt-rust\Generator\Types\ClassDef.cs:line 63
   at Generator.Generator.CollectDependencies() in ...\winrt-rust\Generator\Generator.cs:line 92
   at Generator.Program.Main(String[] args) in ...\winrt-rust\Generator\Program.cs:line 19

The missing key, t.FullName, seems to be System.Guid& modopt(System.Runtime.CompilerServices.IsConst). I have investigated no further yet.

Cargo `winrt` crate name already taken

See https://crates.io/crates/winrt. Since that is the crate name that I would have chosen, and the code in that crate is not more than an experiment, and there is no linked repository where further development might happen, maybe it's possible to contact the author to ask whether the crate ownership can be moved? This is possible using cargo owner --add <GitHub Username>.

@Miot: are you still interested in maintaining your crate or would you agree to give ownership to me and/or @contextfree?

Use &self instead of &mut self

Probably the inner mutability within WinRT objects doesn't matter to Rust, and all the autogenerated wrapper methods should just take &self instead of &mut self (and the same for other interface parameters that are not self).

Some links containing useful information

(Maybe this should be put into the Wiki, but it can be moved later.)

Figure out lifetimes for generic parameters

Currently lifetimes of generic parameters are set to 'static in aliases and return types. This requires the "hack" that for interface and class definitions RtInterface::In is set to *mut interface.If possible, *mut pointers should be avoided (the wrappers are currently defined as unsafe, but that could be changed as soon as we are more confident, and *mut pointers probably shouldn't be part of safe signatures). The problem is that generic types can either be value types or references, but only references have a lifetime. Ideally that lifetime should be tied to the lifetime of a given reference to the outermost type.

As a example, let's take DeviceInformationCollection. It is currently defined as a newtype wrapper around IVectorView<&'static DeviceInformation>. Even if it was defined with a lifetime parameter 'a wrapping IVectorView<&'a DeviceInformation> instead, that would not be enough, because we would need any reference of type &'x DeviceInformationCollection to refer to &'x IVectorView<&'x DeviceInformation>, i.e. the lifetime of the reference itself should be the same as the lifetimes of the generic parameters, with the desired result that whenever the generic parameter T appears in methods of IVectorView<T> and is instantiated with a reference type, its lifetime is always linked to the lifetime of the &mut self reference.

In other words, when a generic interface has a method
foo(&mut self, data: T::In)
and T is a reference to an interface type ISomething, we want the method to act as if it was defined as
foo(&mut self, data: &ISomething)
which (due to lifetime elision) is equivalent to
foo(&'a mut self, data: &'a ISomething).

But since T can never refer to the 'a of &'a mut self, we need to find a different solution.
We also can't trivially do something like foo(&mut self, data: &T::In), because T (and therefore also T::In) might be a value type that needs to be passed by value.

Maybe one could add some lifetime bounds on T or T::In, e.g. foo<'a>(&'a mut self, data: T::In) where T: 'a, I have not tested this yet.

Why does AsyncOperationCompletedHandler::new require Send?

AsyncOperationCompletedHandler::new::<_F_> includes Send in its bounds for _F_, and I’m not sure why it does, or whether it should in fact.

For “I’m not sure why”: AsyncOperationCompletedHandler is explicitly marked !Send and !Sync, so why would its callback need to be Send?

For “I’m not sure whether it should”: my concrete use case is WebViewControl, which requires a single-threaded apartment anyway. Given that WebViewControl instantiation is done asynchronously and you can’t use blocking_get() for reasons I won’t contemplate, the Send bound on the callback is very debilitating; it actively blocks what seems to me the most likely way you want to use it.

I have not investigated in any depth, but my intuition says that IAsyncOperation would always be at least effectively single-threaded.

Have I missed something? Is there a reason why that Send bound is there?

Interop with c++/cx

I was wondering if there's some good way of calling into rust code I've written with winrt-rust from, eg, a XAML control I wrote in C++?

Trivial interop I've already managed, but I'd like to be able to write, say, an IAsyncAction in rust that I can call from C++, and this has so far proved difficult.

Specifically, I wrote the following fairly trivial thing in Rust and compiled as a static library:

#[no_mangle]
pub extern fn test() -> HString {
    HString::new("Hello from rust!")
}

#[no_mangle]
pub extern fn do_async_stuff() -> ComPtr<IAsyncOperation<StorageFile>> {
    let uri = Uri::create_uri(FastHString::new("ms-appx:///Assets/file.txt").deref()).unwrap();
    StorageFile::get_file_from_application_uri_async(&uri).unwrap()
}

And in my C++ control I have

extern "C" {
    extern HSTRING test();
    extern WhatGoesHere? do_async_stuff();
}

MainPage::MainPage()
{
    InitializeComponent();
    this->TXT->Text = ref new String(test());
}

I' don't think it's possible to express the type needed in C terms, so I suppose I would have to get around that by using, say, a void pointer and re-interpret cast it. But to what? I assume the hat pointer types are not what's used on the Rust side...

Missing EventHandler usage

Hi there,

I’m trying to use the Windows.Gaming.Input methods to get Gamepad access. I’m having a lot of trouble figuring out how to implement the event handlers! I’ve gotten as far as getting an event handler with a signature that got accepted (kind of complicated, it seems!);

extern crate winrt;

use winrt::*;
use winrt::windows::foundation::*;
use winrt::windows::gaming::input::*;

fn main() {
    let rt = RuntimeContext::init();
    run();
    rt.uninit();
}

fn added(_sender: *mut winrt::IInspectable, gamepad: *mut Gamepad) -> Result<()> {
    print!("Gamepad added");

    Ok(())
}

fn run() {
    let gamepad_list = Gamepad::get_gamepads().unwrap().unwrap();

    print!("{} gamepads connected", gamepad_list.into_iter().count());

    match Gamepad::add_gamepad_added(&<EventHandler<Gamepad>>::new(added)) {
        Error => panic!("Couldn't add event handler")
    }

    for (_index, gamepad) in gamepad_list.into_iter().enumerate() {
        print!("{:?}", gamepad.unwrap().get_current_reading().unwrap());
    };
}

Unfortunately, I get “0 gamepads connected” printed, before it panics with not being able to add the event handler.

Is there something I’ve missed in how this is intended to work? I can find references in issues to event handlers, but I can’t see any example code.

Any help would be very appreciated - I’d also be happy to contribute the above in a PR as an example if I can get it working :)

Generate correct IIDs for parametrized interfaces

For parametric interface types such as AsyncOperationCompletedHandler<TResult>, the SDK header files include definitions of all used specializations of the generic parameter, together with IIDs. These IIDs are deterministic and I was wondering where they are coming from, so I found this blog post, especially the section on "Generic Interfaces" is helpful. The key is the function RoGetParameterizedTypeInstanceIID.

I will probably add that metadata API to my winapi PR, but since the idea was to generate the bindings with some F# or C# program, it's not that important. Some comments also indicate that the API might only be usable from within a Windows Store App, so of course the best thing would be to know the algorithm used to generate those IIDs (see also the last paragraph of the blog post: The somewhat problematic thing about this is this might be difficult to include in a compiler, because the APIs are only available on Win8, so there's no way to generate the GUIDs from a older version of Windows. It'd be nice if Microsoft provided information on how those GUIDs are constructed so other tools that run on other Windows platforms can cross-build for Win8.)

Some APIs from the Windows SDK 10.0.16299 are missing

The Windows SDK 10.0.16299 includes some APIs which are missing from the Rust bindings. Specifically the stuff from the windows::web::ui::interop namespace. Is this intentional? I tried to use the C# generator application and it produced sources which contain missing APIs. Is there any reason to exclude them from the crate?

Find a way to have 16-bit string literals

Unfortunately all string literals passed to WinRT are stored in UTF8 and must first be converted to 16-bit. (wide string). This probably requires a Rust language feature (C++ has L"xxx" literals), but we might be able to do something with const fn, when they support allocation, which might come some time in the future.

Generate parametric interface GUIDs using const fns

We're currently generating all the necessary parametric interface GUIDs ahead of time in the code generator (C#). At least those that are necessary to compile the library. User code might need additional parametric interface instantiations and there's no way for the user to get the required GUIDs. We should instead try to do this from Rust using const fns, once that is implemented stable.

The C++ WinRT projection is using constexpr to do this: https://www.youtube.com/watch?v=7TdpWB_vRZM#t=23m46s

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.