Skip to content

Commit

Permalink
Authoring support for C# built-in types to WinRT types (#631)
Browse files Browse the repository at this point in the history
* Initial custom type mapping support and bug fixes.

* Bug fixes.

* Custom type mappings and various fixes.

* Fix file paths.

* Fix merge.

* PR feedback.

* PR feedback.

* PR feedback.

* Disable test temporarily.
  • Loading branch information
manodasanW committed Dec 17, 2020
1 parent b89f261 commit 69e9264
Show file tree
Hide file tree
Showing 14 changed files with 4,496 additions and 3,267 deletions.
3 changes: 3 additions & 0 deletions nuget/Microsoft.Windows.CsWinRT.targets
Expand Up @@ -112,6 +112,9 @@ $(CsWinRTFilters)
<CompilerVisibleProperty Include="CsWinRTEnableLogging" />
<CompilerVisibleProperty Include="GeneratedFilesDir" />
<CompilerVisibleProperty Include="CsWinRTExe" />
<CompilerVisibleProperty Include="CsWinRTKeepGeneratedSources" />
<CompilerVisibleProperty Include="CsWinRTWindowsMetadata" />
<CompilerVisibleProperty Include="CsWinRTGenerateProjection" />
</ItemGroup>

<Import Project="$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.Prerelease.targets" Condition="Exists('$(MSBuildThisFileDirectory)Microsoft.Windows.CsWinRT.Prerelease.targets')"/>
Expand Down
@@ -1,18 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="CppTestApp"/>
<file name="WinRT.Host.dll">
<activatableClass
name="AuthoringSample.BasicClass"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringSample.CustomWWW"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringSample.TestClass"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
</file>
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="CppTestApp"/>
<file name="WinRT.Host.dll">
<activatableClass
name="AuthoringSample.BasicClass"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringSample.CustomDictionary"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringSample.CustomReadOnlyDictionary"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringSample.CustomVector"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringSample.CustomVectorView"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringSample.CustomWWW"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringSample.DisposableClass"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
<activatableClass
name="AuthoringSample.TestClass"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1" />
</file>
</assembly>
310 changes: 155 additions & 155 deletions src/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions src/Authoring/AuthoringConsumptionTest/packages.config
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn" version="1.8.1.3" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.200703.9" targetFramework="native" />
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn" version="1.8.1.3" targetFramework="native" />
<package id="Microsoft.Windows.CppWinRT" version="2.0.201113.7" targetFramework="native" />
</packages>
218 changes: 218 additions & 0 deletions src/Authoring/AuthoringConsumptionTest/test.cpp
Expand Up @@ -170,4 +170,222 @@ TEST(AuthoringTest, CCWCaching)
EXPECT_EQ(copy.GetBasicEnum(), BasicEnum::Second);
EXPECT_EQ(copy.GetFlagsEnum(), FlagsEnum::Fourth);
EXPECT_EQ(basicClass, copy);
}

IAsyncOperation<int32_t> GetIntAsync(int num)
{
co_return num;
}

TEST(AuthoringTest, Arrays)
{
BasicClass basicClass;
EXPECT_EQ(basicClass.GetSum({2, 3, 4, 6}), 15);

com_array<int> arr(6);
basicClass.PopulateArray(arr);
for (int idx = 0; idx < arr.size(); idx++)
{
EXPECT_EQ(arr[idx], idx + 1);
}

com_array<int> arr2;
basicClass.GetArrayOfLength(10, arr2);
EXPECT_EQ(arr2.size(), 10);
for (int idx = 0; idx < arr2.size(); idx++)
{
EXPECT_EQ(arr2[idx], idx + 1);
}

std::array<BasicStruct, 2> basicStructArr;
basicStructArr[0] = basicClass.GetBasicStruct();
basicStructArr[1].X = 4;
basicStructArr[1].Y = 6;
basicStructArr[1].Value = L"WinRT";
auto result = basicClass.ReturnArray(basicStructArr);
EXPECT_EQ(result.size(), 2);
EXPECT_EQ(result[0].X, basicStructArr[0].X);
EXPECT_EQ(result[0].Y, basicStructArr[0].Y);
EXPECT_EQ(result[0].Value, basicStructArr[0].Value);
EXPECT_EQ(result[1].X, basicStructArr[1].X);
EXPECT_EQ(result[1].Y, basicStructArr[1].Y);
EXPECT_EQ(result[1].Value, basicStructArr[1].Value);
}

