Skip to content

Commit

Permalink
Add Managed->Native tests for our WinRT primitives (dotnet#23529)
Browse files Browse the repository at this point in the history
* First pass generating the contracts for the WinRT tests. Managed ones are manually written, Native are generated via C++/WinRT.

* Don't overwrite the public implementation files when we run cppwinrt

* Don't output a MIDL-processed header.

* Add default constructor for BindingViewModel.

* Partial implementation of most of the native winrt component.

* Finish implementation of native winrt component.

* Get native component building correctly (cppwinrt doesn't include wrappers for the "Windows::UI::Xaml::Interop::IBindable*" collection types.

* Add WinRT primitive marshalling tests.

* Add testing for projected types used for binding.

* Add license headers to native files.

* Disable WinRT tests on non-WinRT platforms (detection copied from CoreFX).

* Use WINDOWS_SDK_VERSION variable in all locations.

* Use Windows SDK version determined by CMake in WinRT build.

* Resolve WinMDs via globs so the build can roll between different Windows SDK versions that have required APIs seamlessly.

* Add logging of cppwinrt version.

* Try to construct path to cppwinrt when finding it

* Just directly construct the cppwinrt path.

* Remove -prefix flag from cppwinrt invocation

* PR feedback.

* Fix syntax in BindableVectorWrapper.

* Disable winrt binding test on Nano Server.

* Add enum testing. Clean up WinRT tests to hopefully build on CI (or at least fail at a later point).

* Add some more logging to try to determine why an older SDK version is being picked.

* Try to define CMAKE_SYSTEM_VERSION and see if that selects the correct SDK version (it seems to work on the build.cmd script)

* Clean up WinRT CMake now that it builds on AzDO CI.

* Disable WinRT binding test on pre-Win10V1809 systems.
  • Loading branch information
jkoritzinsky authored May 17, 2019
1 parent b4c2b14 commit 6a2c6a4
Show file tree
Hide file tree
Showing 47 changed files with 1,505 additions and 1 deletion.
3 changes: 2 additions & 1 deletion build-test.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ if not defined VSINSTALLDIR (
if not exist "%VSINSTALLDIR%DIA SDK" goto NoDIA

pushd "%__NativeTestIntermediatesDir%"
call "%__SourceDir%\pal\tools\gen-buildsys-win.bat" ""%__ProjectFilesDir%"" %__VSVersion% %__BuildArch%
set __ExtraCmakeArgs="-DCMAKE_SYSTEM_VERSION=10.0"
call "%__SourceDir%\pal\tools\gen-buildsys-win.bat" ""%__ProjectFilesDir%"" %__VSVersion% %__BuildArch% !__ExtraCmakeArgs!
@if defined _echo @echo on
popd

Expand Down
10 changes: 10 additions & 0 deletions tests/src/Common/CoreCLRTestLibrary/Assertion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,16 @@ static public void AreNotSame(object notExpected, object actual, string message)
}
}

static public void OfType<T>(object obj)
{
if (!(obj is T))
{
Assert.HandleFail(
"Assert.IsOfType",
$"Expected an object of type [{typeof(T).AssemblyQualifiedName}], got type of type [{obj.GetType().AssemblyQualifiedName}].");
}
}

/// <summary>
/// Throws an AssertFailedException.
/// </summary>
Expand Down
75 changes: 75 additions & 0 deletions tests/src/Common/CoreCLRTestLibrary/Utilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,12 @@ public static bool Verbose
public static bool IsLinux => RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
public static bool IsMacOSX => RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
public static bool IsWindows7 => IsWindows && Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 1;
public static bool IsWinRTSupported => IsWindows && !IsWindows7;
public static bool IsWindowsNanoServer => (!IsWindowsIoTCore && GetInstallationType().Equals("Nano Server", StringComparison.OrdinalIgnoreCase));

// Windows 10 October 2018 Update
public static bool IsWindows10Version1809OrGreater =>
IsWindows && GetWindowsVersion() == 10 && GetWindowsMinorVersion() == 0 && GetWindowsBuildNumber() >= 17763;
public static bool IsWindowsIoTCore
{
get
Expand Down Expand Up @@ -193,6 +198,37 @@ private static string GetInstallationTypeForWindows()
}
}

