diff --git a/crates/tests/noexcept/Cargo.toml b/crates/tests/noexcept/Cargo.toml index f1caaf2c3a..881ecabdda 100644 --- a/crates/tests/noexcept/Cargo.toml +++ b/crates/tests/noexcept/Cargo.toml @@ -9,3 +9,9 @@ path = "../../libs/core" [build-dependencies.windows-bindgen] path = "../../libs/bindgen" + +[build-dependencies] +cc = "1.0" + +[build-dependencies.cppwinrt] +path = "../../libs/cppwinrt" diff --git a/crates/tests/noexcept/build.rs b/crates/tests/noexcept/build.rs index 217d224bd6..fb516b21f1 100644 --- a/crates/tests/noexcept/build.rs +++ b/crates/tests/noexcept/build.rs @@ -2,6 +2,8 @@ fn main() { println!("cargo:rerun-if-changed=src/test.idl"); let metadata_dir = format!("{}\\System32\\WinMetadata", env!("windir")); let mut command = std::process::Command::new("midlrt.exe"); + println!("cargo:rerun-if-changed=src/interop.cpp"); + println!("cargo:rustc-link-lib=windows.0.52.0"); command.args([ "/winrt", @@ -34,4 +36,20 @@ fn main() { ]) { panic!("{error}"); } + + cppwinrt::cppwinrt([ + "-in", + "test.winmd", + &format!("{}\\System32\\WinMetadata", env!("windir")), + "-out", + "src", + ]) + .unwrap(); + + cc::Build::new() + .cpp(true) + .std("c++20") + .flag("/EHsc") + .file("src/interop.cpp") + .compile("interop"); } diff --git a/crates/tests/noexcept/src/interop.cpp b/crates/tests/noexcept/src/interop.cpp new file mode 100644 index 0000000000..595ad741dd --- /dev/null +++ b/crates/tests/noexcept/src/interop.cpp @@ -0,0 +1,140 @@ +#include +#include "winrt/Test.h" + +using namespace winrt; +using namespace winrt::Test; + +void test_except(ITest const &test) +{ + test.MethodString(L"abc"); + assert(test.String() == L"abc"); + + test.MethodInt32(123); + assert(test.Int32() == 123); + + test.MethodTest(test); + assert(test.Test() == test); +} + +void test_noexcept(ITest const &test) +{ + test.MethodStringN(L"abc"); + assert(test.StringN() == L"abc"); + + test.MethodInt32N(123); + assert(test.Int32N() == 123); + + test.MethodTestN(test); + assert(test.TestN() == test); +} + +struct Implementation : implements +{ + hstring m_string; + int32_t m_int32; + ITest m_test; + + void MethodString(hstring const &value) + { + m_string = value; + } + void MethodInt32(int32_t value) + { + m_int32 = value; + } + void MethodTest(ITest const &value) + { + m_test = value; + } + hstring String() const + { + return m_string; + } + void String(hstring const &value) + { + m_string = value; + } + int32_t Int32() const + { + return m_int32; + } + void Int32(int32_t value) + { + m_int32 = value; + } + ITest Test() const + { + return m_test; + } + void Test(ITest const &value) + { + m_test = value; + } + + void MethodStringN(hstring const &value) noexcept + { + m_string = value; + } + void MethodInt32N(int32_t value) noexcept + { + m_int32 = value; + } + void MethodTestN(ITest const &value) noexcept + { + m_test = value; + } + hstring StringN() const noexcept + { + return m_string; + } + void StringN(hstring const &value) noexcept + { + m_string = value; + } + int32_t Int32N() const noexcept + { + return m_int32; + } + void Int32N(int32_t value) noexcept + { + m_int32 = value; + } + ITest TestN() const noexcept + { + return m_test; + } + void TestN(ITest const &value) noexcept + { + m_test = value; + } +}; + +extern "C" +{ + HRESULT __stdcall consume(void *abi) noexcept + try + { + ITest const &test = *reinterpret_cast(&abi); + + test_noexcept(test); + test_except(test); + + return S_OK; + } + catch (...) + { + return to_hresult(); + } + + HRESULT __stdcall produce(void **abi) noexcept + try + { + *abi = detach_abi(make()); + + return S_OK; + } + catch (...) + { + return to_hresult(); + } +} diff --git a/crates/tests/noexcept/src/lib.rs b/crates/tests/noexcept/src/lib.rs index 90c70dcc2c..79a79039e3 100644 --- a/crates/tests/noexcept/src/lib.rs +++ b/crates/tests/noexcept/src/lib.rs @@ -1 +1,23 @@ -pub mod bindings; +mod bindings; +pub use bindings::*; +pub use windows_core::*; + +pub fn consume(test: &ITest) -> Result<()> { + extern "system" { + fn consume(test: Ref) -> HRESULT; + } + + unsafe { consume(std::mem::transmute_copy(test)).ok() } +} + +pub fn produce() -> Result { + extern "system" { + fn produce(test: *mut *mut std::ffi::c_void) -> HRESULT; + } + + unsafe { + let mut test = None; + produce(&mut test as *mut _ as *mut _).ok()?; + Type::from_default(&test) + } +} diff --git a/crates/tests/noexcept/tests/test.rs b/crates/tests/noexcept/tests/test.rs index 48f289a563..63af99dd4e 100644 --- a/crates/tests/noexcept/tests/test.rs +++ b/crates/tests/noexcept/tests/test.rs @@ -1,5 +1,4 @@ -use test_noexcept::bindings::*; -use windows_core::*; +use test_noexcept::*; #[implement(ITest)] #[derive(Default)] @@ -87,32 +86,43 @@ impl ITest_Impl for Test { } } -#[test] -fn test_except() -> Result<()> { - let test: ITest = Test::default().into(); - +fn test_except(test: &ITest) -> Result<()> { test.MethodString(h!("abc"))?; assert_eq!(test.String()?, "abc"); test.MethodInt32(123)?; assert_eq!(test.Int32()?, 123); - test.MethodTest(&test)?; - assert_eq!(&test.Test()?, &test); + test.MethodTest(test)?; + assert_eq!(&test.Test()?, test); Ok(()) } -#[test] -fn test_noexcept() { - let test: ITest = Test::default().into(); - +fn test_noexcept(test: &ITest) { test.MethodStringN(h!("abc")); assert_eq!(test.StringN(), "abc"); test.MethodInt32N(123); assert_eq!(test.Int32N(), 123); - test.MethodTestN(&test); - assert_eq!(test.TestN().as_ref(), Some(&test)); + test.MethodTestN(test); + assert_eq!(test.TestN().as_ref(), Some(test)); +} + +#[test] +fn test_rust() -> Result<()> { + let test: ITest = Test::default().into(); + test_noexcept(&test); + test_except(&test) +} + +#[test] +fn test_cpp() -> Result<()> { + let test: ITest = Test::default().into(); + consume(&test)?; + + let test: ITest = produce()?; + test_noexcept(&test); + test_except(&test) }