TEST(AuthoringTest, CustomTypes)
{
BasicClass basicClass;

auto dateTime = basicClass.GetDate();
EXPECT_TRUE(dateTime.time_since_epoch().count() != 0);

auto now = winrt::clock::now();
basicClass.SetDate(now);
auto dateTime2 = basicClass.GetDate();
EXPECT_EQ(dateTime2, now);
EXPECT_TRUE(dateTime != dateTime2);

auto timeSpan = basicClass.GetTimespan();
EXPECT_EQ(timeSpan.count(), 100);

TestClass testClass;
testClass.SetProjectedDisposableObject();

testClass.DisposableObject().Close();
EXPECT_FALSE(testClass.DisposableClassObject().IsDisposed());
testClass.DisposableClassObject().Close();
EXPECT_TRUE(testClass.DisposableClassObject().IsDisposed());

testClass.SetNonProjectedDisposableObject();
testClass.DisposableObject().Close();

testClass.IntAsyncOperation(GetIntAsync(24));
EXPECT_EQ(testClass.GetIntAsyncOperation().get(), 24);
testClass.SetIntAsyncOperation(GetIntAsync(50));

auto vector = winrt::single_threaded_vector(std::vector<IInspectable>{ winrt::box_value(0), winrt::box_value(1), winrt::box_value(2) });
testClass.ObjectList(vector);
EXPECT_EQ(testClass.GetObjectListSum(), 3);

auto disposableObjects = testClass.GetDisposableObjects();
EXPECT_EQ(disposableObjects.Size(), 3);
for(auto obj : disposableObjects)
{
obj.Close();
}

for (auto uri : TestClass::GetUris())
{
EXPECT_NE(uri, nullptr);
}
EXPECT_EQ(TestClass::GetUris().Size(), 2);
EXPECT_NE(TestClass::GetUris().First(), nullptr);

testClass.SetTypeToTestClass();
auto type = testClass.Type();
EXPECT_EQ(type.Kind, Windows::UI::Xaml::Interop::TypeKind::Metadata);
EXPECT_EQ(type.Name, L"AuthoringSample.TestClass");
}

TEST(AuthoringTest, CustomDictionaryImplementations)
{
CustomDictionary dictionary;

BasicStruct basicStruct{1, 2};
BasicStruct basicStruct2{ 2, 2 };
BasicStruct basicStruct3{ 3, 3 };
EXPECT_FALSE(dictionary.Insert(L"first", basicStruct));
EXPECT_FALSE(dictionary.Insert(L"second", basicStruct3));
EXPECT_TRUE(dictionary.Insert(L"second", basicStruct2));
EXPECT_FALSE(dictionary.Insert(L"third", basicStruct3));
EXPECT_EQ(dictionary.Size(), 3);

EXPECT_TRUE(dictionary.HasKey(L"first"));
EXPECT_FALSE(dictionary.HasKey(L"fourth"));
EXPECT_TRUE(dictionary.HasKey(L"third"));

hstring keys[] = {L"first", L"second", L"third" };
BasicStruct values[] = { basicStruct, basicStruct2, basicStruct3 };
int idx = 0;
for (auto entry : dictionary)
{
EXPECT_EQ(entry.Key(), keys[idx]);
EXPECT_EQ(entry.Value(), values[idx]);
idx++;
}
EXPECT_EQ(idx, 3);

idx = 0;
for (auto entry : dictionary.GetView())
{
EXPECT_EQ(entry.Key(), keys[idx]);
EXPECT_EQ(entry.Value(), values[idx]);
idx++;
}
EXPECT_EQ(idx, 3);

EXPECT_EQ(dictionary.GetView().TryLookup(L"second").value(), basicStruct2);
EXPECT_FALSE(dictionary.GetView().TryLookup(L"fourth").has_value());

// TODO: Broken due to ALC type mismatch.
/*
TestClass testClass;
EXPECT_EQ(testClass.GetSum(dictionary, L"second"), 4);
CustomReadOnlyDictionary readOnlyDictionary(dictionary);
EXPECT_TRUE(readOnlyDictionary.HasKey(L"first"));
EXPECT_FALSE(readOnlyDictionary.HasKey(L"fourth"));
EXPECT_TRUE(readOnlyDictionary.HasKey(L"third"));
EXPECT_EQ(readOnlyDictionary.Size(), 3);
EXPECT_EQ(readOnlyDictionary.TryLookup(L"second").value(), basicStruct2);
EXPECT_FALSE(readOnlyDictionary.TryLookup(L"fourth").has_value());
Windows::Foundation::Collections::IMapView<hstring, AuthoringSample::BasicStruct> mapSplit1, mapSplit2;
readOnlyDictionary.Split(mapSplit1, mapSplit2);
EXPECT_NE(mapSplit1, nullptr);
EXPECT_NE(mapSplit2, nullptr);
EXPECT_TRUE(mapSplit1.HasKey(L"first"));
EXPECT_FALSE(mapSplit1.HasKey(L"third"));
EXPECT_TRUE(mapSplit2.HasKey(L"third"));
*/

Windows::Foundation::Collections::IMap<hstring, AuthoringSample::BasicStruct> map = dictionary;
map.Clear();
EXPECT_EQ(map.Size(), 0);
}