internal static uint GetWindowsVersion()
{
if (!IsWindows)
{
return 0;
}

Assert.AreEqual(0, Ntdll.RtlGetVersionEx(out Ntdll.RTL_OSVERSIONINFOEX osvi));
return osvi.dwMajorVersion;
}
internal static uint GetWindowsMinorVersion()
{
if (!IsWindows)
{
return 0;
}

Assert.AreEqual(0, Ntdll.RtlGetVersionEx(out Ntdll.RTL_OSVERSIONINFOEX osvi));
return osvi.dwMinorVersion;
}
internal static uint GetWindowsBuildNumber()
{
if (!IsWindows)
{
return 0;
}

Assert.AreEqual(0, Ntdll.RtlGetVersionEx(out Ntdll.RTL_OSVERSIONINFOEX osvi));
return osvi.dwBuildNumber;
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static string GetRegistryValueString(string key, string value)
{
Expand Down Expand Up @@ -231,6 +267,45 @@ private static string GetRegistryValueString(string key, string value)
return stringValue;
}

private static class Ntdll
{
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
internal unsafe struct RTL_OSVERSIONINFOEX
{
internal uint dwOSVersionInfoSize;
internal uint dwMajorVersion;
internal uint dwMinorVersion;
internal uint dwBuildNumber;
internal uint dwPlatformId;
internal fixed char szCSDVersion[128];
}

[DllImport(nameof(Ntdll), ExactSpelling=true)]
private static extern int RtlGetVersion(ref RTL_OSVERSIONINFOEX lpVersionInformation);

internal static unsafe int RtlGetVersionEx(out RTL_OSVERSIONINFOEX osvi)
{
osvi = new RTL_OSVERSIONINFOEX();
osvi.dwOSVersionInfoSize = (uint)sizeof(RTL_OSVERSIONINFOEX);
return RtlGetVersion(ref osvi);
}

internal static unsafe string RtlGetVersion()
{
const string Version = "Microsoft Windows";
if (RtlGetVersionEx(out RTL_OSVERSIONINFOEX osvi) == 0)
{
return osvi.szCSDVersion[0] != '\0' ?
string.Format("{0} {1}.{2}.{3} {4}", Version, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber, new string(&(osvi.szCSDVersion[0]))) :
string.Format("{0} {1}.{2}.{3}", Version, osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.dwBuildNumber);
}
else
{
return Version;
}
}
}

private sealed class Kernel32
{
public const int PRODUCT_UNDEFINED = 0;
Expand Down
1 change: 1 addition & 0 deletions tests/src/Interop/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ if(WIN32)
add_subdirectory(COM/NativeClients/Primitives)
add_subdirectory(COM/NativeClients/Licensing)
add_subdirectory(COM/NativeClients/DefaultInterfaces)
add_subdirectory(WinRT/NativeComponent)

# IJW isn't supported on ARM64
if(NOT CLR_CMAKE_PLATFORM_ARCH_ARM64)
Expand Down
118 changes: 118 additions & 0 deletions tests/src/Interop/WinRT/Contracts/Component.Contracts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;

namespace Component.Contracts
{
[ComImport]
[Guid("971AF13A-9793-4AF7-B2F2-72D829195592")]
[WindowsRuntimeImport]
public interface IBooleanTesting
{
bool And(bool left, bool right);
}

[ComImport]
[Guid("C6F1F632-47B6-4A52-86D2-A89807ED2677")]
[WindowsRuntimeImport]
public interface IStringTesting
{
string ConcatStrings(string left, string right);
}

[ComImport]
[Guid("939D4EE5-8D41-4C4B-8948-86017CEB9244")]
[WindowsRuntimeImport]
public interface INullableTesting
{
bool IsNull(int? value);
int GetIntValue(int? value);
}

[ComImport]
[Guid("BB545A14-9AE7-491A-874D-1C03D239FB70")]
[WindowsRuntimeImport]
public interface ITypeTesting
{
string GetTypeName(Type type);
}

[ComImport]
[Guid("9162201d-b591-4f30-8f41-f0f79f6ecea3")]
[WindowsRuntimeImport]
public interface IExceptionTesting
{
void ThrowException(Exception ex);
Exception GetException(int hResultToReturn);
}

[ComImport]
[Guid("ccd10099-3a45-4382-970d-b76f52780bcd")]
[WindowsRuntimeImport]
public interface IKeyValuePairTesting
{
KeyValuePair<int, int> MakeSimplePair(int key, int value);
KeyValuePair<string, string> MakeMarshaledPair(string key, string value);
KeyValuePair<int, IEnumerable<int>> MakeProjectedPair(int key, int[] values);
}

[ComImport]
[Guid("e0af24b3-e6c6-4e89-b8d1-a332979ef398")]
[WindowsRuntimeImport]
public interface IUriTesting
{
string GetFromUri(Uri uri);
Uri CreateUriFromString(string uri);
}

[ComImport]
[Guid("821B532D-CC5E-4218-90AB-A8361AC92794")]
[WindowsRuntimeImport]
public interface IArrayTesting
{
int Sum(int[] array);
bool Xor(bool[] array);
}

[ComImport]
[Guid("4bb923ae-986a-4aad-9bfb-13e0b5ecffa4")]
[WindowsRuntimeImport]
public interface IBindingViewModel
{
INotifyCollectionChanged Collection { get; }
void AddElement(int i);
string Name { get; set; }
}

[ComImport]
[Guid("857e28e1-3e7f-4f6f-8554-efc73feba286")]
[WindowsRuntimeImport]
public interface IBindingProjectionsTesting
{
IBindingViewModel CreateViewModel();
IDisposable InitializeXamlFrameworkForCurrentThread();
}

public enum TestEnum
{
A = 1,
B = 2,
C = 3
}

[ComImport]
[Guid("d89d71b2-2671-444d-8576-536d206dea49")]
[WindowsRuntimeImport]
public interface IEnumTesting
{
TestEnum GetA();
Boolean IsB(TestEnum val);
}
}
104 changes: 104 additions & 0 deletions tests/src/Interop/WinRT/Contracts/Component.Contracts.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace Component.Contracts
{
[interface_name("Component.Contracts.IBooleanTesting", 971AF13A-9793-4AF7-B2F2-72D829195592)]
runtimeclass BooleanTesting
{
BooleanTesting();
Boolean And(Boolean left, Boolean right);
}

[interface_name("Component.Contracts.IStringTesting", C6F1F632-47B6-4A52-86D2-A89807ED2677)]
runtimeclass StringTesting
{
StringTesting();
String ConcatStrings(String left, String right);
}

[interface_name("Component.Contracts.INullableTesting", 939D4EE5-8D41-4C4B-8948-86017CEB9244)]
runtimeclass NullableTesting
{
NullableTesting();
Boolean IsNull(Windows.Foundation.IReference<Int32> value);
Int32 GetIntValue(Windows.Foundation.IReference<Int32> value);
}

[interface_name("Component.Contracts.ITypeTesting", BB545A14-9AE7-491A-874D-1C03D239FB70)]
runtimeclass TypeTesting
{
TypeTesting();
String GetTypeName(Windows.UI.Xaml.Interop.TypeName typeName);
}

[interface_name("Component.Contracts.IExceptionTesting", 9162201d-b591-4f30-8f41-f0f79f6ecea3)]
runtimeclass ExceptionTesting
{
ExceptionTesting();
void ThrowException(Windows.Foundation.HResult hr);
Windows.Foundation.HResult GetException(Int32 hr);
}

[interface_name("Component.Contracts.IKeyValuePairTesting", ccd10099-3a45-4382-970d-b76f52780bcd)]
runtimeclass KeyValuePairTesting
{
KeyValuePairTesting();
Windows.Foundation.Collections.IKeyValuePair<Int32, Int32> MakeSimplePair(Int32 key, Int32 value);
Windows.Foundation.Collections.IKeyValuePair<String, String> MakeMarshaledPair(String key, String value);
Windows.Foundation.Collections.IKeyValuePair<Int32, Windows.Foundation.Collections.IIterable<Int32> > MakeProjectedPair(Int32 key, Int32[] values);
}

[interface_name("Component.Contracts.IUriTesting", e0af24b3-e6c6-4e89-b8d1-a332979ef398)]
runtimeclass UriTesting
{
UriTesting();
String GetFromUri(Windows.Foundation.Uri uri);
Windows.Foundation.Uri CreateUriFromString(String uri);
}

[interface_name("Component.Contracts.IArrayTesting", 821B532D-CC5E-4218-90AB-A8361AC92794)]
runtimeclass ArrayTesting
{
ArrayTesting();
Int32 Sum(Int32[] array);
Boolean Xor(Boolean[] array);
}

[uuid(4bb923ae-986a-4aad-9bfb-13e0b5ecffa4)]
interface IBindingViewModel
{
Windows.UI.Xaml.Interop.INotifyCollectionChanged Collection { get; };
void AddElement(Int32 i);
String Name { get; set; };
}

runtimeclass BindingViewModel : [default] IBindingViewModel, Windows.UI.Xaml.Data.INotifyPropertyChanged
{
BindingViewModel();
}

[interface_name("Component.Contracts.IBindingProjectionsTesting", 857e28e1-3e7f-4f6f-8554-efc73feba286)]
runtimeclass BindingProjectionsTesting
{
BindingProjectionsTesting();
IBindingViewModel CreateViewModel();
Windows.Foundation.IClosable InitializeXamlFrameworkForCurrentThread();
}

enum TestEnum
{
A = 1,
B = 2,
C = 3
};

[interface_name("Component.Contracts.IEnumTesting", d89d71b2-2671-444d-8576-536d206dea49)]
runtimeclass EnumTesting
{
EnumTesting();
TestEnum GetA();
Boolean IsB(TestEnum val);
}
}
16 changes: 16 additions & 0 deletions tests/src/Interop/WinRT/Contracts/NativeComponent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;

public static class WinRTNativeComponent
{
[DllImport(nameof(WinRTNativeComponent), PreserveSig = false)]
private static extern IActivationFactory DllGetActivationFactory([MarshalAs(UnmanagedType.HString)] string typeName);

public static object GetObjectFromNativeComponent(string typeName)
{
return DllGetActivationFactory(typeName).ActivateInstance();
}
}
13 changes: 13 additions & 0 deletions tests/src/Interop/WinRT/Contracts/WindowsRuntimeImportAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace System.Runtime.InteropServices.WindowsRuntime
{
// Types decorated with this attribute are treated specially by the compiler. A "windowsruntime" bit is set in their metadata.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface | AttributeTargets.Enum | AttributeTargets.Struct | AttributeTargets.Delegate, Inherited = false)]
internal sealed class WindowsRuntimeImportAttribute : Attribute
{
public WindowsRuntimeImportAttribute() { }
}
}
Loading

0 comments on commit 6a2c6a4

Please sign in to comment.