From 1c2d7c6d4906d3cc85f42c2fd32f16c1329cfa5b Mon Sep 17 00:00:00 2001 From: Scott Jones Date: Tue, 22 Jun 2021 14:04:33 -0700 Subject: [PATCH 1/2] Interop interfaces are all pass-by-ref for IID param --- src/Tests/TestComponentCSharp/Class.cpp | 19 +++++++++++ src/Tests/TestComponentCSharp/Class.h | 1 + .../TestComponentCSharp.idl | 1 + src/Tests/UnitTest/ComInteropTests.cs | 30 ++++++++++++++++ src/build.cmd | 6 +++- src/cswinrt/WinRT.Interop.idl | 34 +++++++++---------- 6 files changed, 73 insertions(+), 18 deletions(-) diff --git a/src/Tests/TestComponentCSharp/Class.cpp b/src/Tests/TestComponentCSharp/Class.cpp index c5f355bc3..9075df51b 100644 --- a/src/Tests/TestComponentCSharp/Class.cpp +++ b/src/Tests/TestComponentCSharp/Class.cpp @@ -1480,6 +1480,25 @@ namespace winrt::TestComponentCSharp::implementation return winrt::make(); } + struct __declspec(uuid("15651B9F-6C6B-4CC0-944C-C7D7B0F36F81")) IComInterop : ::IUnknown + { + virtual HRESULT __stdcall GetForWindow(HWND window, guid riid, int64_t* value) noexcept = 0; + }; + + WF::IInspectable Class::ComInterop() + { + struct com_interop : winrt::implements + { + HRESULT __stdcall GetForWindow(HWND window, guid riid, int64_t* value) noexcept override + { + *value = riid == winrt::guid_of() ? (int64_t)window : 0; + return 0; + } + }; + + return winrt::make(); + } + // INotifyDataErrorInfo bool Class::HasErrors() { diff --git a/src/Tests/TestComponentCSharp/Class.h b/src/Tests/TestComponentCSharp/Class.h index 9d36e88a6..f52795a5b 100644 --- a/src/Tests/TestComponentCSharp/Class.h +++ b/src/Tests/TestComponentCSharp/Class.h @@ -367,6 +367,7 @@ namespace winrt::TestComponentCSharp::implementation static IProperties1 NativeProperties1(); static Windows::Foundation::IInspectable ServiceProvider(); + static winrt::Windows::Foundation::IInspectable ComInterop(); // IStringable hstring ToString(); diff --git a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl index e9d3f0de3..c78f28145 100644 --- a/src/Tests/TestComponentCSharp/TestComponentCSharp.idl +++ b/src/Tests/TestComponentCSharp/TestComponentCSharp.idl @@ -386,6 +386,7 @@ namespace TestComponentCSharp // Interface projections static IProperties1 NativeProperties1{ get; }; static Object ServiceProvider{ get; }; + static Object ComInterop{ get; }; // INotifyDataErrorInfo void RaiseDataErrorChanged(); diff --git a/src/Tests/UnitTest/ComInteropTests.cs b/src/Tests/UnitTest/ComInteropTests.cs index 1617db06b..995ac3bcb 100644 --- a/src/Tests/UnitTest/ComInteropTests.cs +++ b/src/Tests/UnitTest/ComInteropTests.cs @@ -13,13 +13,43 @@ using Windows.UI.Input.Spatial; using Windows.UI.ViewManagement; using Xunit; +using WinRT; +using TestComponentCSharp; namespace UnitTest { + [ComImport] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("15651B9F-6C6B-4CC0-944C-C7D7B0F36F81")] + internal interface IComInterop + { + Int64 GetForWindow(IntPtr hwnd, Guid iid); + } + // Note: Many of the COM interop APIs cannot be easily tested without significant test setup. // These cases either expect a runtime exception, or are compile-time only (skipped to validate types). public class ComInteropTests { + [Fact] + public void TestHWND() + { + var comInterop = Class.ComInterop.As(); + if (System.Environment.Is64BitProcess) + { + var hwnd = new IntPtr(0x0123456789ABCDEF); + var value = comInterop.GetForWindow(hwnd, typeof(IComInterop).GUID); + var hwndValue = hwnd.ToInt64(); + Assert.Equal(hwndValue, value); + } + else + { + var hwnd = new IntPtr(0x01234567); + var value = comInterop.GetForWindow(hwnd, typeof(IComInterop).GUID); + var hwndValue = hwnd.ToInt32(); + Assert.Equal(hwndValue, value); + } + } + [Fact] public void TestAccountsSettingsPane() { diff --git a/src/build.cmd b/src/build.cmd index a78c512c0..3748dc044 100644 --- a/src/build.cmd +++ b/src/build.cmd @@ -137,7 +137,11 @@ if "%cswinrt_build_only%"=="true" goto :eof :unittest rem Build/Run xUnit tests, generating xml output report for Azure Devops reporting, via XunitXml.TestLogger NuGet echo Running cswinrt unit tests for %cswinrt_platform% %cswinrt_configuration% -set dotnet_exe="%DOTNET_ROOT%\dotnet.exe" +if %cswinrt_platform%==x86 ( + set dotnet_exe="%DOTNET_ROOT(86)%\dotnet.exe" +) else ( + set dotnet_exe="%DOTNET_ROOT%\dotnet.exe" +) if not exist %dotnet_exe% ( if %cswinrt_platform%==x86 ( set dotnet_exe="%ProgramFiles(x86)%\dotnet\dotnet.exe" diff --git a/src/cswinrt/WinRT.Interop.idl b/src/cswinrt/WinRT.Interop.idl index 3a016cff0..0db1974cd 100644 --- a/src/cswinrt/WinRT.Interop.idl +++ b/src/cswinrt/WinRT.Interop.idl @@ -24,13 +24,13 @@ namespace WinRT.Interop { Object GetForWindow( HWND appWindow, - GUID riid); + ref const GUID riid); Object ShowManageAccountsForWindowAsync( HWND appWindow, - GUID riid); + ref const GUID riid); Object ShowAddAccountForWindowAsync( HWND appWindow, - GUID riid); + ref const GUID riid); } #endif @@ -41,7 +41,7 @@ namespace WinRT.Interop { Object GetForWindow( HWND hwnd, - GUID riid); + ref const GUID riid); } #endif @@ -52,7 +52,7 @@ namespace WinRT.Interop { Object GetForWindow( HWND appWindow, - GUID riid); + ref const GUID riid); } #endif @@ -63,7 +63,7 @@ namespace WinRT.Interop { Object GetForWindow( HWND appWindow, - GUID riid); + ref const GUID riid); void ShowPlayToUIForWindow( HWND appWindow); @@ -77,11 +77,11 @@ namespace WinRT.Interop { Object GetForWindow( HWND appWindow, - GUID riid); + ref const GUID riid); Object ShowPrintUIForWindowAsync( HWND appWindow, - GUID riid); + ref const GUID riid); } #endif @@ -92,7 +92,7 @@ namespace WinRT.Interop { Object CreateForWindow( HWND hwnd, - GUID riid); + ref const GUID riid); } #endif @@ -102,7 +102,7 @@ namespace WinRT.Interop { Object GetForWindow( HWND hwnd, - GUID riid); + ref const GUID riid); } #endif @@ -112,7 +112,7 @@ namespace WinRT.Interop { Object CreateForWindow( HWND hwnd, - GUID riid); + ref const GUID riid); } #endif @@ -124,7 +124,7 @@ namespace WinRT.Interop { Object GetForWindow( HWND window, - GUID riid); + ref const GUID riid); } #endif @@ -135,7 +135,7 @@ namespace WinRT.Interop { Object GetForWindow( HWND appWindow, - GUID riid); + ref const GUID riid); } #endif @@ -146,7 +146,7 @@ namespace WinRT.Interop { Object GetForWindow( HWND hwnd, - GUID riid); + ref const GUID riid); } #endif @@ -158,7 +158,7 @@ namespace WinRT.Interop Object RequestVerificationForWindowAsync( HWND appWindow, String message, - GUID riid); + ref const GUID riid); } #endif @@ -170,13 +170,13 @@ namespace WinRT.Interop Object RequestTokenForWindowAsync( HWND appWindow, Windows.Security.Authentication.Web.Core.WebTokenRequest request, - GUID riid); // __uuidof(IAsyncOperation) + ref const GUID riid); // __uuidof(IAsyncOperation) Object RequestTokenWithWebAccountForWindowAsync( HWND appWindow, Windows.Security.Authentication.Web.Core.WebTokenRequest request, Windows.Security.Credentials.WebAccount webAccount, - GUID riid); // __uuidof(IAsyncOperation) + ref const GUID riid); // __uuidof(IAsyncOperation) } #endif } \ No newline at end of file From 55287ccdfeb36e1985f359a20994bdf89d032c7e Mon Sep 17 00:00:00 2001 From: Scott Jones Date: Tue, 22 Jun 2021 18:59:06 -0700 Subject: [PATCH 2/2] added unit test implementation of actual interop interface --- src/Projections/Windows/Windows.csproj | 1 + src/Tests/TestComponentCSharp/Class.cpp | 24 +++++++++++++++++++++--- src/Tests/UnitTest/ComInteropTests.cs | 15 ++++++++++++--- src/Tests/UnitTest/WinUITest.net5.cs | 3 --- 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/src/Projections/Windows/Windows.csproj b/src/Projections/Windows/Windows.csproj index 982dfdcc6..b3003e27e 100644 --- a/src/Projections/Windows/Windows.csproj +++ b/src/Projections/Windows/Windows.csproj @@ -9,6 +9,7 @@ + diff --git a/src/Tests/TestComponentCSharp/Class.cpp b/src/Tests/TestComponentCSharp/Class.cpp index 9075df51b..95a63ed23 100644 --- a/src/Tests/TestComponentCSharp/Class.cpp +++ b/src/Tests/TestComponentCSharp/Class.cpp @@ -1482,18 +1482,36 @@ namespace winrt::TestComponentCSharp::implementation struct __declspec(uuid("15651B9F-6C6B-4CC0-944C-C7D7B0F36F81")) IComInterop : ::IUnknown { - virtual HRESULT __stdcall GetForWindow(HWND window, guid riid, int64_t* value) noexcept = 0; + virtual HRESULT __stdcall ReturnWindowHandle(HWND window, guid riid, int64_t* value) noexcept = 0; + }; + + struct __declspec(uuid("5AD8CBA7-4C01-4DAC-9074-827894292D63")) IDragDropManagerInterop : ::IInspectable + { + virtual HRESULT __stdcall GetForWindow(HWND window, guid const& riid, void** value) noexcept = 0; }; WF::IInspectable Class::ComInterop() { - struct com_interop : winrt::implements + struct com_interop : winrt::implements { - HRESULT __stdcall GetForWindow(HWND window, guid riid, int64_t* value) noexcept override + HRESULT __stdcall ReturnWindowHandle(HWND window, guid riid, int64_t* value) noexcept override { *value = riid == winrt::guid_of() ? (int64_t)window : 0; return 0; } + + HRESULT __stdcall GetForWindow(HWND window, guid const& riid, void** value) noexcept override + { + static const guid ICoreDragDropManager("7D56D344-8464-4FAF-AA49-37EA6E2D7BD1"); + if (riid == ICoreDragDropManager) + { + auto dummy = winrt::make(); + *value = winrt::detach_abi(dummy); + return 0; + } + *value = 0; + return 0x80070057; // E_INVALIDARG + } }; return winrt::make(); diff --git a/src/Tests/UnitTest/ComInteropTests.cs b/src/Tests/UnitTest/ComInteropTests.cs index 995ac3bcb..e2120801d 100644 --- a/src/Tests/UnitTest/ComInteropTests.cs +++ b/src/Tests/UnitTest/ComInteropTests.cs @@ -23,7 +23,7 @@ namespace UnitTest [Guid("15651B9F-6C6B-4CC0-944C-C7D7B0F36F81")] internal interface IComInterop { - Int64 GetForWindow(IntPtr hwnd, Guid iid); + Int64 ReturnWindowHandle(IntPtr hwnd, Guid iid); } // Note: Many of the COM interop APIs cannot be easily tested without significant test setup. @@ -37,19 +37,28 @@ public void TestHWND() if (System.Environment.Is64BitProcess) { var hwnd = new IntPtr(0x0123456789ABCDEF); - var value = comInterop.GetForWindow(hwnd, typeof(IComInterop).GUID); + var value = comInterop.ReturnWindowHandle(hwnd, typeof(IComInterop).GUID); var hwndValue = hwnd.ToInt64(); Assert.Equal(hwndValue, value); } else { var hwnd = new IntPtr(0x01234567); - var value = comInterop.GetForWindow(hwnd, typeof(IComInterop).GUID); + var value = comInterop.ReturnWindowHandle(hwnd, typeof(IComInterop).GUID); var hwndValue = hwnd.ToInt32(); Assert.Equal(hwndValue, value); } } + [Fact] + public void TestMockDragDropManager() + { + var interop = Class.ComInterop.As(); + Guid iid = GuidGenerator.CreateIID(typeof(ICoreDragDropManager)); + var manager = interop.GetForWindow(new IntPtr(0), iid); + Assert.NotNull(manager); + } + [Fact] public void TestAccountsSettingsPane() { diff --git a/src/Tests/UnitTest/WinUITest.net5.cs b/src/Tests/UnitTest/WinUITest.net5.cs index 6329cf614..07709622e 100644 --- a/src/Tests/UnitTest/WinUITest.net5.cs +++ b/src/Tests/UnitTest/WinUITest.net5.cs @@ -32,9 +32,6 @@ public class TestAllowMultipleAttributes { }; [Fact] public void TestApp() { - WinrtModule module = new WinrtModule(); - - var app = new App(); // TODO: load up some MUX! //Assert.Equal(true, true); }