Initial Windows App SDK support

The beginnings of the `windows-app` crate. Includes the wiring necessary to bootstrap dynamic dependencies for unpackaged Windows apps and a window handle helper.
This commit is contained in:
Rafael Rivera 2021-06-24 15:31:45 -07:00 коммит произвёл GitHub
Родитель 49330d2787
Коммит 14a0e9edee
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
24 изменённых файлов: 271 добавлений и 25 удалений

6
.gitattributes поставляемый Normal file
Просмотреть файл

@ -0,0 +1,6 @@
* text=auto
* text eol=lf
*.png -text
*.winmd -text
*.dll -text
*.lib -text

48
.github/SUPPORT.md поставляемый
Просмотреть файл

@ -1,25 +1,23 @@
# TODO: The maintainer of this repo has not yet edited this file
**REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project?
- **No CSS support:** Fill out this template with information about how to file issues and get help.
- **Yes CSS support:** Fill out an intake form at [aka.ms/spot](https://aka.ms/spot). CSS will work with/help you to determine next steps. More details also available at [aka.ms/onboardsupport](https://aka.ms/onboardsupport).
- **Not sure?** Fill out a SPOT intake as though the answer were "Yes". CSS will help you decide.
*Then remove this first heading from this SUPPORT.MD file before publishing your repo.*
# Support
## How to file issues and get help
This project uses GitHub Issues to track bugs and feature requests. Please search the existing
issues before filing new issues to avoid duplicates. For new issues, file your bug or
feature request as a new Issue.
For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE
FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER
CHANNEL. WHERE WILL YOU HELP PEOPLE?**.
## Microsoft Support Policy
Support for this **PROJECT or PRODUCT** is limited to the resources listed above.
**REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project?
- **No CSS support:** Fill out this template with information about how to file issues and get help.
- **Yes CSS support:** Fill out an intake form at [aka.ms/spot](https://aka.ms/spot). CSS will work with/help you to determine next steps. More details also available at [aka.ms/onboardsupport](https://aka.ms/onboardsupport).
- **Not sure?** Fill out a SPOT intake as though the answer were "Yes". CSS will help you decide.
*Then remove this first heading from this SUPPORT.MD file before publishing your repo.*
# Support
## How to file issues and get help
This project uses GitHub Issues to track bugs and feature requests. Please search the existing
issues before filing new issues to avoid duplicates. For new issues, file your bug or
feature request as a new Issue.
For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE
FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER
CHANNEL. WHERE WILL YOU HELP PEOPLE?**.
## Microsoft Support Policy
Support for this **PROJECT or PRODUCT** is limited to the resources listed above.

4
.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,4 @@
/target
/.vscode
/.vs
Cargo.lock

Двоичные данные
.windows/arm64/Microsoft.ProjectReunion.Bootstrap.dll Normal file

Двоичный файл не отображается.

Двоичные данные
.windows/arm64/Microsoft.ProjectReunion.Bootstrap.lib Normal file

Двоичный файл не отображается.

Двоичные данные
.windows/winmd/Microsoft.ApplicationModel.Resources.winmd Normal file

Двоичный файл не отображается.

Двоичные данные
.windows/winmd/Microsoft.Foundation.winmd Normal file

Двоичный файл не отображается.

Двоичные данные
.windows/winmd/Microsoft.Graphics.winmd Normal file

Двоичный файл не отображается.

Двоичные данные
.windows/winmd/Microsoft.UI.Text.winmd Normal file

Двоичный файл не отображается.

Двоичные данные
.windows/winmd/Microsoft.UI.winmd Normal file

Двоичный файл не отображается.

Двоичные данные
.windows/winmd/Microsoft.Web.WebView2.Core.winmd Normal file

Двоичный файл не отображается.

Двоичные данные
.windows/winmd/Microsoft.Windows.AppLifecycle.winmd Normal file

Двоичный файл не отображается.

Двоичный файл не отображается.

Двоичные данные
.windows/x64/Microsoft.ProjectReunion.Bootstrap.dll Normal file

Двоичный файл не отображается.

Двоичные данные
.windows/x64/Microsoft.ProjectReunion.Bootstrap.lib Normal file

Двоичный файл не отображается.

Двоичные данные
.windows/x86/Microsoft.ProjectReunion.Bootstrap.dll Normal file

Двоичный файл не отображается.

Двоичные данные
.windows/x86/Microsoft.ProjectReunion.Bootstrap.lib Normal file

Двоичный файл не отображается.

15
Cargo.toml Normal file
Просмотреть файл

@ -0,0 +1,15 @@
[package]
name = "windows-app"
version = "0.2.0"
authors = ["Microsoft"]
edition = "2018"
license = "MIT OR Apache-2.0"
description = "Windows App SDK"
repository = "https://github.com/microsoft/windows-app-rs"
documentation = "https://docs.rs/windows-app"
readme = "README.md"
exclude = [".github", ".windows", "docs"]
[dependencies]
bindings = { package = "windows_app_bindings", path = "bindings" }
windows = "0.12"

13
bindings/Cargo.toml Normal file
Просмотреть файл

@ -0,0 +1,13 @@
[package]
name = "windows_app_bindings"
version = "0.2.0"
authors = ["Microsoft"]
edition = "2018"
license = "MIT OR Apache-2.0"
description = "Implementation for windows-app crate"
[dependencies]
windows = "0.12.0"
[build-dependencies]
windows = "0.12.0"

5
bindings/build.rs Normal file
Просмотреть файл

@ -0,0 +1,5 @@
fn main() {
windows::build! {
Windows::Win32::UI::WindowsAndMessaging::MessageBoxW
};
}

1
bindings/src/lib.rs Normal file
Просмотреть файл

@ -0,0 +1 @@
windows::include_bindings!();

15
build.rs Normal file
Просмотреть файл

@ -0,0 +1,15 @@
fn main() {
let arch = match std::env::var("CARGO_CFG_TARGET_ARCH").unwrap().as_str() {
"x86_64" => "x64",
"x86" => "x86",
"arm" => "arm",
"aarch64" => "arm64",
unexpected => panic!(
"Unexpected `{}` architecture set by `CARGO_CFG_TARGET_ARCH`",
unexpected
),
};
println!("cargo:rustc-link-search=native=.windows/{}", arch);
println!("cargo:rerun-if-changed=build.rs");
println!("cargo:rerun-if-changed=.windows");
}

134
src/bootstrap.rs Normal file
Просмотреть файл

@ -0,0 +1,134 @@
use bindings::Windows::Win32::{
Foundation::HWND,
UI::WindowsAndMessaging::{MessageBoxW, MB_ICONERROR, MB_OK},
};
#[repr(C)]
#[derive(Clone, Copy)]
pub struct PackageVersion {
pub revision: u8,
pub build: u8,
pub minor: u8,
pub major: u8,
}
impl PackageVersion {
pub fn new(major: u8, minor: u8, build: u8, revision: u8) -> Self {
Self {
revision,
build,
minor,
major,
}
}
fn to_major_minor(self) -> u32 {
((self.major as u32) << 8) | self.minor as u32
}
}
#[test]
#[allow(non_snake_case)]
fn package_version_zero_produces_zero_major_minor() {
let v = PackageVersion {
major: 0,
minor: 0,
revision: 0,
build: 0,
};
assert_eq!(v.to_major_minor(), 0);
}
#[test]
fn package_version_max_produces_correct_major_minor() {
let v = PackageVersion {
major: 255,
minor: 255,
revision: 42,
build: 42,
};
assert_eq!(v.to_major_minor(), 255 << 8 | 255);
}
#[test]
fn package_version_mixed_produces_correct_major_minor() {
let v = PackageVersion {
major: 0,
minor: 8,
revision: 42,
build: 192,
};
assert_eq!(v.to_major_minor(), 0 << 8 | 8);
}
#[test]
fn package_version_has_expected_c_representation() {
let v = PackageVersion {
major: 1,
minor: 2,
build: 3,
revision: 4,
};
unsafe {
let bytes = &v as *const _ as *const u8;
assert_eq!(std::slice::from_raw_parts(bytes, 4), [4, 3, 2, 1]);
}
}
#[link(name = "Microsoft.ProjectReunion.Bootstrap")]
extern "system" {
fn MddBootstrapInitialize(
majorMinorVersion: u32,
versionTag: *const u16,
minVersion: PackageVersion,
) -> windows::HRESULT;
fn MddBootstrapShutdown() -> windows::HRESULT;
}
/// Locates the Windows App framework package compatible with the (currently internal)
/// versioning criteria and loads it into the current process. If multiple packages meet
/// the criteria, the best candidate is selected.
pub fn initialize() -> windows::Result<()> {
initialize_without_dialog()
.map_err(|outer_error| {
unsafe {
MessageBoxW(
HWND::default(),
"To run this application, the Windows App preview runtime must be installed.\n\nhttps://aka.ms/projectreunion/0.8preview",
"This application could not be started",
MB_OK | MB_ICONERROR,
);
outer_error
}
})
}
pub fn initialize_without_dialog() -> windows::Result<()> {
let version_tag: Vec<u16> = "preview".encode_utf16().collect();
let mdd_version = PackageVersion {
major: 0,
minor: 8,
revision: 0,
build: 0,
};
let min_framework_version = PackageVersion {
major: 0,
minor: 1,
revision: 0,
build: 0,
};
unsafe {
MddBootstrapInitialize(
mdd_version.to_major_minor(),
version_tag.as_ptr(),
min_framework_version,
)
.ok()
}
}
/// Undo the changes made by `initialize()`
pub fn uninitialize() -> windows::Result<()> {
unsafe { MddBootstrapShutdown().ok() }
}

55
src/lib.rs Normal file
Просмотреть файл

@ -0,0 +1,55 @@
pub mod bootstrap;
use windows::{IInspectable, Interface, HRESULT};
#[repr(transparent)]
struct IWindowNative(windows::IUnknown);
#[allow(dead_code)]
impl IWindowNative {
pub fn handle(&self) -> Option<isize> {
unsafe {
let mut hwnd = 0;
match self.WindowHandle(&mut hwnd as *mut isize) {
HRESULT(0) => Some(hwnd),
_ => None,
}
}
}
#[allow(non_snake_case)]
unsafe fn WindowHandle(&self, hwnd: *mut isize) -> windows::HRESULT {
(::windows::Interface::vtable(self).3)(::windows::Abi::abi(self), hwnd)
}
}
#[repr(C)]
struct IWindowNative_vtbl(
// IUnknown::QueryInterface
pub unsafe extern "system" fn(
this: ::windows::RawPtr,
iid: &::windows::Guid,
interface: *mut ::windows::RawPtr,
) -> ::windows::HRESULT,
// IUnknown::AddRef
pub unsafe extern "system" fn(this: ::windows::RawPtr) -> u32,
// IUnknown::Release
pub unsafe extern "system" fn(this: ::windows::RawPtr) -> u32,
// HRESULT WindowHandle(HWND* hWnd);
pub unsafe extern "system" fn(this: ::windows::RawPtr, hwnd: *const isize) -> ::windows::HRESULT,
);
unsafe impl ::windows::Interface for IWindowNative {
type Vtable = IWindowNative_vtbl;
// {eecdbf0e-bae9-4cb6-a68e-9598e1cb57bb}
const IID: ::windows::Guid = ::windows::Guid::from_values(
0xeecdbf0e,
0xbae9,
0x4cb6,
[0xa6, 0x8e, 0x95, 0x98, 0xe1, 0xcb, 0x57, 0xbb],
);
}
pub fn window_handle(window: &IInspectable) -> Option<isize> {
window.cast::<IWindowNative>().unwrap().handle()
}