// TODO: Broken due to ALC type mismatch.
TEST(AuthoringTest, DISABLED_CustomVectorImplementations)
{
TestClass testClass;
testClass.SetProjectedDisposableObject();
DisposableClass disposed;
disposed.Close();

CustomVector vector;
EXPECT_EQ(vector.Size(), 0);
vector.Append(DisposableClass());
vector.Append(DisposableClass());
vector.Append(testClass.DisposableClassObject());
vector.Append(disposed);
EXPECT_EQ(vector.Size(), 4);

auto first = vector.First();
EXPECT_TRUE(first.HasCurrent());
EXPECT_FALSE(first.Current().IsDisposed());
first.Current().Close();
EXPECT_TRUE(first.Current().IsDisposed());
EXPECT_FALSE(vector.GetAt(2).IsDisposed());
EXPECT_TRUE(vector.GetAt(3).IsDisposed());
for (auto obj : vector.GetView())
{
obj.Close();
}
EXPECT_TRUE(vector.GetAt(3).IsDisposed());

std::array<DisposableClass, 2> view{};
EXPECT_EQ(vector.GetMany(2, view), 2);
EXPECT_EQ(view.size(), 2);
for (auto &obj : view)
{
EXPECT_TRUE(obj.IsDisposed());
}

CustomVectorView vectorView(vector);
EXPECT_EQ(vectorView.Size(), 4);
auto firstView = vectorView.First();
EXPECT_TRUE(firstView.HasCurrent());
EXPECT_TRUE(firstView.Current().IsDisposed());
firstView.Current().Close();
EXPECT_TRUE(vectorView.GetAt(2).IsDisposed());
EXPECT_TRUE(vectorView.GetAt(3).IsDisposed());
uint32_t index = 0;
EXPECT_TRUE(vectorView.IndexOf(disposed, index));
EXPECT_EQ(index, 3);
EXPECT_TRUE(vectorView.IndexOf(testClass.DisposableClassObject(), index));
EXPECT_EQ(index, 2);

vector.Clear();
EXPECT_EQ(vector.Size(), 0);
}
51 changes: 23 additions & 28 deletions src/Authoring/AuthoringSample/AuthoringSample.csproj
@@ -1,28 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<Platforms>x64;x86</Platforms>
<LangVersion>preview</LangVersion>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<CsWinRTEnableLogging>true</CsWinRTEnableLogging>
<CsWinRTComponent>true</CsWinRTComponent>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GeneratedFilesDir Condition="'$(GeneratedFilesDir)'==''">$([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)', '$(IntermediateOutputPath)', 'Generated Files'))</GeneratedFilesDir>
</PropertyGroup>

<ItemGroup>
<CompilerVisibleProperty Include="AssemblyName" />
<CompilerVisibleProperty Include="AssemblyVersion" />
<CompilerVisibleProperty Include="CsWinRTComponent" />
<CompilerVisibleProperty Include="CsWinRTEnableLogging" />
<CompilerVisibleProperty Include="GeneratedFilesDir" />
<CompilerVisibleProperty Include="CsWinRTExe" />

<ProjectReference Include="..\..\Projections\Windows\Windows.csproj" />
<ProjectReference Include="..\WinRT.SourceGenerator\WinRT.SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\..\cswinrt\cswinrt.vcxproj" />
<ProjectReference Include="..\..\WinRT.Runtime\WinRT.Runtime.csproj" />
</ItemGroup>

</Project>
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<Platforms>x64;x86</Platforms>
<LangVersion>preview</LangVersion>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<CsWinRTEnableLogging>true</CsWinRTEnableLogging>
<CsWinRTComponent>true</CsWinRTComponent>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GeneratedFilesDir Condition="'$(GeneratedFilesDir)'==''">$([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)', '$(IntermediateOutputPath)', 'Generated Files'))</GeneratedFilesDir>
<!-- Enable to diagnose generation issues -->
<!-- <CsWinRTKeepGeneratedSources>true</CsWinRTKeepGeneratedSources> -->
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Projections\Windows\Windows.csproj" />
<ProjectReference Include="..\WinRT.SourceGenerator\WinRT.SourceGenerator.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\..\cswinrt\cswinrt.vcxproj" />
<ProjectReference Include="..\..\WinRT.Runtime\WinRT.Runtime.csproj" />
</ItemGroup>

</Project>

0 comments on commit 69e9264

Please sign in to comment.