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:
Родитель
49330d2787
Коммит
14a0e9edee
|
@ -0,0 +1,6 @@
|
|||
* text=auto
|
||||
* text eol=lf
|
||||
*.png -text
|
||||
*.winmd -text
|
||||
*.dll -text
|
||||
*.lib -text
|
|
@ -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.
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/target
|
||||
/.vscode
|
||||
/.vs
|
||||
Cargo.lock
|
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичный файл не отображается.
Двоичные данные
.windows/winmd/Microsoft.Windows.ApplicationModel.DynamicDependency.winmd
Normal file
Двоичные данные
.windows/winmd/Microsoft.Windows.ApplicationModel.DynamicDependency.winmd
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"
|
|
@ -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"
|
|
@ -0,0 +1,5 @@
|
|||
fn main() {
|
||||
windows::build! {
|
||||
Windows::Win32::UI::WindowsAndMessaging::MessageBoxW
|
||||
};
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
windows::include_bindings!();
|
|
@ -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");
|
||||
}
|
|
@ -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() }
|
||||
}
|
|
@ -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()
|
||||
}
|
Загрузка…
Ссылка в новой задаче