diff --git a/README.md b/README.md index 3d7638b4a..c76016a40 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ WinRT APIs are defined in `*.winmd` format, and C#/WinRT includes tooling that g Component Authors need to build a C#/WinRT projection for .NET5+ targets. Creating projection ### Application Developers @@ -21,7 +21,7 @@ Component Authors need to build a C#/WinRT projection for .NET5+ targets. .NET5+ apps reference the NuGet package, which pulls in the projection assembly instead of a winmd. Adding projection ## Motivation @@ -57,7 +57,7 @@ The `build.cmd` script takes care of all related configuration steps and is the ## Developer Guidance -Please read the [usage](USAGE.md) and [repository structure](STRUCTURE.md) docs for a detailed breakdown. For recommendations on migrating from System.Runtime.InteropServices, see the [COM Interop](docs/interop.md) guide. For additional documentation visit . +Please read the [usage](docs/usage.md) and [repository structure](docs/structure.md) docs for a detailed breakdown. For recommendations on migrating from System.Runtime.InteropServices, see the [COM Interop](docs/interop.md) guide. For additional documentation visit . ## Related Projects diff --git a/Diagram_AddProjection.jpg b/docs/images/Diagram_AddProjection.jpg similarity index 100% rename from Diagram_AddProjection.jpg rename to docs/images/Diagram_AddProjection.jpg diff --git a/Diagram_CreateProjection.jpg b/docs/images/Diagram_CreateProjection.jpg similarity index 100% rename from Diagram_CreateProjection.jpg rename to docs/images/Diagram_CreateProjection.jpg diff --git a/STRUCTURE.md b/docs/structure.md similarity index 62% rename from STRUCTURE.md rename to docs/structure.md index ff8429817..0be7d3f7b 100644 --- a/STRUCTURE.md +++ b/docs/structure.md @@ -1,45 +1,55 @@ -# Repository Structure - -## The [`cswinrt`](/cswinrt) folder - -Contains the sources and cswinrt.vcxproj project file for building the C#/WinRT compiler, cswinrt.exe. The projection's base library is contained in /cswinrt/strings/WinRT.cs, which is processed by /strings.props to generate string literals contained in the compiler. - -The compiler uses the [WinMD NuGet package](http://aka.ms/winmd/nuget) for parsing [ECMA-335 metadata](http://www.ecma-international.org/publications/standards/Ecma-335.htm) files. The WinMD github repo includes a [winmd.natvis](https://github.com/microsoft/winmd/blob/master/vs/winmd.natvis) script for debugging metadata parsing. A symlink can be used to install the script: - > for /f "tokens=2*" %i in ('reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Personal ^| findstr Personal') do @for /f "tokens=2" %k in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest ^| findstr catalog_productLineVersion') do @echo %j\Visual Studio %k\Visualizers| for /f "delims=" %l in ('more') do @md "%l" 2>nul & mklink "%l\winmd.natvis" "c:\git\winmd\vs\winmd.natvis" - -The C#/WinRT project also contains a cswinrt.natvis script for debugging the C# projection writing, which can also be installed with a symlink: -> for /f "tokens=2*" %i in ('reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Personal ^| findstr Personal') do @for /f "tokens=2" %k in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest ^| findstr catalog_productLineVersion') do @echo %j\Visual Studio %k\Visualizers| for /f "delims=" %l in ('more') do @md "%l" 2>nul & mklink "%l\cswinrt.natvis" "c:\git\cswinrt\cswinrt\cswinrt.natvis" - -See also [Deploying .natvis files](https://docs.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2015#BKMK_natvis_location). - -## The [`WinRT.Runtime`](/WinRT.Runtime) folder - -Contains the WinRT.Runtime project for building the C#/WinRT runtime assembly, winrt.runtime.dll. There are two versions of this assembly, providing an abstraction layer over both .NET Standard 2.0 and .NET 5 runtimes. While all code generated by cswinrt.exe is compatible with .NET Standard 2.0, there are runtime differences which must be addressed. The primary difference is that the .NET 5 winrt.runtime.dll provides Xaml reference tracking support, which is necessary for WinUI 3 applications to manage memory correctly. Future performance enhancements, such as function pointer support, may also be limited to the .NET 5 winrt.runtime.dll. - -## The [`nuget`](/nuget) folder - -Contains source files for producing a C#/WinRT NuGet package, which is regularly built, signed, and published to nuget.org by Microsoft. The C#/WinRT NuGet package contains the cswinrt.exe compiler, and both versions of the winrt.runtime.dll. - -## [`TestWinRT`](https://github.com/microsoft/TestWinRT/) - -C#/WinRT makes use of the standalone [TestWinRT](https://github.com/microsoft/TestWinRT/) repository for general language projection test coverage. This repo should be cloned into the root of the C#/WinRT repo, via **get_testwinrt.cmd**, so that the cswinrt.sln can resolve its reference to TestComponent.vcxproj. The resulting TestComponent.dll and TestComponent.winmd files are consumed by the UnitTest project above. - -## The [`TestComponentCSharp`](/TestComponentCSharp) folder - -Contains an implementation of a WinRT test component, defined in class.idl and used by the UnitTest project. To complement the general TestComponent above, the TestComponentCSharp tests scenarios specific to the C#/WinRT language projection. - -## The [`Projections`](/Projections) folder - -Contains several projects for generating and building projections from the Windows SDK, WinUI, Benchmark (produced by the BenchmarkComponent project), and Test metadata (produced by the TestWinRT and TestComponentCSharp projects). - -## The [`UnitTest`](/UnitTest) folder - -Contains unit tests for validating the Windows SDK, WinUI, and Test projections generated above. All pull requests should ensure that this project executes without errors. - -## The [`Benchmarks`](/Benchmarks) folder - -Contains benchmarks written using BenchmarkDotNet to track the performance of scenarios in the generated projection. To run the benchmarks using the CsWinRT projection, run **benchmark.cmd**. To run the same benchmarks using the built-in WinMD support in NET Core 3.1 to compare against as a baseline, run **benchmark_winmd.cmd**. - -## The [`WinUIDesktopSample`](/WinUIDesktopSample) folder - -Contains an end-to-end sample app that uses the Windows SDK and WinUI projections generated above. \ No newline at end of file +# Repository Structure + +This document describes the CsWinRT repository organization. Documentation and specs are located in the [`/docs`](.) folder. All source code for CsWinRT is located in the [`/src`](../src) folder, and files for generating the NuGet package are located in [`/nuget`](../nuget). + +## [`nuget`](../nuget) + +Contains source files for producing a C#/WinRT NuGet package, which is regularly built, signed, and published to nuget.org by Microsoft. The C#/WinRT NuGet package contains the cswinrt.exe compiler, and both versions of the winrt.runtime.dll. + +## [`src/Authoring`](../src/Authoring) + +Contains projects for implementing authoring and hosting support. + +## [`src/Benchmarks`](../src/Benchmarks) + +Contains benchmarks written using BenchmarkDotNet to track the performance of scenarios in the generated projection. To run the benchmarks using the CsWinRT projection, run **benchmark.cmd**. To run the same benchmarks using the built-in WinMD support in NET Core 3.1 to compare against as a baseline, run **benchmark_winmd.cmd**. + +## [`src/cswinrt`](../src/cswinrt) + +Contains the sources and cswinrt.vcxproj project file for building the C#/WinRT compiler, cswinrt.exe. The projection's base library is contained in /cswinrt/strings/WinRT.cs, which is processed by /strings.props to generate string literals contained in the compiler. + +The compiler uses the [WinMD NuGet package](http://aka.ms/winmd/nuget) for parsing [ECMA-335 metadata](http://www.ecma-international.org/publications/standards/Ecma-335.htm) files. The WinMD github repo includes a [winmd.natvis](https://github.com/microsoft/winmd/blob/master/vs/winmd.natvis) script for debugging metadata parsing. A symlink can be used to install the script: + > for /f "tokens=2*" %i in ('reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Personal ^| findstr Personal') do @for /f "tokens=2" %k in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest ^| findstr catalog_productLineVersion') do @echo %j\Visual Studio %k\Visualizers| for /f "delims=" %l in ('more') do @md "%l" 2>nul & mklink "%l\winmd.natvis" "c:\git\winmd\vs\winmd.natvis" + +The C#/WinRT project also contains a cswinrt.natvis script for debugging the C# projection writing, which can also be installed with a symlink: +> for /f "tokens=2*" %i in ('reg query "HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders" /v Personal ^| findstr Personal') do @for /f "tokens=2" %k in ('"%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest ^| findstr catalog_productLineVersion') do @echo %j\Visual Studio %k\Visualizers| for /f "delims=" %l in ('more') do @md "%l" 2>nul & mklink "%l\cswinrt.natvis" "c:\git\cswinrt\cswinrt\cswinrt.natvis" + +See also [Deploying .natvis files](https://docs.microsoft.com/en-us/visualstudio/debugger/create-custom-views-of-native-objects?view=vs-2015#BKMK_natvis_location). + +## [`src/Projections`](../src/Projections) + +Contains several projects for generating and building projections from the Windows SDK, WinUI, Benchmark (produced by the BenchmarkComponent project), and Test metadata (produced by the TestWinRT and TestComponentCSharp projects). + +## [`src/Samples`](../src/Samples) + +- [`Net5ProjectionSample`](../src/Samples/Net5ProjectionSample): Contains an end-to-end sample for component authors, showing how to generate a projection from a C++/WinRT component and consume it using a NuGet package. + +- [`WinUIDesktopSample`](../src/Samples/WinUIDesktopSample): Contains an end-to-end sample app that uses the Windows SDK and WinUI projections generated above. + +## [`src/Tests`](../src/Tests) + +Contains various testing-related projects: + +- [`TestComponentCSharp`](../src/Tests/TestComponentCSharp): This is an implementation of a WinRT test component, defined in class.idl and used by the UnitTest project. To complement the general TestComponent above, the TestComponentCSharp tests scenarios specific to the C#/WinRT language projection. + +- [`UnitTest`](../src/Tests/UnitTest): Unit tests for validating the Windows SDK, WinUI, and Test projections generated above. All pull requests should ensure that this project executes without errors. + +- [`HostTest`](../src/Tests/HostTest): Unit tests for WinRT.Host.dll, which provides hosting for runtime components written in C#. + +## [`src/TestWinRT`](https://github.com/microsoft/TestWinRT/) + +C#/WinRT makes use of the standalone [TestWinRT](https://github.com/microsoft/TestWinRT/) repository for general language projection test coverage. This repo is cloned via **get_testwinrt.cmd** into the `src` folder, so that the cswinrt.sln can resolve its reference to TestComponent.vcxproj. The resulting `TestComponent` and `BenchmarkComponent` files are consumed by the UnitTest and Benchmarks projects above. + +## [`src/WinRT.Runtime`](../src/WinRT.Runtime) + +Contains the WinRT.Runtime project for building the C#/WinRT runtime assembly, winrt.runtime.dll. There are two versions of this assembly, providing an abstraction layer over both .NET Standard 2.0 and .NET 5 runtimes. While all code generated by cswinrt.exe is compatible with .NET Standard 2.0, there are runtime differences which must be addressed. The primary difference is that the .NET 5 winrt.runtime.dll provides Xaml reference tracking support, which is necessary for WinUI 3 applications to manage memory correctly. Future performance enhancements, such as function pointer support, may also be limited to the .NET 5 winrt.runtime.dll. \ No newline at end of file diff --git a/USAGE.md b/docs/usage.md similarity index 94% rename from USAGE.md rename to docs/usage.md index 6309e03bb..a90609830 100644 --- a/USAGE.md +++ b/docs/usage.md @@ -1,21 +1,21 @@ -# Usage - -## Component Project - -A component project adds a NuGet reference to C#/WinRT to invoke cswinrt.exe at build time, generate projection sources, and compile these into an interop assembly. For an example of this, see the [Projection Sample](https://github.com/microsoft/CsWinRT/tree/master/Samples/Net5ProjectionSample). Command line options can be displayed by running **cswinrt -?**. The interop assembly is then typically distributed as a NuGet package itself. - -### Example - -To invoke cswinrt to generate projection sources for types in the **Contoso** namespace, you need to add the following property to your C# library project file. In this project you would also need to reference the CsWinRT NuGet package and the project-specific `winmd` files you want to project, whether through a NuGet package, project reference or direct reference. By default, the **Windows** and **Microsoft** namespaces are not projected. - -``` - - Contoso - -``` - -To further customize C#/WinRT behavior, refer to the [CsWinRT NuGet documentation](https://github.com/microsoft/CsWinRT/blob/master/nuget/readme.md). - -## Application Project - -An application project adds NuGet references to both the component interop assembly produced above and to CsWinRT to include the `winrt.runtime.dll` assembly. If the interop assembly is distributed as a NuGet package itself, this package will require a dependency on C#/WinRT for .NET5 targets. If a third party WinRT component is distributed without an official interop assembly, an application project may add a reference to C#/WinRT to generate its own private component interop assembly. There are versioning concerns related to this scenario, so the preferred solution is for the third party to publish an interop assembly directly. +# Usage + +## Component Project + +A component project adds a NuGet reference to C#/WinRT to invoke cswinrt.exe at build time, generate projection sources, and compile these into an interop assembly. For an example of this, see the [Projection Sample](https://github.com/microsoft/CsWinRT/tree/master/Samples/Net5ProjectionSample). Command line options can be displayed by running **cswinrt -?**. The interop assembly is then typically distributed as a NuGet package itself. + +### Example + +To invoke cswinrt to generate projection sources for types in the **Contoso** namespace, you need to add the following property to your C# library project file. In this project you would also need to reference the CsWinRT NuGet package and the project-specific `winmd` files you want to project, whether through a NuGet package, project reference or direct reference. By default, the **Windows** and **Microsoft** namespaces are not projected. + +``` + + Contoso + +``` + +To further customize C#/WinRT behavior, refer to the [CsWinRT NuGet documentation](../nuget/readme.md). + +## Application Project + +An application project adds NuGet references to both the component interop assembly produced above and to CsWinRT to include the `winrt.runtime.dll` assembly. If the interop assembly is distributed as a NuGet package itself, this package will require a dependency on C#/WinRT for .NET5 targets. If a third party WinRT component is distributed without an official interop assembly, an application project may add a reference to C#/WinRT to generate its own private component interop assembly. There are versioning concerns related to this scenario, so the preferred solution is for the third party to publish an interop assembly directly. diff --git a/nuget/Microsoft.Windows.CsWinRT.targets b/nuget/Microsoft.Windows.CsWinRT.targets index 103d8f5b6..e9497afe4 100644 --- a/nuget/Microsoft.Windows.CsWinRT.targets +++ b/nuget/Microsoft.Windows.CsWinRT.targets @@ -1,118 +1,118 @@ - - - - - normal - -verbose - $(ResolveAssemblyReferencesDependsOn);CsWinRTRemoveWindowsReference - true - false - false - true - true - true - CsWinRTIncludeProjection;CsWinRTRemoveWinMDReferences;$(CoreCompileDependsOn) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - $(GeneratedFilesDir) - $([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)', '$(IntermediateOutputPath)', 'Generated Files')) - - - - - - $(CsWinRTGeneratedFilesDir)cswinrt.rsp - "$(CsWinRTExe)" %40"$(CsWinRTResponseFile)" - $(WindowsSDKVersion.TrimEnd('\')) - -input $(CsWinRTWindowsMetadata) - - - - - - - - Windows;Microsoft - - - - - - - -@(CsWinRTExcludeItems->'-exclude %(Identity)', ' ') -@(CsWinRTIncludeItems->'-include %(Identity)', ' ') - - -$(CsWinRTCommandVerbosity) --target $(TargetFramework) -$(CsWinRTWindowsMetadataInput) --input @(CsWinRTInputs->'"%(FullPath)"', ' ') --output "$(CsWinRTGeneratedFilesDir.TrimEnd('\'))" -$(CsWinRTFilters) - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + normal + -verbose + $(ResolveAssemblyReferencesDependsOn);CsWinRTRemoveWindowsReference + true + false + false + true + true + true + CsWinRTIncludeProjection;CsWinRTRemoveWinMDReferences;$(CoreCompileDependsOn) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $(GeneratedFilesDir) + $([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)', '$(IntermediateOutputPath)', 'Generated Files')) + + + + + + $(CsWinRTGeneratedFilesDir)cswinrt.rsp + "$(CsWinRTExe)" %40"$(CsWinRTResponseFile)" + $(WindowsSDKVersion.TrimEnd('\')) + -input $(CsWinRTWindowsMetadata) + + + + + + + + Windows;Microsoft + + + + + + + +@(CsWinRTExcludeItems->'-exclude %(Identity)', ' ') +@(CsWinRTIncludeItems->'-include %(Identity)', ' ') + + +$(CsWinRTCommandVerbosity) +-target $(TargetFramework) +$(CsWinRTWindowsMetadataInput) +-input @(CsWinRTInputs->'"%(FullPath)"', ' ') +-output "$(CsWinRTGeneratedFilesDir.TrimEnd('\'))" +$(CsWinRTFilters) + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.exe.manifest b/src/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.exe.manifest similarity index 97% rename from Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.exe.manifest rename to src/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.exe.manifest index 547907221..4fc008805 100644 --- a/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.exe.manifest +++ b/src/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.exe.manifest @@ -1,18 +1,18 @@ - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj b/src/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj similarity index 96% rename from Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj rename to src/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj index b5a119db1..8634016a5 100644 --- a/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj +++ b/src/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj @@ -1,157 +1,157 @@ - - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {0212a7c5-8d3f-443c-9ebc-1f28091fdf88} - Win32Proj - AuthoringConsumptionTest - 10.0.19592.0 - Application - v142 - Unicode - <_WinMDPlatform>$(Platform) - <_WinMDPlatform Condition="'$(Platform)' == 'Win32'">x86 - - - - - - - - - - - - - - Create - - - - - - - true - true - - - - - {ffa9a78b-f53f-43ee-af87-24a80f4c330a} - - - {0bb8f82d-874e-45aa-bca3-20ce0562164a} - - - {7e33bcb7-19c5-4061-981d-ba695322708a} - - - {25244ced-966e-45f2-9711-1f51e951ff89} - - - {41e2a272-150f-42f5-ad40-047aad9088a0} - - - - - ..\AuthoringSample\bin\$(_WinMDPlatform)\$(Configuration)\net5.0\AuthoringSample.winmd - true - - - - - - - - - - - - - Use - pch.h - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebugDLL - Level3 - - - true - Console - - - - - Use - pch.h - Disabled - X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - EnableFastChecks - MultiThreadedDebugDLL - Level3 - - - DebugFull - Console - - - - - Use - pch.h - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - MultiThreadedDLL - Level3 - ProgramDatabase - - - true - Console - true - true - - - - - Use - pch.h - X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - MultiThreadedDLL - Level3 - ProgramDatabase - - - true - Console - true - true - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + {0212a7c5-8d3f-443c-9ebc-1f28091fdf88} + Win32Proj + AuthoringConsumptionTest + 10.0.19592.0 + Application + v142 + Unicode + <_WinMDPlatform>$(Platform) + <_WinMDPlatform Condition="'$(Platform)' == 'Win32'">x86 + + + + + + + + + + + + + + Create + + + + + + + true + true + + + + + {ffa9a78b-f53f-43ee-af87-24a80f4c330a} + + + {0bb8f82d-874e-45aa-bca3-20ce0562164a} + + + {7e33bcb7-19c5-4061-981d-ba695322708a} + + + {25244ced-966e-45f2-9711-1f51e951ff89} + + + {41e2a272-150f-42f5-ad40-047aad9088a0} + + + + + ..\AuthoringSample\bin\$(_WinMDPlatform)\$(Configuration)\net5.0\AuthoringSample.winmd + true + + + + + + + + + + + + + Use + pch.h + Disabled + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + true + Console + + + + + Use + pch.h + Disabled + X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebugDLL + Level3 + + + DebugFull + Console + + + + + Use + pch.h + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + + + true + Console + true + true + + + + + Use + pch.h + X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + ProgramDatabase + + + true + Console + true + true + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj.filters b/src/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj.filters similarity index 97% rename from Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj.filters rename to src/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj.filters index 61ec75b50..146a017e0 100644 --- a/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj.filters +++ b/src/Authoring/AuthoringConsumptionTest/AuthoringConsumptionTest.vcxproj.filters @@ -1,38 +1,38 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - - - Source Files - - - Source Files - - - - - - - - - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + + + Source Files + + + Source Files + + + + + + + + + + \ No newline at end of file diff --git a/Authoring/AuthoringConsumptionTest/Directory.Build.targets b/src/Authoring/AuthoringConsumptionTest/Directory.Build.targets similarity index 100% rename from Authoring/AuthoringConsumptionTest/Directory.Build.targets rename to src/Authoring/AuthoringConsumptionTest/Directory.Build.targets diff --git a/Authoring/AuthoringConsumptionTest/WinRT.Host.runtimeconfig.json b/src/Authoring/AuthoringConsumptionTest/WinRT.Host.runtimeconfig.json similarity index 95% rename from Authoring/AuthoringConsumptionTest/WinRT.Host.runtimeconfig.json rename to src/Authoring/AuthoringConsumptionTest/WinRT.Host.runtimeconfig.json index 93de5becd..41cab90c1 100644 --- a/Authoring/AuthoringConsumptionTest/WinRT.Host.runtimeconfig.json +++ b/src/Authoring/AuthoringConsumptionTest/WinRT.Host.runtimeconfig.json @@ -1,10 +1,10 @@ -{ - "runtimeOptions": { - "tfm": "net5.0", - "rollForward": "LatestMinor", - "framework": { - "name": "Microsoft.NETCore.App", - "version": "5.0.0-preview" - } - } +{ + "runtimeOptions": { + "tfm": "net5.0", + "rollForward": "LatestMinor", + "framework": { + "name": "Microsoft.NETCore.App", + "version": "5.0.0-preview" + } + } } \ No newline at end of file diff --git a/Authoring/AuthoringConsumptionTest/packages.config b/src/Authoring/AuthoringConsumptionTest/packages.config similarity index 98% rename from Authoring/AuthoringConsumptionTest/packages.config rename to src/Authoring/AuthoringConsumptionTest/packages.config index 5890a574e..1a73d6a2f 100644 --- a/Authoring/AuthoringConsumptionTest/packages.config +++ b/src/Authoring/AuthoringConsumptionTest/packages.config @@ -1,5 +1,5 @@ - - - - + + + + \ No newline at end of file diff --git a/Authoring/AuthoringConsumptionTest/pch.cpp b/src/Authoring/AuthoringConsumptionTest/pch.cpp similarity index 100% rename from Authoring/AuthoringConsumptionTest/pch.cpp rename to src/Authoring/AuthoringConsumptionTest/pch.cpp diff --git a/Authoring/AuthoringConsumptionTest/pch.h b/src/Authoring/AuthoringConsumptionTest/pch.h similarity index 100% rename from Authoring/AuthoringConsumptionTest/pch.h rename to src/Authoring/AuthoringConsumptionTest/pch.h diff --git a/Authoring/AuthoringConsumptionTest/test.cpp b/src/Authoring/AuthoringConsumptionTest/test.cpp similarity index 100% rename from Authoring/AuthoringConsumptionTest/test.cpp rename to src/Authoring/AuthoringConsumptionTest/test.cpp diff --git a/Authoring/AuthoringSample/AuthoringSample.csproj b/src/Authoring/AuthoringSample/AuthoringSample.csproj similarity index 97% rename from Authoring/AuthoringSample/AuthoringSample.csproj rename to src/Authoring/AuthoringSample/AuthoringSample.csproj index d2786592e..99287f733 100644 --- a/Authoring/AuthoringSample/AuthoringSample.csproj +++ b/src/Authoring/AuthoringSample/AuthoringSample.csproj @@ -1,28 +1,28 @@ - - - - net5.0 - x64;x86 - preview - 1.0.0.0 - true - true - true - $([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)', '$(IntermediateOutputPath)', 'Generated Files')) - - - - - - - - - - - - - - - - - + + + + net5.0 + x64;x86 + preview + 1.0.0.0 + true + true + true + $([MSBuild]::NormalizeDirectory('$(MSBuildProjectDirectory)', '$(IntermediateOutputPath)', 'Generated Files')) + + + + + + + + + + + + + + + + + diff --git a/Authoring/AuthoringSample/Directory.Build.props b/src/Authoring/AuthoringSample/Directory.Build.props similarity index 100% rename from Authoring/AuthoringSample/Directory.Build.props rename to src/Authoring/AuthoringSample/Directory.Build.props diff --git a/Authoring/AuthoringSample/Directory.Build.targets b/src/Authoring/AuthoringSample/Directory.Build.targets similarity index 100% rename from Authoring/AuthoringSample/Directory.Build.targets rename to src/Authoring/AuthoringSample/Directory.Build.targets diff --git a/Authoring/AuthoringSample/Program.cs b/src/Authoring/AuthoringSample/Program.cs similarity index 95% rename from Authoring/AuthoringSample/Program.cs rename to src/Authoring/AuthoringSample/Program.cs index de46e0aac..adef5309d 100644 --- a/Authoring/AuthoringSample/Program.cs +++ b/src/Authoring/AuthoringSample/Program.cs @@ -1,258 +1,258 @@ -using System; -using System.Reflection; -using Windows.Foundation; -using Windows.Foundation.Metadata; -using WinRT; - -namespace AuthoringSample -{ - public enum BasicEnum - { - First = -1, - Second = 0, - Third = 1, - Fourth - } - - [Flags] - public enum FlagsEnum : uint - { - First = 0, - Second = 1, - Third = 2, - Fourth = 4 - } - - internal enum PrivateEnum - { - PrivateFirst, - PrivateSecond - } - - public delegate void BasicDelegate(uint value); - public delegate bool ComplexDelegate(double value, int value2); - - public sealed class BasicClass - { - private BasicEnum basicEnum = BasicEnum.First; - private FlagsEnum flagsEnum = FlagsEnum.Second | FlagsEnum.Third; - - public event ComplexDelegate ComplexDelegateEvent; - private event ComplexDelegate ComplexDelegateEvent2; - - public Point GetPoint() - { - Point p = new Point - { - X = 2, - Y = 3 - }; - return p; - } - - public CustomWWW GetCustomWWW() - { - return new CustomWWW(); - } - - public BasicStruct GetBasicStruct() - { - BasicStruct basicStruct; - basicStruct.X = 4; - basicStruct.Y = 8; - basicStruct.Value = "CsWinRT"; - return basicStruct; - } - - public int GetSumOfInts(BasicStruct basicStruct) - { - return basicStruct.X + basicStruct.Y; - } - - public ComplexStruct GetComplexStruct() - { - ComplexStruct complexStruct; - complexStruct.X = 12; - complexStruct.Val = true; - complexStruct.BasicStruct = GetBasicStruct(); - return complexStruct; - } - - public int? GetX(ComplexStruct basicStruct) - { - return basicStruct.X; - } - - public void SetBasicEnum(BasicEnum basicEnum) - { - this.basicEnum = basicEnum; - } - - public BasicEnum GetBasicEnum() - { - return basicEnum; - } - - public void SetFlagsEnum(FlagsEnum flagsEnum) - { - this.flagsEnum = flagsEnum; - } - - public FlagsEnum GetFlagsEnum() - { - return flagsEnum; - } - - public BasicClass ReturnParameter(BasicClass basicClass) - { - return basicClass; - } - - private void PrivateFunction() - { - } - } - - public struct BasicStruct - { - public int X, Y; - public string Value; - } - - public struct ComplexStruct - { - public int? X; - public bool? Val; - public BasicStruct BasicStruct; - } - - public class CustomWWW : IWwwFormUrlDecoderEntry - { - public string Name => "CustomWWW"; - - public string Value => "CsWinRT"; - } - - [Version(3u)] - public interface IDouble - { - double GetDouble(); - double GetDouble(bool ignoreFactor); - } - - public interface IAnotherInterface - { - event ComplexDelegate ComplexDelegateEvent; - - bool FireComplexDelegate(double value, int value2); - - [Version(5u)] - int GetThree(); - } - - public sealed class TestClass : IDouble, IAnotherInterface - { - public event BasicDelegate BasicDelegateEvent, BasicDelegateEvent2; - public event ComplexDelegate ComplexDelegateEvent; - - public int Factor { get; set; } - private int Factor2 { get; set; } - public uint DelegateValue { get; set; } - - public TestClass() - { - Factor = 1; - Factor2 = 1; - BasicDelegateEvent += TestClass_BasicDelegateEvent; - } - - private void TestClass_BasicDelegateEvent(uint value) - { - DelegateValue = value; - } - - // Factory - - public TestClass(int factor) - { - Factor = factor; - } - - // Statics - public static int GetDefaultFactor() - { - return 1; - } - - public static int GetDefaultNumber() - { - return 2; - } - - // Default interface - - public void FireBasicDelegate(uint value) - { - BasicDelegateEvent.Invoke(value); - } - - public void FireBasicDelegate2(uint value) - { - BasicDelegateEvent2.Invoke(value); - } - - public int GetFactor() - { - return Factor; - } - - // Method overloading - - public int GetNumber() - { - return 2 * Factor; - } - - public int GetNumber(bool ignoreFactor) - { - return ignoreFactor ? 2 : GetNumber(); - } - - public int GetNumberWithDelta(bool ignoreFactor, int delta) - { - return delta + (ignoreFactor ? 2 : GetNumber()); - } - - // Implementing interface - - public double GetDouble() - { - return 2.0 * Factor; - } - - public double GetDouble(bool ignoreFactor) - { - return ignoreFactor ? 2.0 : GetNumber(); - } - - // Implementing another interface - - public bool FireComplexDelegate(double value, int value2) - { - return ComplexDelegateEvent.Invoke(value, value2); - } - - public int GetThree() - { - return 3; - } - - } - - internal class InternalClass - { - public static void Get() - { - } - } +using System; +using System.Reflection; +using Windows.Foundation; +using Windows.Foundation.Metadata; +using WinRT; + +namespace AuthoringSample +{ + public enum BasicEnum + { + First = -1, + Second = 0, + Third = 1, + Fourth + } + + [Flags] + public enum FlagsEnum : uint + { + First = 0, + Second = 1, + Third = 2, + Fourth = 4 + } + + internal enum PrivateEnum + { + PrivateFirst, + PrivateSecond + } + + public delegate void BasicDelegate(uint value); + public delegate bool ComplexDelegate(double value, int value2); + + public sealed class BasicClass + { + private BasicEnum basicEnum = BasicEnum.First; + private FlagsEnum flagsEnum = FlagsEnum.Second | FlagsEnum.Third; + + public event ComplexDelegate ComplexDelegateEvent; + private event ComplexDelegate ComplexDelegateEvent2; + + public Point GetPoint() + { + Point p = new Point + { + X = 2, + Y = 3 + }; + return p; + } + + public CustomWWW GetCustomWWW() + { + return new CustomWWW(); + } + + public BasicStruct GetBasicStruct() + { + BasicStruct basicStruct; + basicStruct.X = 4; + basicStruct.Y = 8; + basicStruct.Value = "CsWinRT"; + return basicStruct; + } + + public int GetSumOfInts(BasicStruct basicStruct) + { + return basicStruct.X + basicStruct.Y; + } + + public ComplexStruct GetComplexStruct() + { + ComplexStruct complexStruct; + complexStruct.X = 12; + complexStruct.Val = true; + complexStruct.BasicStruct = GetBasicStruct(); + return complexStruct; + } + + public int? GetX(ComplexStruct basicStruct) + { + return basicStruct.X; + } + + public void SetBasicEnum(BasicEnum basicEnum) + { + this.basicEnum = basicEnum; + } + + public BasicEnum GetBasicEnum() + { + return basicEnum; + } + + public void SetFlagsEnum(FlagsEnum flagsEnum) + { + this.flagsEnum = flagsEnum; + } + + public FlagsEnum GetFlagsEnum() + { + return flagsEnum; + } + + public BasicClass ReturnParameter(BasicClass basicClass) + { + return basicClass; + } + + private void PrivateFunction() + { + } + } + + public struct BasicStruct + { + public int X, Y; + public string Value; + } + + public struct ComplexStruct + { + public int? X; + public bool? Val; + public BasicStruct BasicStruct; + } + + public class CustomWWW : IWwwFormUrlDecoderEntry + { + public string Name => "CustomWWW"; + + public string Value => "CsWinRT"; + } + + [Version(3u)] + public interface IDouble + { + double GetDouble(); + double GetDouble(bool ignoreFactor); + } + + public interface IAnotherInterface + { + event ComplexDelegate ComplexDelegateEvent; + + bool FireComplexDelegate(double value, int value2); + + [Version(5u)] + int GetThree(); + } + + public sealed class TestClass : IDouble, IAnotherInterface + { + public event BasicDelegate BasicDelegateEvent, BasicDelegateEvent2; + public event ComplexDelegate ComplexDelegateEvent; + + public int Factor { get; set; } + private int Factor2 { get; set; } + public uint DelegateValue { get; set; } + + public TestClass() + { + Factor = 1; + Factor2 = 1; + BasicDelegateEvent += TestClass_BasicDelegateEvent; + } + + private void TestClass_BasicDelegateEvent(uint value) + { + DelegateValue = value; + } + + // Factory + + public TestClass(int factor) + { + Factor = factor; + } + + // Statics + public static int GetDefaultFactor() + { + return 1; + } + + public static int GetDefaultNumber() + { + return 2; + } + + // Default interface + + public void FireBasicDelegate(uint value) + { + BasicDelegateEvent.Invoke(value); + } + + public void FireBasicDelegate2(uint value) + { + BasicDelegateEvent2.Invoke(value); + } + + public int GetFactor() + { + return Factor; + } + + // Method overloading + + public int GetNumber() + { + return 2 * Factor; + } + + public int GetNumber(bool ignoreFactor) + { + return ignoreFactor ? 2 : GetNumber(); + } + + public int GetNumberWithDelta(bool ignoreFactor, int delta) + { + return delta + (ignoreFactor ? 2 : GetNumber()); + } + + // Implementing interface + + public double GetDouble() + { + return 2.0 * Factor; + } + + public double GetDouble(bool ignoreFactor) + { + return ignoreFactor ? 2.0 : GetNumber(); + } + + // Implementing another interface + + public bool FireComplexDelegate(double value, int value2) + { + return ComplexDelegateEvent.Invoke(value, value2); + } + + public int GetThree() + { + return 3; + } + + } + + internal class InternalClass + { + public static void Get() + { + } + } } \ No newline at end of file diff --git a/Authoring/AuthoringSample/Properties/launchSettings.json b/src/Authoring/AuthoringSample/Properties/launchSettings.json similarity index 94% rename from Authoring/AuthoringSample/Properties/launchSettings.json rename to src/Authoring/AuthoringSample/Properties/launchSettings.json index e05d02806..c05aeebf5 100644 --- a/Authoring/AuthoringSample/Properties/launchSettings.json +++ b/src/Authoring/AuthoringSample/Properties/launchSettings.json @@ -1,8 +1,8 @@ -{ - "profiles": { - "AuthoringSample": { - "commandName": "Project", - "nativeDebugging": true - } - } +{ + "profiles": { + "AuthoringSample": { + "commandName": "Project", + "nativeDebugging": true + } + } } \ No newline at end of file diff --git a/Authoring/Directory.Build.props b/src/Authoring/Directory.Build.props similarity index 100% rename from Authoring/Directory.Build.props rename to src/Authoring/Directory.Build.props diff --git a/WinRT.Host.Shim/Module.cs b/src/Authoring/WinRT.Host.Shim/Module.cs similarity index 97% rename from WinRT.Host.Shim/Module.cs rename to src/Authoring/WinRT.Host.Shim/Module.cs index 7dd51c6d4..1eb9d37b5 100644 --- a/WinRT.Host.Shim/Module.cs +++ b/src/Authoring/WinRT.Host.Shim/Module.cs @@ -1,126 +1,126 @@ -// TODO: consider embedding this as a resource into WinRT.Host.dll, -// to simplify deployment - -using System; -using System.Collections.Generic; -using System.IO; -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -#if !NETSTANDARD2_0 -using System.Runtime.Loader; -#endif -using System.Text; -using Windows.Foundation; -using WinRT; - -namespace WinRT.Host -{ - public static class Shim - { - private const int S_OK = 0; - private const int E_NOINTERFACE = unchecked((int)0x80004002); - private const int REGDB_E_READREGDB = unchecked((int)0x80040150); - private const int REGDB_E_CLASSNOTREG = unchecked((int)0x80040154); - - public unsafe delegate int GetActivationFactoryDelegate(IntPtr hstrTargetAssembly, IntPtr hstrRuntimeClassId, IntPtr* activationFactory); - - public static unsafe int GetActivationFactory(IntPtr hstrTargetAssembly, IntPtr hstrRuntimeClassId, IntPtr* activationFactory) - { - *activationFactory = IntPtr.Zero; - - var targetAssembly = MarshalString.FromAbi(hstrTargetAssembly); - var runtimeClassId = MarshalString.FromAbi(hstrRuntimeClassId); - - try - { - var assembly = ActivationLoader.LoadAssembly(targetAssembly); - var type = assembly.GetType("WinRT.Module"); - if (type == null) - { - return REGDB_E_CLASSNOTREG; - } - var GetActivationFactory = type.GetMethod("GetActivationFactory"); - if (GetActivationFactory == null) - { - return REGDB_E_READREGDB; - } - IntPtr factory = (IntPtr)GetActivationFactory.Invoke(null, new object[] { runtimeClassId }); - if (factory == IntPtr.Zero) - { - return E_NOINTERFACE; - } - *activationFactory = factory; - return S_OK; - } - catch (Exception e) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(e); - return global::WinRT.ExceptionHelpers.GetHRForException(e); - } - } - -#if NETSTANDARD2_0 - private static class ActivationLoader - { - public static Assembly LoadAssembly(string targetAssembly) => Assembly.LoadFrom(targetAssembly); - } -#else - private class ActivationLoader : AssemblyLoadContext - { - private AssemblyDependencyResolver _resolver; - - public static Assembly LoadAssembly(string targetAssembly) - { - var loader = new ActivationLoader(targetAssembly); - return loader.LoadFromAssemblyPath(targetAssembly); - } - - private ActivationLoader(string path) - { - _resolver = new AssemblyDependencyResolver(path); - AssemblyLoadContext.Default.Resolving += (AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName) => - { - // Consolidate all WinRT.Runtime loads to the default ALC, or failing that, the first shim ALC - if (assemblyName.Name == "WinRT.Runtime") - { - string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); - if (assemblyPath != null) - { - return LoadFromAssemblyPath(assemblyPath); - } - } - return null; - }; - } - - - protected override Assembly Load(AssemblyName assemblyName) - { - if (assemblyName.Name != "WinRT.Runtime") - { - string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); - if (assemblyPath != null) - { - return LoadFromAssemblyPath(assemblyPath); - } - } - - return null; - } - - protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) - { - string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName); - if (libraryPath != null) - { - return LoadUnmanagedDllFromPath(libraryPath); - } - - return IntPtr.Zero; - } - } -#endif - } -} - +// TODO: consider embedding this as a resource into WinRT.Host.dll, +// to simplify deployment + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +#if !NETSTANDARD2_0 +using System.Runtime.Loader; +#endif +using System.Text; +using Windows.Foundation; +using WinRT; + +namespace WinRT.Host +{ + public static class Shim + { + private const int S_OK = 0; + private const int E_NOINTERFACE = unchecked((int)0x80004002); + private const int REGDB_E_READREGDB = unchecked((int)0x80040150); + private const int REGDB_E_CLASSNOTREG = unchecked((int)0x80040154); + + public unsafe delegate int GetActivationFactoryDelegate(IntPtr hstrTargetAssembly, IntPtr hstrRuntimeClassId, IntPtr* activationFactory); + + public static unsafe int GetActivationFactory(IntPtr hstrTargetAssembly, IntPtr hstrRuntimeClassId, IntPtr* activationFactory) + { + *activationFactory = IntPtr.Zero; + + var targetAssembly = MarshalString.FromAbi(hstrTargetAssembly); + var runtimeClassId = MarshalString.FromAbi(hstrRuntimeClassId); + + try + { + var assembly = ActivationLoader.LoadAssembly(targetAssembly); + var type = assembly.GetType("WinRT.Module"); + if (type == null) + { + return REGDB_E_CLASSNOTREG; + } + var GetActivationFactory = type.GetMethod("GetActivationFactory"); + if (GetActivationFactory == null) + { + return REGDB_E_READREGDB; + } + IntPtr factory = (IntPtr)GetActivationFactory.Invoke(null, new object[] { runtimeClassId }); + if (factory == IntPtr.Zero) + { + return E_NOINTERFACE; + } + *activationFactory = factory; + return S_OK; + } + catch (Exception e) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(e); + return global::WinRT.ExceptionHelpers.GetHRForException(e); + } + } + +#if NETSTANDARD2_0 + private static class ActivationLoader + { + public static Assembly LoadAssembly(string targetAssembly) => Assembly.LoadFrom(targetAssembly); + } +#else + private class ActivationLoader : AssemblyLoadContext + { + private AssemblyDependencyResolver _resolver; + + public static Assembly LoadAssembly(string targetAssembly) + { + var loader = new ActivationLoader(targetAssembly); + return loader.LoadFromAssemblyPath(targetAssembly); + } + + private ActivationLoader(string path) + { + _resolver = new AssemblyDependencyResolver(path); + AssemblyLoadContext.Default.Resolving += (AssemblyLoadContext assemblyLoadContext, AssemblyName assemblyName) => + { + // Consolidate all WinRT.Runtime loads to the default ALC, or failing that, the first shim ALC + if (assemblyName.Name == "WinRT.Runtime") + { + string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); + if (assemblyPath != null) + { + return LoadFromAssemblyPath(assemblyPath); + } + } + return null; + }; + } + + + protected override Assembly Load(AssemblyName assemblyName) + { + if (assemblyName.Name != "WinRT.Runtime") + { + string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName); + if (assemblyPath != null) + { + return LoadFromAssemblyPath(assemblyPath); + } + } + + return null; + } + + protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) + { + string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName); + if (libraryPath != null) + { + return LoadUnmanagedDllFromPath(libraryPath); + } + + return IntPtr.Zero; + } + } +#endif + } +} + diff --git a/WinRT.Host.Shim/WinRT.Host.Shim.csproj b/src/Authoring/WinRT.Host.Shim/WinRT.Host.Shim.csproj similarity index 74% rename from WinRT.Host.Shim/WinRT.Host.Shim.csproj rename to src/Authoring/WinRT.Host.Shim/WinRT.Host.Shim.csproj index 6948bcb24..311cdba38 100644 --- a/WinRT.Host.Shim/WinRT.Host.Shim.csproj +++ b/src/Authoring/WinRT.Host.Shim/WinRT.Host.Shim.csproj @@ -1,15 +1,15 @@ - - - - netstandard2.0;net5.0 - - - - true - - - - - - - + + + + netstandard2.0;net5.0 + + + + true + + + + + + + diff --git a/WinRT.Host/NetHost.targets b/src/Authoring/WinRT.Host/NetHost.targets similarity index 98% rename from WinRT.Host/NetHost.targets rename to src/Authoring/WinRT.Host/NetHost.targets index 6c5651c80..06fe6fcaa 100644 --- a/WinRT.Host/NetHost.targets +++ b/src/Authoring/WinRT.Host/NetHost.targets @@ -1,42 +1,42 @@ - - - - false - true - true - NETHOST_USE_AS_STATIC - libnethost.lib - nethost.lib - - - - win-x86 - win-x64 - - - - - - @(NetHostDir) - - - - - - $(NetHostDefines);%(ClCompile.PreprocessorDefinitions) - $(NetHostDir);%(ClCompile.AdditionalIncludeDirectories) - - - - - - - $(NetHostLib);%(Link.AdditionalDependencies) - $(NetHostDir);%(Link.AdditionalLibraryDirectories) - - - - - - - + + + + false + true + true + NETHOST_USE_AS_STATIC + libnethost.lib + nethost.lib + + + + win-x86 + win-x64 + + + + + + @(NetHostDir) + + + + + + $(NetHostDefines);%(ClCompile.PreprocessorDefinitions) + $(NetHostDir);%(ClCompile.AdditionalIncludeDirectories) + + + + + + + $(NetHostLib);%(Link.AdditionalDependencies) + $(NetHostDir);%(Link.AdditionalLibraryDirectories) + + + + + + + diff --git a/WinRT.Host/NetHostDir.csproj b/src/Authoring/WinRT.Host/NetHostDir.csproj similarity index 97% rename from WinRT.Host/NetHostDir.csproj rename to src/Authoring/WinRT.Host/NetHostDir.csproj index 463dbe036..2a65838c6 100644 --- a/WinRT.Host/NetHostDir.csproj +++ b/src/Authoring/WinRT.Host/NetHostDir.csproj @@ -1,14 +1,14 @@ - - - - net5.0 - - - - - $(NetCoreTargetingPackRoot)/Microsoft.NETCore.App.Host.$(NETCoreSdkRuntimeIdentifier)/$(BundledNETCoreAppPackageVersion)/runtimes/$(NETCoreSdkRuntimeIdentifier)/native - - - - - + + + + net5.0 + + + + + $(NetCoreTargetingPackRoot)/Microsoft.NETCore.App.Host.$(NETCoreSdkRuntimeIdentifier)/$(BundledNETCoreAppPackageVersion)/runtimes/$(NETCoreSdkRuntimeIdentifier)/native + + + + + diff --git a/WinRT.Host/WinRT.Host.cpp b/src/Authoring/WinRT.Host/WinRT.Host.cpp similarity index 97% rename from WinRT.Host/WinRT.Host.cpp rename to src/Authoring/WinRT.Host/WinRT.Host.cpp index 2fec06115..8080fc651 100644 --- a/WinRT.Host/WinRT.Host.cpp +++ b/src/Authoring/WinRT.Host/WinRT.Host.cpp @@ -1,396 +1,396 @@ -// WinRT.Host.cpp : Implementation of C#/WinRT managed runtime component host - -#include "pch.h" -#include "hostfxr_status.h" -#include -#include - -#undef GetObject - -#include -#include -#include -#include -#include - -using namespace winrt; -using namespace winrt::Windows::Storage; -using namespace winrt::Windows::Data::Json; - -// NetHost headers, found via NetHostDir.csproj:GetNetHostDir -#if __has_include("nethost.h") -#include -#else -#error Project build required to resolve NetHost directory. Individual compilation not supported. -#endif -#include -#include - -#include - -// Global function pointers -typedef int (CORECLR_DELEGATE_CALLTYPE* get_activation_factory_fn)( - void* hstr_target_path, void* hstr_class_id, void** activation_factory); -static get_activation_factory_fn get_activation_factory = nullptr; -static hostfxr_close_fn hostfxr_close = nullptr; -static hostfxr_get_runtime_delegate_fn hostfxr_get_runtime_delegate = nullptr; -static hostfxr_initialize_for_runtime_config_fn hostfxr_initialize_for_runtime_config = nullptr; -static hostfxr_set_error_writer_fn hostfxr_set_error_writer = nullptr; -static load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer = nullptr; - -[[noreturn]] inline __declspec(noinline) void throw_hostfxr_hresult(hresult const result) -{ - static const struct - { - HostFxrStatus status; - const wchar_t* message; - } - hostfxr_status_messages[] = - { - { InvalidArgFailure, L"One of the specified arguments for the operation is invalid." }, - { CoreHostLibLoadFailure, L"There was a failure loading a dependent library." }, - { CoreHostLibMissingFailure, L"One of the dependent libraries is missing." }, - { CoreHostEntryPointFailure, L"One of the dependent libraries is missing a required entry point." }, - { CoreHostCurHostFindFailure, L"Could not deduce installation location from current module." }, - { CoreClrResolveFailure, L"The coreclr library could not be found." }, - { CoreClrBindFailure, L"The loaded coreclr library doesn't have one of the required entry points." }, - { CoreClrInitFailure, L"The call to coreclr_initialize failed." }, - { CoreClrExeFailure, L"The call to coreclr_execute_assembly failed." }, - { ResolverInitFailure, L"Initialization of the hostpolicy dependency resolver failed." }, - { ResolverResolveFailure, L"Resolution of dependencies in hostpolicy failed." }, - { LibHostCurExeFindFailure, L"Failure to determine the location of the current executable." }, - { LibHostInitFailure, L"Initialization of the hostpolicy library failed." }, - { LibHostSdkFindFailure, L"Failure to find the requested SDK. This happens in the hostfxr when an SDK(also called CLI) command is used with dotnet. In this case the hosting layer tries to find an installed. NET SDK to run the command on. The search is based on deduced install locationand on the requested version from potential global. json file. If either no matching SDK version can be found, or that version exists, but it's missing the dotnet. dll file, this error code is returned." }, - { LibHostInvalidArgs, L"Arguments to hostpolicy are invalid." }, - { InvalidConfigFile, L"The .runtimeconfig.json file is invalid." }, - { AppArgNotRunnable, L"The command line for dotnet.exe doesn't contain the path to the application." }, - { AppHostExeNotBoundFailure, L"Apphost failed to determine which application to run." }, - { FrameworkMissingFailure, L"It was not possible to find a compatible framework version." }, - { HostApiFailed, L"The hostpolicy could not calculate the NATIVE_DLL_SEARCH_DIRECTORIES." }, - { HostApiBufferTooSmall, L"The buffer specified to an API is not big enough to fit the requested value." }, - { LibHostUnknownCommand, L"The corehost_main_with_output_buffer is called with unsupported host command." }, - { LibHostAppRootFindFailure, L"The imprinted application path doesn't exist." }, - { SdkResolverResolveFailure, L"hostfxr_resolve_sdk2 failed to find matching SDK." }, - { FrameworkCompatFailure, L"The .runtimeconfig.json contains two incompatible framework references." }, - { FrameworkCompatRetry, L"A previously processed framework reference was reprocessed." }, - { BundleExtractionFailure, L"Error extracting single-file apphost bundle." }, - { BundleExtractionIOError, L"Error reading or writing files during single-file apphost bundle extraction." }, - { LibHostDuplicateProperty, L"The .runtimeconfig.json contains a runtime property which is also produced by the hosting layer." }, - { HostApiUnsupportedVersion, L"Feature which requires certain version of the hosting layer binaries was used on a version which doesn't support it." }, - { HostInvalidState, L"The current state is incompatible with the requested operation." }, - { HostPropertyNotFound, L"A property requested by hostfxr_get_runtime_property_value doesn't exist." }, - { CoreHostIncompatibleConfig, L"The component being initialized requires framework which is not available" }, - { HostApiUnsupportedScenario, L"hostfxr doesn't currently support requesting the given delegate type using the given context." }, - }; - - for (auto&& elem : hostfxr_status_messages) - { - if (elem.status == result) - { - throw hresult_error(result, elem.message); - } - } - - winrt::throw_hresult(result); -} - -inline void check_hostfxr_hresult(hresult const result) -{ - if (result < 0) - { - throw_hostfxr_hresult(result); - } -} - -// Using the nethost library, discover the location of hostfxr and get exports -void load_hostfxr() -{ - static const auto is_hostfxr_loaded = [&]() - { - return(hostfxr_initialize_for_runtime_config && - hostfxr_get_runtime_delegate && - hostfxr_close && - hostfxr_set_error_writer); - }; - - if (is_hostfxr_loaded()) - { - return; - } - - wchar_t buffer[MAX_PATH]; - size_t buffer_size = sizeof(buffer) / sizeof(wchar_t); - check_hostfxr_hresult(get_hostfxr_path(buffer, &buffer_size, nullptr)); - auto lib = ::LoadLibraryW(buffer); - if (lib == 0) - { - winrt::throw_last_error(); - } - - if ((hostfxr_initialize_for_runtime_config = (hostfxr_initialize_for_runtime_config_fn)::GetProcAddress(lib, "hostfxr_initialize_for_runtime_config")) && - (hostfxr_get_runtime_delegate = (hostfxr_get_runtime_delegate_fn)::GetProcAddress(lib, "hostfxr_get_runtime_delegate")) && - (hostfxr_close = (hostfxr_close_fn)::GetProcAddress(lib, "hostfxr_close")) && - (hostfxr_set_error_writer = (hostfxr_set_error_writer_fn)::GetProcAddress(lib, "hostfxr_set_error_writer"))) - { - return; - } - - winrt::throw_last_error(); -} - -struct error_writer -{ - static thread_local std::wstringstream _message; - hostfxr_error_writer_fn _previous_writer; - - error_writer() - { - _previous_writer = hostfxr_set_error_writer([](const wchar_t* message) - { - _message << message << L"\r\n"; - }); - } - - ~error_writer() - { - hostfxr_set_error_writer(_previous_writer); - } -}; -thread_local std::wstringstream error_writer::_message; - -// Load and initialize .NET runtime and get assembly load function pointer -void init_runtime(const wchar_t* host_path, const wchar_t* host_config) -{ - struct hostfxr_context - { - ~hostfxr_context() - { - if (_handle != nullptr) - { - hostfxr_close(_handle); - } - } - hostfxr_handle _handle = nullptr; - }; - hostfxr_context context; - - error_writer writer; - HRESULT hr = hostfxr_initialize_for_runtime_config(host_config, nullptr, &context._handle); - if (hr == Success_HostAlreadyInitialized || hr == Success_DifferentRuntimeProperties) - { - hr = Success; - } - else if (hr != Success) - { - auto message = writer._message.str(); - throw hresult_error(hr, message); - } - - if(load_assembly_and_get_function_pointer == nullptr) - { - // Get the load assembly function pointer - hr = hostfxr_get_runtime_delegate( - context._handle, - hdt_load_assembly_and_get_function_pointer, - (void**)&load_assembly_and_get_function_pointer); - check_hostfxr_hresult(hr); - } -} - -std::wstring find_mapped_target_assembly(std::filesystem::path host_config, winrt::hstring class_id) -{ - std::wstring target_assembly; - - try - { - auto config_file = StorageFile::GetFileFromPathAsync(host_config.c_str()).get(); - auto json_string = FileIO::ReadTextAsync(config_file).get(); - JsonObject root_object; - if (JsonObject::TryParse(json_string, root_object)) - { - if (auto classes = root_object.TryLookup(L"activatableClasses"); classes) - { - if (auto value_type = classes.ValueType(); value_type == JsonValueType::Object) - { - if (auto class_path = classes.GetObject().TryLookup(class_id); class_path) - { - target_assembly = class_path.GetString().c_str(); - } - } - } - } - } - catch (const winrt::hresult_error&) - { - } - - return target_assembly; -} - -std::filesystem::path probe_for_target_assembly(std::filesystem::path host_module, winrt::hstring class_id) -{ - auto host_file = host_module.filename(); - auto host_path = host_module; - host_path.remove_filename(); - - std::wstring target_path; - - std::vector probe_paths; - - auto probe = [&](const wchar_t* suffix) - { - auto probe_path = target_path + suffix; - auto end = probe_paths.end(); - if (std::find(probe_paths.begin(), end, probe_path) == end) - { - if (std::filesystem::exists(probe_path)) - { - target_path = probe_path; - return true; - } - probe_paths.emplace_back(std::move(probe_path)); - } - return false; - }; - - auto shorten_target_path = [&]() - { - std::size_t count = target_path.rfind('.'); - if (count == std::wstring::npos) - { - target_path.clear(); - return false; - } - target_path.resize(count); - return true; - }; - - auto probe_target = [&]() - { - while (!probe(L".Server.dll") && !probe(L".dll") && shorten_target_path()) {}; - return !target_path.empty(); - }; - - // Probe for target assembly by host name, if renamed (most common) - if (host_file.wstring() != L"winrt.host.dll") - { - probe_paths.push_back(host_module); - target_path = host_module; - target_path.resize(target_path.size() - 4); - if (probe_target()) - { - return target_path; - } - } - - // Probe for target assembly by runtime class name (less common) - target_path = host_path.wstring() + std::wstring(class_id.c_str()); - if(probe_target()) - { - return target_path; - } - - return {}; -} - -EXTERN_C IMAGE_DOS_HEADER __ImageBase; - -void GetActivationFactory(void* hstr_class_id, void** activation_factory) -{ - // Assumes the managed assembly to load and its runtime configuration file are next to the host - wchar_t buffer[MAX_PATH]; - auto size = ::GetModuleFileName((HINSTANCE)&__ImageBase, buffer, _countof(buffer)); - std::filesystem::path host_module(buffer); - auto host_file = host_module.filename(); - auto host_path = host_module; - host_path.remove_filename(); - - // Load HostFxr and get exported hosting functions - load_hostfxr(); - - // Determine host runtimeconfig.json from module name and load the runtime with it - winrt::hstring class_id; - winrt::copy_from_abi(class_id, hstr_class_id); - std::filesystem::path host_config = host_module; - host_config.replace_extension(L".runtimeconfig.json"); - std::filesystem::path target_path; - if (std::filesystem::exists(host_config)) - { - // If host runtimeconfig.json found, look for a target assembly mapping in it - auto target_assembly = find_mapped_target_assembly(host_config, class_id); - if (!target_assembly.empty()) - { - target_path = host_module; - target_path.replace_filename(target_assembly); - if (!std::filesystem::exists(target_path)) - { - throw_hostfxr_hresult(InvalidConfigFile); - } - } - } - else - { - // TODO: create a reasonable default runtimeconfig.json? - throw_hostfxr_hresult(InvalidConfigFile); - } - - init_runtime(host_module.wstring().c_str(), host_config.c_str()); - - // If no explicit target assembly mapping found, probe for it by naming convention - if (target_path.empty()) - { - target_path = probe_for_target_assembly(host_module, class_id); - if (target_path.empty() || !std::filesystem::exists(target_path)) - { - winrt::throw_hresult(HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND)); - } - } - - // Load shim (managed portion of host) and retrieve get_activation_factory pointer - if (::get_activation_factory == nullptr) - { - auto shim_path = host_module; - shim_path.replace_filename("WinRT.Host.Shim.dll"); - check_hostfxr_hresult(load_assembly_and_get_function_pointer( - shim_path.wstring().c_str(), - L"WinRT.Host.Shim, WinRT.Host.Shim", - L"GetActivationFactory", - L"WinRT.Host.Shim+GetActivationFactoryDelegate, WinRT.Host.Shim", - nullptr, - (void**)&::get_activation_factory)); - } - - // Load target assembly and get managed runtime class activation factory - winrt::hstring hstr_target_path(target_path.c_str()); - check_hostfxr_hresult(::get_activation_factory( - winrt::get_abi(hstr_target_path), hstr_class_id, activation_factory)); -} - -extern "C" HRESULT STDMETHODCALLTYPE DllGetActivationFactory(void* hstr_class_id, void** activation_factory) -{ - try - { - GetActivationFactory(hstr_class_id, activation_factory); - return S_OK; - } - catch (const winrt::hresult_error& hr) - { - return hr.to_abi(); - } - catch (const std::exception& e) - { - std::string message(e.what()); - std::wstring message_wide(message.begin(), message.end()); - winrt::hresult_error hr(winrt::hresult(E_FAIL), winrt::hstring(message_wide)); - return hr.to_abi(); - } - catch (...) - { - return E_FAIL; - } -} - -extern "C" HRESULT STDMETHODCALLTYPE DllCanUnloadNow(void) -{ - return S_FALSE; -} +// WinRT.Host.cpp : Implementation of C#/WinRT managed runtime component host + +#include "pch.h" +#include "hostfxr_status.h" +#include +#include + +#undef GetObject + +#include +#include +#include +#include +#include + +using namespace winrt; +using namespace winrt::Windows::Storage; +using namespace winrt::Windows::Data::Json; + +// NetHost headers, found via NetHostDir.csproj:GetNetHostDir +#if __has_include("nethost.h") +#include +#else +#error Project build required to resolve NetHost directory. Individual compilation not supported. +#endif +#include +#include + +#include + +// Global function pointers +typedef int (CORECLR_DELEGATE_CALLTYPE* get_activation_factory_fn)( + void* hstr_target_path, void* hstr_class_id, void** activation_factory); +static get_activation_factory_fn get_activation_factory = nullptr; +static hostfxr_close_fn hostfxr_close = nullptr; +static hostfxr_get_runtime_delegate_fn hostfxr_get_runtime_delegate = nullptr; +static hostfxr_initialize_for_runtime_config_fn hostfxr_initialize_for_runtime_config = nullptr; +static hostfxr_set_error_writer_fn hostfxr_set_error_writer = nullptr; +static load_assembly_and_get_function_pointer_fn load_assembly_and_get_function_pointer = nullptr; + +[[noreturn]] inline __declspec(noinline) void throw_hostfxr_hresult(hresult const result) +{ + static const struct + { + HostFxrStatus status; + const wchar_t* message; + } + hostfxr_status_messages[] = + { + { InvalidArgFailure, L"One of the specified arguments for the operation is invalid." }, + { CoreHostLibLoadFailure, L"There was a failure loading a dependent library." }, + { CoreHostLibMissingFailure, L"One of the dependent libraries is missing." }, + { CoreHostEntryPointFailure, L"One of the dependent libraries is missing a required entry point." }, + { CoreHostCurHostFindFailure, L"Could not deduce installation location from current module." }, + { CoreClrResolveFailure, L"The coreclr library could not be found." }, + { CoreClrBindFailure, L"The loaded coreclr library doesn't have one of the required entry points." }, + { CoreClrInitFailure, L"The call to coreclr_initialize failed." }, + { CoreClrExeFailure, L"The call to coreclr_execute_assembly failed." }, + { ResolverInitFailure, L"Initialization of the hostpolicy dependency resolver failed." }, + { ResolverResolveFailure, L"Resolution of dependencies in hostpolicy failed." }, + { LibHostCurExeFindFailure, L"Failure to determine the location of the current executable." }, + { LibHostInitFailure, L"Initialization of the hostpolicy library failed." }, + { LibHostSdkFindFailure, L"Failure to find the requested SDK. This happens in the hostfxr when an SDK(also called CLI) command is used with dotnet. In this case the hosting layer tries to find an installed. NET SDK to run the command on. The search is based on deduced install locationand on the requested version from potential global. json file. If either no matching SDK version can be found, or that version exists, but it's missing the dotnet. dll file, this error code is returned." }, + { LibHostInvalidArgs, L"Arguments to hostpolicy are invalid." }, + { InvalidConfigFile, L"The .runtimeconfig.json file is invalid." }, + { AppArgNotRunnable, L"The command line for dotnet.exe doesn't contain the path to the application." }, + { AppHostExeNotBoundFailure, L"Apphost failed to determine which application to run." }, + { FrameworkMissingFailure, L"It was not possible to find a compatible framework version." }, + { HostApiFailed, L"The hostpolicy could not calculate the NATIVE_DLL_SEARCH_DIRECTORIES." }, + { HostApiBufferTooSmall, L"The buffer specified to an API is not big enough to fit the requested value." }, + { LibHostUnknownCommand, L"The corehost_main_with_output_buffer is called with unsupported host command." }, + { LibHostAppRootFindFailure, L"The imprinted application path doesn't exist." }, + { SdkResolverResolveFailure, L"hostfxr_resolve_sdk2 failed to find matching SDK." }, + { FrameworkCompatFailure, L"The .runtimeconfig.json contains two incompatible framework references." }, + { FrameworkCompatRetry, L"A previously processed framework reference was reprocessed." }, + { BundleExtractionFailure, L"Error extracting single-file apphost bundle." }, + { BundleExtractionIOError, L"Error reading or writing files during single-file apphost bundle extraction." }, + { LibHostDuplicateProperty, L"The .runtimeconfig.json contains a runtime property which is also produced by the hosting layer." }, + { HostApiUnsupportedVersion, L"Feature which requires certain version of the hosting layer binaries was used on a version which doesn't support it." }, + { HostInvalidState, L"The current state is incompatible with the requested operation." }, + { HostPropertyNotFound, L"A property requested by hostfxr_get_runtime_property_value doesn't exist." }, + { CoreHostIncompatibleConfig, L"The component being initialized requires framework which is not available" }, + { HostApiUnsupportedScenario, L"hostfxr doesn't currently support requesting the given delegate type using the given context." }, + }; + + for (auto&& elem : hostfxr_status_messages) + { + if (elem.status == result) + { + throw hresult_error(result, elem.message); + } + } + + winrt::throw_hresult(result); +} + +inline void check_hostfxr_hresult(hresult const result) +{ + if (result < 0) + { + throw_hostfxr_hresult(result); + } +} + +// Using the nethost library, discover the location of hostfxr and get exports +void load_hostfxr() +{ + static const auto is_hostfxr_loaded = [&]() + { + return(hostfxr_initialize_for_runtime_config && + hostfxr_get_runtime_delegate && + hostfxr_close && + hostfxr_set_error_writer); + }; + + if (is_hostfxr_loaded()) + { + return; + } + + wchar_t buffer[MAX_PATH]; + size_t buffer_size = sizeof(buffer) / sizeof(wchar_t); + check_hostfxr_hresult(get_hostfxr_path(buffer, &buffer_size, nullptr)); + auto lib = ::LoadLibraryW(buffer); + if (lib == 0) + { + winrt::throw_last_error(); + } + + if ((hostfxr_initialize_for_runtime_config = (hostfxr_initialize_for_runtime_config_fn)::GetProcAddress(lib, "hostfxr_initialize_for_runtime_config")) && + (hostfxr_get_runtime_delegate = (hostfxr_get_runtime_delegate_fn)::GetProcAddress(lib, "hostfxr_get_runtime_delegate")) && + (hostfxr_close = (hostfxr_close_fn)::GetProcAddress(lib, "hostfxr_close")) && + (hostfxr_set_error_writer = (hostfxr_set_error_writer_fn)::GetProcAddress(lib, "hostfxr_set_error_writer"))) + { + return; + } + + winrt::throw_last_error(); +} + +struct error_writer +{ + static thread_local std::wstringstream _message; + hostfxr_error_writer_fn _previous_writer; + + error_writer() + { + _previous_writer = hostfxr_set_error_writer([](const wchar_t* message) + { + _message << message << L"\r\n"; + }); + } + + ~error_writer() + { + hostfxr_set_error_writer(_previous_writer); + } +}; +thread_local std::wstringstream error_writer::_message; + +// Load and initialize .NET runtime and get assembly load function pointer +void init_runtime(const wchar_t* host_path, const wchar_t* host_config) +{ + struct hostfxr_context + { + ~hostfxr_context() + { + if (_handle != nullptr) + { + hostfxr_close(_handle); + } + } + hostfxr_handle _handle = nullptr; + }; + hostfxr_context context; + + error_writer writer; + HRESULT hr = hostfxr_initialize_for_runtime_config(host_config, nullptr, &context._handle); + if (hr == Success_HostAlreadyInitialized || hr == Success_DifferentRuntimeProperties) + { + hr = Success; + } + else if (hr != Success) + { + auto message = writer._message.str(); + throw hresult_error(hr, message); + } + + if(load_assembly_and_get_function_pointer == nullptr) + { + // Get the load assembly function pointer + hr = hostfxr_get_runtime_delegate( + context._handle, + hdt_load_assembly_and_get_function_pointer, + (void**)&load_assembly_and_get_function_pointer); + check_hostfxr_hresult(hr); + } +} + +std::wstring find_mapped_target_assembly(std::filesystem::path host_config, winrt::hstring class_id) +{ + std::wstring target_assembly; + + try + { + auto config_file = StorageFile::GetFileFromPathAsync(host_config.c_str()).get(); + auto json_string = FileIO::ReadTextAsync(config_file).get(); + JsonObject root_object; + if (JsonObject::TryParse(json_string, root_object)) + { + if (auto classes = root_object.TryLookup(L"activatableClasses"); classes) + { + if (auto value_type = classes.ValueType(); value_type == JsonValueType::Object) + { + if (auto class_path = classes.GetObject().TryLookup(class_id); class_path) + { + target_assembly = class_path.GetString().c_str(); + } + } + } + } + } + catch (const winrt::hresult_error&) + { + } + + return target_assembly; +} + +std::filesystem::path probe_for_target_assembly(std::filesystem::path host_module, winrt::hstring class_id) +{ + auto host_file = host_module.filename(); + auto host_path = host_module; + host_path.remove_filename(); + + std::wstring target_path; + + std::vector probe_paths; + + auto probe = [&](const wchar_t* suffix) + { + auto probe_path = target_path + suffix; + auto end = probe_paths.end(); + if (std::find(probe_paths.begin(), end, probe_path) == end) + { + if (std::filesystem::exists(probe_path)) + { + target_path = probe_path; + return true; + } + probe_paths.emplace_back(std::move(probe_path)); + } + return false; + }; + + auto shorten_target_path = [&]() + { + std::size_t count = target_path.rfind('.'); + if (count == std::wstring::npos) + { + target_path.clear(); + return false; + } + target_path.resize(count); + return true; + }; + + auto probe_target = [&]() + { + while (!probe(L".Server.dll") && !probe(L".dll") && shorten_target_path()) {}; + return !target_path.empty(); + }; + + // Probe for target assembly by host name, if renamed (most common) + if (host_file.wstring() != L"winrt.host.dll") + { + probe_paths.push_back(host_module); + target_path = host_module; + target_path.resize(target_path.size() - 4); + if (probe_target()) + { + return target_path; + } + } + + // Probe for target assembly by runtime class name (less common) + target_path = host_path.wstring() + std::wstring(class_id.c_str()); + if(probe_target()) + { + return target_path; + } + + return {}; +} + +EXTERN_C IMAGE_DOS_HEADER __ImageBase; + +void GetActivationFactory(void* hstr_class_id, void** activation_factory) +{ + // Assumes the managed assembly to load and its runtime configuration file are next to the host + wchar_t buffer[MAX_PATH]; + auto size = ::GetModuleFileName((HINSTANCE)&__ImageBase, buffer, _countof(buffer)); + std::filesystem::path host_module(buffer); + auto host_file = host_module.filename(); + auto host_path = host_module; + host_path.remove_filename(); + + // Load HostFxr and get exported hosting functions + load_hostfxr(); + + // Determine host runtimeconfig.json from module name and load the runtime with it + winrt::hstring class_id; + winrt::copy_from_abi(class_id, hstr_class_id); + std::filesystem::path host_config = host_module; + host_config.replace_extension(L".runtimeconfig.json"); + std::filesystem::path target_path; + if (std::filesystem::exists(host_config)) + { + // If host runtimeconfig.json found, look for a target assembly mapping in it + auto target_assembly = find_mapped_target_assembly(host_config, class_id); + if (!target_assembly.empty()) + { + target_path = host_module; + target_path.replace_filename(target_assembly); + if (!std::filesystem::exists(target_path)) + { + throw_hostfxr_hresult(InvalidConfigFile); + } + } + } + else + { + // TODO: create a reasonable default runtimeconfig.json? + throw_hostfxr_hresult(InvalidConfigFile); + } + + init_runtime(host_module.wstring().c_str(), host_config.c_str()); + + // If no explicit target assembly mapping found, probe for it by naming convention + if (target_path.empty()) + { + target_path = probe_for_target_assembly(host_module, class_id); + if (target_path.empty() || !std::filesystem::exists(target_path)) + { + winrt::throw_hresult(HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND)); + } + } + + // Load shim (managed portion of host) and retrieve get_activation_factory pointer + if (::get_activation_factory == nullptr) + { + auto shim_path = host_module; + shim_path.replace_filename("WinRT.Host.Shim.dll"); + check_hostfxr_hresult(load_assembly_and_get_function_pointer( + shim_path.wstring().c_str(), + L"WinRT.Host.Shim, WinRT.Host.Shim", + L"GetActivationFactory", + L"WinRT.Host.Shim+GetActivationFactoryDelegate, WinRT.Host.Shim", + nullptr, + (void**)&::get_activation_factory)); + } + + // Load target assembly and get managed runtime class activation factory + winrt::hstring hstr_target_path(target_path.c_str()); + check_hostfxr_hresult(::get_activation_factory( + winrt::get_abi(hstr_target_path), hstr_class_id, activation_factory)); +} + +extern "C" HRESULT STDMETHODCALLTYPE DllGetActivationFactory(void* hstr_class_id, void** activation_factory) +{ + try + { + GetActivationFactory(hstr_class_id, activation_factory); + return S_OK; + } + catch (const winrt::hresult_error& hr) + { + return hr.to_abi(); + } + catch (const std::exception& e) + { + std::string message(e.what()); + std::wstring message_wide(message.begin(), message.end()); + winrt::hresult_error hr(winrt::hresult(E_FAIL), winrt::hstring(message_wide)); + return hr.to_abi(); + } + catch (...) + { + return E_FAIL; + } +} + +extern "C" HRESULT STDMETHODCALLTYPE DllCanUnloadNow(void) +{ + return S_FALSE; +} diff --git a/WinRT.Host/WinRT.Host.vcxproj b/src/Authoring/WinRT.Host/WinRT.Host.vcxproj similarity index 90% rename from WinRT.Host/WinRT.Host.vcxproj rename to src/Authoring/WinRT.Host/WinRT.Host.vcxproj index ba13535b2..e87efd13c 100644 --- a/WinRT.Host/WinRT.Host.vcxproj +++ b/src/Authoring/WinRT.Host/WinRT.Host.vcxproj @@ -1,225 +1,225 @@ - - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - 16.0 - Win32Proj - {7e33bcb7-19c5-4061-981d-ba695322708a} - WinRTHost - 10.0 - - - - DynamicLibrary - true - v142 - Unicode - - - DynamicLibrary - false - v142 - true - Unicode - - - DynamicLibrary - true - v142 - Unicode - - - DynamicLibrary - false - v142 - true - Unicode - - - - - - - - - - - - - - - - - - - - - false - WinRT.Host - - - false - WinRT.Host - - - false - WinRT.Host - - - false - WinRT.Host - - - - Level3 - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - MultiThreaded - - - Windows - true - false - module.def - libcpmt.lib;advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib - /ignore:4099 %(AdditionalOptions) - false - libcpmtd.lib - UseLinkTimeCodeGeneration - - - - - Level3 - true - true - true - WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - MultiThreaded - - - Windows - true - true - true - false - module.def - advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib - /ignore:4099 %(AdditionalOptions) - false - UseLinkTimeCodeGeneration - - - - - Level3 - true - NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - MultiThreaded - ProgramDatabase - - - Windows - true - false - module.def - libcpmt.lib;advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib - /ignore:4099 %(AdditionalOptions) - false - libcpmtd.lib - UseLinkTimeCodeGeneration - - - - - Level3 - true - true - true - NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) - true - Use - MultiThreaded - - - Windows - true - true - true - false - module.def - advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib - /ignore:4099 %(AdditionalOptions) - false - UseLinkTimeCodeGeneration - - - - - - /GL- %(AdditionalOptions) - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - {0bb8f82d-874e-45aa-bca3-20ce0562164a} - - - - - - - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - + + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 16.0 + Win32Proj + {7e33bcb7-19c5-4061-981d-ba695322708a} + WinRTHost + 10.0 + + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + DynamicLibrary + true + v142 + Unicode + + + DynamicLibrary + false + v142 + true + Unicode + + + + + + + + + + + + + + + + + + + + + false + WinRT.Host + + + false + WinRT.Host + + + false + WinRT.Host + + + false + WinRT.Host + + + + Level3 + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + MultiThreaded + + + Windows + true + false + module.def + libcpmt.lib;advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib + /ignore:4099 %(AdditionalOptions) + false + libcpmtd.lib + UseLinkTimeCodeGeneration + + + + + Level3 + true + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + MultiThreaded + + + Windows + true + true + true + false + module.def + advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib + /ignore:4099 %(AdditionalOptions) + false + UseLinkTimeCodeGeneration + + + + + Level3 + true + NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + MultiThreaded + ProgramDatabase + + + Windows + true + false + module.def + libcpmt.lib;advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib + /ignore:4099 %(AdditionalOptions) + false + libcpmtd.lib + UseLinkTimeCodeGeneration + + + + + Level3 + true + true + true + NDEBUG;_WINDOWS;_USRDLL;%(PreprocessorDefinitions) + true + Use + MultiThreaded + + + Windows + true + true + true + false + module.def + advapi32.lib;kernel32.lib;user32.lib;%(AdditionalDependencies);WindowsApp.lib + /ignore:4099 %(AdditionalOptions) + false + UseLinkTimeCodeGeneration + + + + + + /GL- %(AdditionalOptions) + + + + + + + + + + Create + Create + Create + Create + + + + + + + + + + + + {0bb8f82d-874e-45aa-bca3-20ce0562164a} + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/WinRT.Host/WinRT.Host.vcxproj.filters b/src/Authoring/WinRT.Host/WinRT.Host.vcxproj.filters similarity index 97% rename from WinRT.Host/WinRT.Host.vcxproj.filters rename to src/Authoring/WinRT.Host/WinRT.Host.vcxproj.filters index 821eb49d7..162da606b 100644 --- a/WinRT.Host/WinRT.Host.vcxproj.filters +++ b/src/Authoring/WinRT.Host/WinRT.Host.vcxproj.filters @@ -1,48 +1,48 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - Source Files - - - - - Source Files - - - Source Files - - - Source Files - - - + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/WinRT.Host/dllmain.cpp b/src/Authoring/WinRT.Host/dllmain.cpp similarity index 95% rename from WinRT.Host/dllmain.cpp rename to src/Authoring/WinRT.Host/dllmain.cpp index e07ad494d..26ecaa9cc 100644 --- a/WinRT.Host/dllmain.cpp +++ b/src/Authoring/WinRT.Host/dllmain.cpp @@ -1,20 +1,20 @@ -// dllmain.cpp : Defines the entry point for the DLL application. -#include "pch.h" - -BOOL APIENTRY DllMain( HMODULE hModule, - DWORD ul_reason_for_call, - LPVOID lpReserved - ) -{ - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: - DisableThreadLibraryCalls(hModule); - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} - +// dllmain.cpp : Defines the entry point for the DLL application. +#include "pch.h" + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hModule); + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + diff --git a/WinRT.Host/hostfxr_status.h b/src/Authoring/WinRT.Host/hostfxr_status.h similarity index 97% rename from WinRT.Host/hostfxr_status.h rename to src/Authoring/WinRT.Host/hostfxr_status.h index 9656db1f7..3ed4821d7 100644 --- a/WinRT.Host/hostfxr_status.h +++ b/src/Authoring/WinRT.Host/hostfxr_status.h @@ -1,51 +1,51 @@ -#pragma once - -// These error and exit codes are document in the host-error-codes.md -enum HostFxrStatus -{ - // Success - Success = 0, - Success_HostAlreadyInitialized = 0x00000001, - Success_DifferentRuntimeProperties = 0x00000002, - - // Failure - InvalidArgFailure = 0x80008081, - CoreHostLibLoadFailure = 0x80008082, - CoreHostLibMissingFailure = 0x80008083, - CoreHostEntryPointFailure = 0x80008084, - CoreHostCurHostFindFailure = 0x80008085, - // unused = 0x80008086, - CoreClrResolveFailure = 0x80008087, - CoreClrBindFailure = 0x80008088, - CoreClrInitFailure = 0x80008089, - CoreClrExeFailure = 0x8000808a, - ResolverInitFailure = 0x8000808b, - ResolverResolveFailure = 0x8000808c, - LibHostCurExeFindFailure = 0x8000808d, - LibHostInitFailure = 0x8000808e, - // unused = 0x8000808f, - LibHostExecModeFailure = 0x80008090, - LibHostSdkFindFailure = 0x80008091, - LibHostInvalidArgs = 0x80008092, - InvalidConfigFile = 0x80008093, - AppArgNotRunnable = 0x80008094, - AppHostExeNotBoundFailure = 0x80008095, - FrameworkMissingFailure = 0x80008096, - HostApiFailed = 0x80008097, - HostApiBufferTooSmall = 0x80008098, - LibHostUnknownCommand = 0x80008099, - LibHostAppRootFindFailure = 0x8000809a, - SdkResolverResolveFailure = 0x8000809b, - FrameworkCompatFailure = 0x8000809c, - FrameworkCompatRetry = 0x8000809d, - // unused = 0x8000809e, - BundleExtractionFailure = 0x8000809f, - BundleExtractionIOError = 0x800080a0, - LibHostDuplicateProperty = 0x800080a1, - HostApiUnsupportedVersion = 0x800080a2, - HostInvalidState = 0x800080a3, - HostPropertyNotFound = 0x800080a4, - CoreHostIncompatibleConfig = 0x800080a5, - HostApiUnsupportedScenario = 0x800080a6, -}; - +#pragma once + +// These error and exit codes are document in the host-error-codes.md +enum HostFxrStatus +{ + // Success + Success = 0, + Success_HostAlreadyInitialized = 0x00000001, + Success_DifferentRuntimeProperties = 0x00000002, + + // Failure + InvalidArgFailure = 0x80008081, + CoreHostLibLoadFailure = 0x80008082, + CoreHostLibMissingFailure = 0x80008083, + CoreHostEntryPointFailure = 0x80008084, + CoreHostCurHostFindFailure = 0x80008085, + // unused = 0x80008086, + CoreClrResolveFailure = 0x80008087, + CoreClrBindFailure = 0x80008088, + CoreClrInitFailure = 0x80008089, + CoreClrExeFailure = 0x8000808a, + ResolverInitFailure = 0x8000808b, + ResolverResolveFailure = 0x8000808c, + LibHostCurExeFindFailure = 0x8000808d, + LibHostInitFailure = 0x8000808e, + // unused = 0x8000808f, + LibHostExecModeFailure = 0x80008090, + LibHostSdkFindFailure = 0x80008091, + LibHostInvalidArgs = 0x80008092, + InvalidConfigFile = 0x80008093, + AppArgNotRunnable = 0x80008094, + AppHostExeNotBoundFailure = 0x80008095, + FrameworkMissingFailure = 0x80008096, + HostApiFailed = 0x80008097, + HostApiBufferTooSmall = 0x80008098, + LibHostUnknownCommand = 0x80008099, + LibHostAppRootFindFailure = 0x8000809a, + SdkResolverResolveFailure = 0x8000809b, + FrameworkCompatFailure = 0x8000809c, + FrameworkCompatRetry = 0x8000809d, + // unused = 0x8000809e, + BundleExtractionFailure = 0x8000809f, + BundleExtractionIOError = 0x800080a0, + LibHostDuplicateProperty = 0x800080a1, + HostApiUnsupportedVersion = 0x800080a2, + HostInvalidState = 0x800080a3, + HostPropertyNotFound = 0x800080a4, + CoreHostIncompatibleConfig = 0x800080a5, + HostApiUnsupportedScenario = 0x800080a6, +}; + diff --git a/WinRT.Host/module.def b/src/Authoring/WinRT.Host/module.def similarity index 96% rename from WinRT.Host/module.def rename to src/Authoring/WinRT.Host/module.def index 6011e87aa..f82e6dbd0 100644 --- a/WinRT.Host/module.def +++ b/src/Authoring/WinRT.Host/module.def @@ -1,3 +1,3 @@ -EXPORTS - DllGetActivationFactory PRIVATE - DllCanUnloadNow PRIVATE +EXPORTS + DllGetActivationFactory PRIVATE + DllCanUnloadNow PRIVATE diff --git a/WinRT.Host/packages.config b/src/Authoring/WinRT.Host/packages.config similarity index 98% rename from WinRT.Host/packages.config rename to src/Authoring/WinRT.Host/packages.config index 938a92d6a..81f107b8b 100644 --- a/WinRT.Host/packages.config +++ b/src/Authoring/WinRT.Host/packages.config @@ -1,4 +1,4 @@ - - - + + + \ No newline at end of file diff --git a/WinRT.Host/pch.cpp b/src/Authoring/WinRT.Host/pch.cpp similarity index 97% rename from WinRT.Host/pch.cpp rename to src/Authoring/WinRT.Host/pch.cpp index 91c22df2a..64b7eef6d 100644 --- a/WinRT.Host/pch.cpp +++ b/src/Authoring/WinRT.Host/pch.cpp @@ -1,5 +1,5 @@ -// pch.cpp: source file corresponding to the pre-compiled header - -#include "pch.h" - -// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. +// pch.cpp: source file corresponding to the pre-compiled header + +#include "pch.h" + +// When you are using pre-compiled headers, this source file is necessary for compilation to succeed. diff --git a/WinRT.Host/pch.h b/src/Authoring/WinRT.Host/pch.h similarity index 95% rename from WinRT.Host/pch.h rename to src/Authoring/WinRT.Host/pch.h index 158a63aea..9bf86f4ea 100644 --- a/WinRT.Host/pch.h +++ b/src/Authoring/WinRT.Host/pch.h @@ -1,9 +1,9 @@ -#pragma once - -#if defined(_DEBUG) -// Statically linking to nethost requires matching CRT -#undef _DEBUG -#endif - -#define WIN32_LEAN_AND_MEAN -#include +#pragma once + +#if defined(_DEBUG) +// Statically linking to nethost requires matching CRT +#undef _DEBUG +#endif + +#define WIN32_LEAN_AND_MEAN +#include diff --git a/Authoring/WinRT.SourceGenerator/Generator.cs b/src/Authoring/WinRT.SourceGenerator/Generator.cs similarity index 97% rename from Authoring/WinRT.SourceGenerator/Generator.cs rename to src/Authoring/WinRT.SourceGenerator/Generator.cs index 0b43d751c..8f3e091c3 100644 --- a/Authoring/WinRT.SourceGenerator/Generator.cs +++ b/src/Authoring/WinRT.SourceGenerator/Generator.cs @@ -1,186 +1,186 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.Text; -using System; -using System.Diagnostics; -using System.IO; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; -using System.Reflection.PortableExecutable; -using System.Text; - -namespace Generator -{ - [Generator] - public class SourceGenerator : ISourceGenerator - { - private string _tempFolder; - - private string GetAssemblyName(GeneratorExecutionContext context) - { - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.AssemblyName", out var assemblyName); - return assemblyName; - } - - private string GetAssemblyVersion(GeneratorExecutionContext context) - { - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.AssemblyVersion", out var assemblyVersion); - return assemblyVersion; - } - - public static string GetGeneratedFilesDir(GeneratorExecutionContext context) - { - // TODO: determine correct location to write to. - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.GeneratedFilesDir", out var generatedFilesDir); - Directory.CreateDirectory(generatedFilesDir); - return generatedFilesDir; - } - - private static bool IsCsWinRTComponent(GeneratorExecutionContext context) - { - if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTComponent", out var isCsWinRTComponentStr)) - { - return bool.TryParse(isCsWinRTComponentStr, out var isCsWinRTComponent) && isCsWinRTComponent; - } - - return false; - } - - private static string GetCsWinRTExe(GeneratorExecutionContext context) - { - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTExe", out var cswinrtExe); - return cswinrtExe; - } - - private string GetTempFolder(bool clearSourceFilesFromFolder = false) - { - if(_tempFolder == null || !File.Exists(_tempFolder)) - { - string outputDir = Path.Combine(Path.GetTempPath(), "CsWinRT", Path.GetRandomFileName()).TrimEnd('\\'); - Directory.CreateDirectory(outputDir); - _tempFolder = outputDir; - Logger.Log("Created temp folder: " + _tempFolder); - } - - if (clearSourceFilesFromFolder) - { - foreach (var file in Directory.GetFiles(_tempFolder, "*.cs", SearchOption.TopDirectoryOnly)) - { - Logger.Log("Clearing " + file); - File.Delete(file); - } - } - - return _tempFolder; - } - - private void GenerateSources(GeneratorExecutionContext context) - { - string cswinrtExe = GetCsWinRTExe(context); - string assemblyName = GetAssemblyName(context); - string winmdFile = GetWinmdOutputFile(context); - string outputDir = GetTempFolder(true); - // TODO: make it a property with a list of WinMDs - string additionalWinMds = "10.0.18362.0"; - - string arguments = string.Format("-component -input \"{0}\" -input {1} -include {2} -output \"{3}\" -verbose", winmdFile, additionalWinMds, assemblyName, outputDir); - Logger.Log("Running " + cswinrtExe + " " + arguments); - - var processInfo = new ProcessStartInfo - { - FileName = cswinrtExe, - Arguments = arguments, - UseShellExecute = false, - RedirectStandardOutput = true, - RedirectStandardError = true, - WindowStyle = ProcessWindowStyle.Hidden, - CreateNoWindow = true - }; - - using var cswinrtProcess = Process.Start(processInfo); - Logger.Log(cswinrtProcess.StandardOutput.ReadToEnd()); - Logger.Log(cswinrtProcess.StandardError.ReadToEnd()); - cswinrtProcess.WaitForExit(); - - foreach(var file in Directory.GetFiles(outputDir, "*.cs", SearchOption.TopDirectoryOnly)) - { - Logger.Log("Adding " + file); - context.AddSource(Path.GetFileNameWithoutExtension(file), SourceText.From(File.ReadAllText(file), Encoding.UTF8)); - } - - Directory.Delete(outputDir, true); - } - - private string GetWinmdOutputFile(GeneratorExecutionContext context) - { - return Path.Combine(GetGeneratedFilesDir(context), GetAssemblyName(context) + ".winmd"); - } - - private void GenerateWinMD(MetadataBuilder metadataBuilder, string outputFile) - { - Logger.Log("Writing " + outputFile); - var managedPeBuilder = new ManagedPEBuilder( - new PEHeaderBuilder( - machine: Machine.I386, - imageCharacteristics: Characteristics.ExecutableImage | Characteristics.Dll | Characteristics.Bit32Machine), - new MetadataRootBuilder(metadataBuilder, "WindowsRuntime 1.4"), - new BlobBuilder(), - flags: CorFlags.ILOnly); - - var peBlob = new BlobBuilder(); - managedPeBuilder.Serialize(peBlob); - - using var fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write); - peBlob.WriteContentTo(fs); - } - - public void Execute(GeneratorExecutionContext context) - { - if (!IsCsWinRTComponent(context)) - { - return; - } - - Logger.Initialize(context); - - try - { - string assembly = GetAssemblyName(context); - string version = GetAssemblyVersion(context); - MetadataBuilder metadataBuilder = new MetadataBuilder(); - - var writer = new WinRTTypeWriter( - assembly, - version, - metadataBuilder); - foreach (SyntaxTree tree in context.Compilation.SyntaxTrees) - { - writer.Model = context.Compilation.GetSemanticModel(tree); - writer.Visit(tree.GetRoot()); - } - writer.FinalizeGeneration(); - - string winmdFile = GetWinmdOutputFile(context); - - GenerateWinMD(metadataBuilder, winmdFile); - GenerateSources(context); - } - catch(Exception e) - { - Logger.Log(e.ToString()); - if(e.InnerException != null) - { - Logger.Log(e.InnerException.ToString()); - } - Logger.Close(); - throw; - } - - Logger.Log("Done"); - Logger.Close(); - } - - public void Initialize(GeneratorInitializationContext context) - { - } - } -} +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.Text; +using System; +using System.Diagnostics; +using System.IO; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Reflection.PortableExecutable; +using System.Text; + +namespace Generator +{ + [Generator] + public class SourceGenerator : ISourceGenerator + { + private string _tempFolder; + + private string GetAssemblyName(GeneratorExecutionContext context) + { + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.AssemblyName", out var assemblyName); + return assemblyName; + } + + private string GetAssemblyVersion(GeneratorExecutionContext context) + { + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.AssemblyVersion", out var assemblyVersion); + return assemblyVersion; + } + + public static string GetGeneratedFilesDir(GeneratorExecutionContext context) + { + // TODO: determine correct location to write to. + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.GeneratedFilesDir", out var generatedFilesDir); + Directory.CreateDirectory(generatedFilesDir); + return generatedFilesDir; + } + + private static bool IsCsWinRTComponent(GeneratorExecutionContext context) + { + if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTComponent", out var isCsWinRTComponentStr)) + { + return bool.TryParse(isCsWinRTComponentStr, out var isCsWinRTComponent) && isCsWinRTComponent; + } + + return false; + } + + private static string GetCsWinRTExe(GeneratorExecutionContext context) + { + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTExe", out var cswinrtExe); + return cswinrtExe; + } + + private string GetTempFolder(bool clearSourceFilesFromFolder = false) + { + if(_tempFolder == null || !File.Exists(_tempFolder)) + { + string outputDir = Path.Combine(Path.GetTempPath(), "CsWinRT", Path.GetRandomFileName()).TrimEnd('\\'); + Directory.CreateDirectory(outputDir); + _tempFolder = outputDir; + Logger.Log("Created temp folder: " + _tempFolder); + } + + if (clearSourceFilesFromFolder) + { + foreach (var file in Directory.GetFiles(_tempFolder, "*.cs", SearchOption.TopDirectoryOnly)) + { + Logger.Log("Clearing " + file); + File.Delete(file); + } + } + + return _tempFolder; + } + + private void GenerateSources(GeneratorExecutionContext context) + { + string cswinrtExe = GetCsWinRTExe(context); + string assemblyName = GetAssemblyName(context); + string winmdFile = GetWinmdOutputFile(context); + string outputDir = GetTempFolder(true); + // TODO: make it a property with a list of WinMDs + string additionalWinMds = "10.0.18362.0"; + + string arguments = string.Format("-component -input \"{0}\" -input {1} -include {2} -output \"{3}\" -verbose", winmdFile, additionalWinMds, assemblyName, outputDir); + Logger.Log("Running " + cswinrtExe + " " + arguments); + + var processInfo = new ProcessStartInfo + { + FileName = cswinrtExe, + Arguments = arguments, + UseShellExecute = false, + RedirectStandardOutput = true, + RedirectStandardError = true, + WindowStyle = ProcessWindowStyle.Hidden, + CreateNoWindow = true + }; + + using var cswinrtProcess = Process.Start(processInfo); + Logger.Log(cswinrtProcess.StandardOutput.ReadToEnd()); + Logger.Log(cswinrtProcess.StandardError.ReadToEnd()); + cswinrtProcess.WaitForExit(); + + foreach(var file in Directory.GetFiles(outputDir, "*.cs", SearchOption.TopDirectoryOnly)) + { + Logger.Log("Adding " + file); + context.AddSource(Path.GetFileNameWithoutExtension(file), SourceText.From(File.ReadAllText(file), Encoding.UTF8)); + } + + Directory.Delete(outputDir, true); + } + + private string GetWinmdOutputFile(GeneratorExecutionContext context) + { + return Path.Combine(GetGeneratedFilesDir(context), GetAssemblyName(context) + ".winmd"); + } + + private void GenerateWinMD(MetadataBuilder metadataBuilder, string outputFile) + { + Logger.Log("Writing " + outputFile); + var managedPeBuilder = new ManagedPEBuilder( + new PEHeaderBuilder( + machine: Machine.I386, + imageCharacteristics: Characteristics.ExecutableImage | Characteristics.Dll | Characteristics.Bit32Machine), + new MetadataRootBuilder(metadataBuilder, "WindowsRuntime 1.4"), + new BlobBuilder(), + flags: CorFlags.ILOnly); + + var peBlob = new BlobBuilder(); + managedPeBuilder.Serialize(peBlob); + + using var fs = new FileStream(outputFile, FileMode.Create, FileAccess.Write); + peBlob.WriteContentTo(fs); + } + + public void Execute(GeneratorExecutionContext context) + { + if (!IsCsWinRTComponent(context)) + { + return; + } + + Logger.Initialize(context); + + try + { + string assembly = GetAssemblyName(context); + string version = GetAssemblyVersion(context); + MetadataBuilder metadataBuilder = new MetadataBuilder(); + + var writer = new WinRTTypeWriter( + assembly, + version, + metadataBuilder); + foreach (SyntaxTree tree in context.Compilation.SyntaxTrees) + { + writer.Model = context.Compilation.GetSemanticModel(tree); + writer.Visit(tree.GetRoot()); + } + writer.FinalizeGeneration(); + + string winmdFile = GetWinmdOutputFile(context); + + GenerateWinMD(metadataBuilder, winmdFile); + GenerateSources(context); + } + catch(Exception e) + { + Logger.Log(e.ToString()); + if(e.InnerException != null) + { + Logger.Log(e.InnerException.ToString()); + } + Logger.Close(); + throw; + } + + Logger.Log("Done"); + Logger.Close(); + } + + public void Initialize(GeneratorInitializationContext context) + { + } + } +} diff --git a/Authoring/WinRT.SourceGenerator/Helper.cs b/src/Authoring/WinRT.SourceGenerator/Helper.cs similarity index 96% rename from Authoring/WinRT.SourceGenerator/Helper.cs rename to src/Authoring/WinRT.SourceGenerator/Helper.cs index 1b73cfc5d..7423ded73 100644 --- a/Authoring/WinRT.SourceGenerator/Helper.cs +++ b/src/Authoring/WinRT.SourceGenerator/Helper.cs @@ -1,35 +1,35 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Generator -{ - public static class Helper - { - public static Guid EncodeGuid(byte[] data) - { - if (BitConverter.IsLittleEndian) - { - // swap bytes of int a - byte t = data[0]; - data[0] = data[3]; - data[3] = t; - t = data[1]; - data[1] = data[2]; - data[2] = t; - // swap bytes of short b - t = data[4]; - data[4] = data[5]; - data[5] = t; - // swap bytes of short c and encode rfc time/version field - t = data[6]; - data[6] = data[7]; - data[7] = (byte)((t & 0x0f) | (5 << 4)); - // encode rfc clock/reserved field - data[8] = (byte)((data[8] & 0x3f) | 0x80); - } - return new Guid(data.Take(16).ToArray()); - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Generator +{ + public static class Helper + { + public static Guid EncodeGuid(byte[] data) + { + if (BitConverter.IsLittleEndian) + { + // swap bytes of int a + byte t = data[0]; + data[0] = data[3]; + data[3] = t; + t = data[1]; + data[1] = data[2]; + data[2] = t; + // swap bytes of short b + t = data[4]; + data[4] = data[5]; + data[5] = t; + // swap bytes of short c and encode rfc time/version field + t = data[6]; + data[6] = data[7]; + data[7] = (byte)((t & 0x0f) | (5 << 4)); + // encode rfc clock/reserved field + data[8] = (byte)((data[8] & 0x3f) | 0x80); + } + return new Guid(data.Take(16).ToArray()); + } + } +} diff --git a/Authoring/WinRT.SourceGenerator/Logger.cs b/src/Authoring/WinRT.SourceGenerator/Logger.cs similarity index 96% rename from Authoring/WinRT.SourceGenerator/Logger.cs rename to src/Authoring/WinRT.SourceGenerator/Logger.cs index 91d58bec4..7bcea7618 100644 --- a/Authoring/WinRT.SourceGenerator/Logger.cs +++ b/src/Authoring/WinRT.SourceGenerator/Logger.cs @@ -1,30 +1,30 @@ -using Microsoft.CodeAnalysis; -using System.IO; - -namespace Generator -{ - class Logger - { - public static void Initialize(GeneratorExecutionContext context) - { - context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTEnableLogging", out var enableLoggingStr); - if (enableLoggingStr != null && bool.TryParse(enableLoggingStr, out var enableLogging) && enableLogging) - { - string logFile = Path.Combine(SourceGenerator.GetGeneratedFilesDir(context), "log.txt"); - fileLogger = File.CreateText(logFile); - } - } - - public static void Log(string text) - { - fileLogger?.WriteLine(text); - } - - public static void Close() - { - fileLogger?.Close(); - } - - private static TextWriter fileLogger; - } -} +using Microsoft.CodeAnalysis; +using System.IO; + +namespace Generator +{ + class Logger + { + public static void Initialize(GeneratorExecutionContext context) + { + context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.CsWinRTEnableLogging", out var enableLoggingStr); + if (enableLoggingStr != null && bool.TryParse(enableLoggingStr, out var enableLogging) && enableLogging) + { + string logFile = Path.Combine(SourceGenerator.GetGeneratedFilesDir(context), "log.txt"); + fileLogger = File.CreateText(logFile); + } + } + + public static void Log(string text) + { + fileLogger?.WriteLine(text); + } + + public static void Close() + { + fileLogger?.Close(); + } + + private static TextWriter fileLogger; + } +} diff --git a/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj similarity index 97% rename from Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj rename to src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj index 14431f062..89e272957 100644 --- a/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj +++ b/src/Authoring/WinRT.SourceGenerator/WinRT.SourceGenerator.csproj @@ -1,25 +1,25 @@ - - - - netstandard2.0 - preview - Microsoft Corporation - Microsoft Corporation - C#/WinRT - WinRT.SourceGenerator - $(VersionNumber) - $(VersionNumber) - $(VersionNumber) - $(VersionNumber) - en - C#/WinRT Authoring Source Generator Preview $(VersionString) - C#/WinRT Authoring Source Generator Preview v$(VersionString) - Copyright (c) Microsoft Corporation. All rights reserved. - - - - - - - - + + + + netstandard2.0 + preview + Microsoft Corporation + Microsoft Corporation + C#/WinRT + WinRT.SourceGenerator + $(VersionNumber) + $(VersionNumber) + $(VersionNumber) + $(VersionNumber) + en + C#/WinRT Authoring Source Generator Preview $(VersionString) + C#/WinRT Authoring Source Generator Preview v$(VersionString) + Copyright (c) Microsoft Corporation. All rights reserved. + + + + + + + + diff --git a/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs similarity index 97% rename from Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs rename to src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs index 93461ad84..1237494a9 100644 --- a/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs +++ b/src/Authoring/WinRT.SourceGenerator/WinRTTypeWriter.cs @@ -1,2180 +1,2180 @@ -using Microsoft.CodeAnalysis; -using Microsoft.CodeAnalysis.CSharp; -using Microsoft.CodeAnalysis.CSharp.Syntax; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Reflection.Metadata; -using System.Reflection.Metadata.Ecma335; -using System.Security.Cryptography; -using System.Text; - -namespace Generator -{ - class Parameter - { - public Symbol Type; - public string Name; - public ParameterAttributes Attributes; - - public Parameter(Symbol type, string name, ParameterAttributes attributes) - { - Type = type; - Name = name; - Attributes = attributes; - } - - public Parameter(ITypeSymbol type, string name, ParameterAttributes attributes) - : this(new Symbol(type), name, attributes) - { - } - - public Parameter(EntityHandle type, string name, ParameterAttributes attributes) - : this(new Symbol(type), name, attributes) - { - } - - public Parameter(ParameterSyntax parameter, ParameterAttributes attributes, SemanticModel model) - { - Type = new Symbol(model.GetDeclaredSymbol(parameter).Type); - Name = parameter.Identifier.ValueText; - Attributes = attributes; - } - } - - class Symbol - { - public ITypeSymbol Type; - public EntityHandle Handle; - - public Symbol(ITypeSymbol type) - { - Type = type; - Handle = default; - } - - public Symbol(EntityHandle handle) - { - Type = default; - Handle = handle; - } - - public bool IsHandle() - { - return Handle != default; - } - } - - class TypeDeclaration - { - public readonly ISymbol Node; - public TypeDefinitionHandle Handle; - public string DefaultInterface; - public string StaticInterface; - - public Dictionary> MethodDefinitions = new Dictionary>(); - public Dictionary> MethodReferences = new Dictionary>(); - public Dictionary FieldDefinitions = new Dictionary(); - public Dictionary PropertyDefinitions = new Dictionary(); - public Dictionary EventDefinitions = new Dictionary(); - public Dictionary InterfaceImplDefinitions = new Dictionary(); - public Dictionary> MethodsByName = new Dictionary>(); - public Dictionary OverloadedMethods = new Dictionary(); - - public TypeDeclaration(ISymbol node) - { - Node = node; - Handle = default; - } - - public override string ToString() - { - return Node.ToString(); - } - - public void AddMethod(ISymbol node, string name, MethodDefinitionHandle handle) - { - if(!MethodDefinitions.ContainsKey(node)) - { - MethodDefinitions[node] = new List(); - MethodReferences[node] = new List(); - } - - if(!MethodsByName.ContainsKey(name)) - { - MethodsByName[name] = new List(); - } - - MethodDefinitions[node].Add(handle); - MethodReferences[node].Add(handle); - MethodsByName[name].Add(node); - } - - public void AddMethodReference(ISymbol node, MemberReferenceHandle handle) - { - if (!MethodReferences.ContainsKey(node)) - { - MethodReferences[node] = new List(); - } - - MethodReferences[node].Add(handle); - } - - public void AddMethodOverload(ISymbol node, string overloadedMethodName) - { - OverloadedMethods[node] = overloadedMethodName; - } - - public List GetMethodDefinitions() - { - return MethodDefinitions.Values.SelectMany(list => list).ToList(); - } - - public List GetMethodReferences() - { - return MethodReferences.Values.SelectMany(list => list).ToList(); - } - - public void AddField(ISymbol node, FieldDefinitionHandle handle) - { - FieldDefinitions[node] = handle; - } - - public List GetFieldDefinitions() - { - return FieldDefinitions.Values.ToList(); - } - - public void AddProperty(ISymbol node, PropertyDefinitionHandle handle) - { - PropertyDefinitions[node] = handle; - } - - public List GetPropertyDefinitions() - { - return PropertyDefinitions.Values.ToList(); - } - - public void AddEvent(ISymbol node, EventDefinitionHandle handle) - { - EventDefinitions[node] = handle; - } - - public List GetEventDefinitions() - { - return EventDefinitions.Values.ToList(); - } - - public void AddInterfaceImpl(ISymbol node, InterfaceImplementationHandle handle) - { - InterfaceImplDefinitions[node] = handle; - } - - } - - class WinRTTypeWriter : CSharpSyntaxWalker - { - private struct MappedType - { - public readonly string @namespace; - public readonly string name; - public readonly string assembly; - - public MappedType(string @namespace, string name, string assembly) - { - this.@namespace = @namespace; - this.name = name; - this.assembly = assembly; - } - } - - private static readonly Dictionary MappedCSharpTypes = new Dictionary() - { - { "System.Nullable", new MappedType("Windows.Foundation", "IReference`1", "Windows.Foundation.FoundationContract" ) }, - { "System.FlagsAttribute", new MappedType("System", "FlagsAttribute", "mscorlib" ) } - }; - - public SemanticModel Model; - - private readonly string assembly; - private readonly string version; - - private readonly Stack namespaces = new Stack(); - private readonly Dictionary typeReferenceMapping; - private readonly Dictionary assemblyReferenceMapping; - private readonly List nodesWithAttributes; - private readonly MetadataBuilder metadataBuilder; - private bool hasConstructor, hasDefaultConstructor; - - private readonly Dictionary typeDefinitionMapping; - private TypeDeclaration currentTypeDeclaration; - - public WinRTTypeWriter( - string assembly, - string version, - MetadataBuilder metadataBuilder) - { - this.assembly = assembly; - this.version = version; - this.metadataBuilder = metadataBuilder; - typeReferenceMapping = new Dictionary(); - assemblyReferenceMapping = new Dictionary(); - typeDefinitionMapping = new Dictionary(); - nodesWithAttributes = new List(); - - CreteAssembly(); - } - - private void CreteAssembly() - { - Logger.Log("Generating assembly " + assembly + " version " + version); - metadataBuilder.AddAssembly( - metadataBuilder.GetOrAddString(assembly), - new Version(version), - default, - default, - AssemblyFlags.WindowsRuntime, - AssemblyHashAlgorithm.Sha1); - - var moduleDefinition = metadataBuilder.AddModule( - 0, - metadataBuilder.GetOrAddString(assembly + ".winmd"), - metadataBuilder.GetOrAddGuid(Guid.NewGuid()), - default, - default); - assemblyReferenceMapping[assembly] = moduleDefinition; - - metadataBuilder.AddTypeDefinition( - default, - default, - metadataBuilder.GetOrAddString(""), - default, - MetadataTokens.FieldDefinitionHandle(1), - MetadataTokens.MethodDefinitionHandle(1)); - } - - private void EncodeSpecialType(SpecialType specialType, SignatureTypeEncoder typeEncoder) - { - switch (specialType) - { - case SpecialType.System_Boolean: - typeEncoder.Boolean(); - break; - case SpecialType.System_Byte: - typeEncoder.Byte(); - break; - case SpecialType.System_Int16: - typeEncoder.Int16(); - break; - case SpecialType.System_Int32: - typeEncoder.Int32(); - break; - case SpecialType.System_Int64: - typeEncoder.Int64(); - break; - case SpecialType.System_UInt16: - typeEncoder.UInt16(); - break; - case SpecialType.System_UInt32: - typeEncoder.UInt32(); - break; - case SpecialType.System_UInt64: - typeEncoder.UInt64(); - break; - case SpecialType.System_Single: - typeEncoder.Single(); - break; - case SpecialType.System_Double: - typeEncoder.Double(); - break; - case SpecialType.System_Char: - typeEncoder.Char(); - break; - case SpecialType.System_String: - typeEncoder.String(); - break; - case SpecialType.System_Object: - typeEncoder.Object(); - break; - case SpecialType.System_IntPtr: - typeEncoder.IntPtr(); - break; - default: - Logger.Log("TODO special type: " + specialType); - break; - } - - // TODO: handle C# interface mappings for special types - } - - private BlobHandle GetStrongNameKey(string assembly) - { - if(assembly == "mscorlib") - { - byte[] mscorlibStrongName = { 0xb7, 0x7a, 0x5c, 0x56, 0x19, 0x34, 0xe0, 0x89 }; - return metadataBuilder.GetOrAddBlob(mscorlibStrongName); - } - - return default; - } - - private EntityHandle GetTypeReference(string @namespace, string name, string assembly) - { - string fullname = QualifiedName(@namespace, name); - if (typeReferenceMapping.ContainsKey(fullname)) - { - return typeReferenceMapping[fullname]; - } - - if (!assemblyReferenceMapping.ContainsKey(assembly)) - { - EntityHandle assemblyReference = metadataBuilder.AddAssemblyReference( - metadataBuilder.GetOrAddString(assembly), - new Version(0xff, 0xff, 0xff, 0xff), - default, - GetStrongNameKey(assembly), - assembly == "mscorlib" ? default : AssemblyFlags.WindowsRuntime, - default); - assemblyReferenceMapping[assembly] = assemblyReference; - } - - var typeRef = metadataBuilder.AddTypeReference( - assemblyReferenceMapping[assembly], - metadataBuilder.GetOrAddString(@namespace), - metadataBuilder.GetOrAddString(name)); - typeReferenceMapping[fullname] = typeRef; - return typeRef; - } - - public string GetAssemblyForWinRTType(ISymbol type) - { - var winrtTypeAttribute = type.GetAttributes(). - Where(attribute => attribute.AttributeClass.Name == "WindowsRuntimeTypeAttribute"); - if (winrtTypeAttribute.Any()) - { - return (string) winrtTypeAttribute.First().ConstructorArguments[0].Value; - } - - return null; - } - - private EntityHandle GetTypeReference(ISymbol symbol) - { - string @namespace = symbol.ContainingNamespace.ToString(); - string name = symbol.Name; - string fullType = QualifiedName(@namespace, name); - - var assembly = GetAssemblyForWinRTType(symbol); - if (assembly == null) - { - if (MappedCSharpTypes.ContainsKey(fullType)) - { - Logger.Log("Mapping known type: " + fullType); - var newType = MappedCSharpTypes[fullType]; - @namespace = newType.@namespace; - name = newType.name; - assembly = newType.assembly; - - Logger.Log("Mapping " + fullType + " to " + QualifiedName(@namespace, name) + " from " + assembly); - } - else - { - assembly = symbol.ContainingAssembly.Name; - } - } - - return GetTypeReference(@namespace, name, assembly); - } - - private void EncodeSymbol(Symbol symbol, SignatureTypeEncoder typeEncoder) - { - if (symbol.IsHandle()) - { - typeEncoder.Type(symbol.Handle, false); - } - else if(symbol.Type is INamedTypeSymbol namedType && namedType.TypeArguments.Length != 0) - { - Logger.Log("generic type"); - var genericType = typeEncoder.GenericInstantiation(GetTypeReference(symbol.Type), namedType.TypeArguments.Length, false); - foreach (var typeArgument in namedType.TypeArguments) - { - EncodeSymbol(new Symbol(typeArgument), genericType.AddArgument()); - } - } - else if(symbol.Type.SpecialType != SpecialType.None) - { - EncodeSpecialType(symbol.Type.SpecialType, typeEncoder); - } - else - { - typeEncoder.Type(GetTypeReference(symbol.Type), symbol.Type.TypeKind == TypeKind.Enum); - } - } - - private void EncodeReturnType(Symbol symbol, ReturnTypeEncoder returnTypeEncoder) - { - if(symbol == null) - { - returnTypeEncoder.Void(); - } - else if(symbol.IsHandle() || symbol.Type.SpecialType == SpecialType.None) - { - EncodeSymbol(symbol, returnTypeEncoder.Type()); - } - else if(symbol.Type.SpecialType == SpecialType.System_Void) - { - returnTypeEncoder.Void(); - } - else - { - EncodeSpecialType(symbol.Type.SpecialType, returnTypeEncoder.Type()); - } - } - - private void EncodeParameters(Parameter[] parameters, ParametersEncoder parametersEncoder) - { - foreach (var parameter in parameters) - { - var parameterType = parameter.Type; - var parameterTypeEncoder = parametersEncoder.AddParameter(); - - if (!parameterType.IsHandle() && parameterType.Type.SpecialType != SpecialType.None) - { - EncodeSpecialType(parameterType.Type.SpecialType, parameterTypeEncoder.Type()); - } - else - { - EncodeSymbol(parameterType, parameterTypeEncoder.Type()); - } - } - } - - public MethodDefinitionHandle AddMethodDefinition( - string name, - Parameter[] parameters, - Symbol returnSymbol, - bool isStatic, - bool isInterfaceParent, - bool isSpecialMethod = false, - bool isPublic = true, - bool isOverridable = false) - { - var methodSignature = new BlobBuilder(); - new BlobEncoder(methodSignature) - .MethodSignature( - SignatureCallingConvention.Default, - 0, - !isStatic) - .Parameters( - parameters.Length, - returnType => EncodeReturnType(returnSymbol, returnType), - parametersEncoder => EncodeParameters(parameters, parametersEncoder) - ); - - List parameterHandles = new List(); - for (int idx = 0; idx < parameters.Length; idx++) - { - parameterHandles.Add(metadataBuilder.AddParameter( - parameters[idx].Attributes, - metadataBuilder.GetOrAddString(parameters[idx].Name), - idx + 1)); - } - - var methodAttributes = - (isPublic ? MethodAttributes.Public : MethodAttributes.Private) | - MethodAttributes.HideBySig; - - var methodImplAttributes = MethodImplAttributes.Managed; - - if (isInterfaceParent) - { - methodAttributes |= MethodAttributes.Abstract; - } - else - { - // TODO check if from overridable interface - if (!isOverridable) - { - methodAttributes |= MethodAttributes.Final; - } - methodImplAttributes |= MethodImplAttributes.Runtime; - } - - if (isSpecialMethod && name == ".ctor") - { - methodAttributes |= MethodAttributes.RTSpecialName; - } - else if(isStatic) - { - methodAttributes |= MethodAttributes.Static; - } - else - { - methodAttributes |= - MethodAttributes.Virtual | - MethodAttributes.NewSlot; - } - - if (isSpecialMethod) - { - methodAttributes |= MethodAttributes.SpecialName; - } - - var methodDefinitionHandle = metadataBuilder.AddMethodDefinition( - methodAttributes, - methodImplAttributes, - metadataBuilder.GetOrAddString(name), - metadataBuilder.GetOrAddBlob(methodSignature), - -1, - parameterHandles.Count == 0 ? - MetadataTokens.ParameterHandle(metadataBuilder.GetRowCount(TableIndex.Param) + 1) : - parameterHandles[0]); - return methodDefinitionHandle; - } - - public override void VisitMethodDeclaration(MethodDeclarationSyntax node) - { - Logger.Log("method: " + node.Identifier.ValueText); - if(!IsPublicNode(node)) - { - return; - } - - base.VisitMethodDeclaration(node); - - int numParameters = node.ParameterList.Parameters.Count; - Parameter[] parameters = new Parameter[numParameters]; - for(int idx = 0; idx < numParameters; idx++) - { - parameters[idx] = new Parameter(node.ParameterList.Parameters[idx], ParameterAttributes.In, Model); - } - - var methodSymbol = Model.GetDeclaredSymbol(node); - var methodDefinitionHandle = AddMethodDefinition( - methodSymbol.Name, - parameters, - new Symbol(methodSymbol.ReturnType), - IsStaticNode(node), - node.Parent is InterfaceDeclarationSyntax); - currentTypeDeclaration.AddMethod(methodSymbol, methodSymbol.Name, methodDefinitionHandle); - } - - public override void VisitFieldDeclaration(FieldDeclarationSyntax node) - { - if (!IsPublicNode(node) || node.Parent is not StructDeclarationSyntax) - { - return; - } - - base.VisitFieldDeclaration(node); - - var symbol = Model.GetTypeInfo(node.Declaration.Type).Type; - var fieldSignature = new BlobBuilder(); - var encoder = new BlobEncoder(fieldSignature); - - if (symbol.SpecialType != SpecialType.None) - { - EncodeSpecialType(symbol.SpecialType, encoder.FieldSignature()); - } - else - { - EncodeSymbol(new Symbol(symbol), encoder.FieldSignature()); - } - - foreach (var variable in node.Declaration.Variables) - { - var fieldSymbol = Model.GetDeclaredSymbol(variable); - var fieldDefinitionHandle = metadataBuilder.AddFieldDefinition( - FieldAttributes.Public, - metadataBuilder.GetOrAddString(variable.Identifier.Text), - metadataBuilder.GetOrAddBlob(fieldSignature)); - currentTypeDeclaration.AddField(fieldSymbol, fieldDefinitionHandle); - } - } - - public void AddPropertyDeclaration(IPropertySymbol property, bool isInterfaceParent) - { - Logger.Log("defining property " + property.Name); - Logger.Log("parent: " + property.ContainingType.Name); - - var propertySignature = new BlobBuilder(); - new BlobEncoder(propertySignature) - .PropertySignature(true) - .Parameters( - 0, - returnType => EncodeReturnType(new Symbol(property.Type), returnType), - parameters => { } - ); - - var propertyDefinitonHandle = metadataBuilder.AddProperty( - PropertyAttributes.None, - metadataBuilder.GetOrAddString(property.Name), - metadataBuilder.GetOrAddBlob(propertySignature)); - currentTypeDeclaration.AddProperty(property, propertyDefinitonHandle); - - if (property.SetMethod != null) - { - string setMethodName = "put_" + property.Name; - var setMethod = AddMethodDefinition( - setMethodName, - new Parameter[] { new Parameter(property.Type, "value", ParameterAttributes.In) }, - null, - false, - isInterfaceParent, - true); - currentTypeDeclaration.AddMethod(property, setMethodName, setMethod); - - metadataBuilder.AddMethodSemantics( - propertyDefinitonHandle, - MethodSemanticsAttributes.Setter, - setMethod); - } - - string getMethodName = "get_" + property.Name; - var getMethod = AddMethodDefinition( - getMethodName, - new Parameter[0], - new Symbol(property.Type), - false, - isInterfaceParent, - true); - currentTypeDeclaration.AddMethod(property, getMethodName, getMethod); - - metadataBuilder.AddMethodSemantics( - propertyDefinitonHandle, - MethodSemanticsAttributes.Getter, - getMethod); - } - - public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node) - { - if (!IsPublicNode(node)) - { - return; - } - - base.VisitPropertyDeclaration(node); - - var symbol = Model.GetDeclaredSymbol(node); - - var propertySignature = new BlobBuilder(); - new BlobEncoder(propertySignature) - .PropertySignature(true) - .Parameters( - 0, - returnType => EncodeReturnType(new Symbol(symbol.Type), returnType), - parameters => { } - ); - - var propertyDefinitonHandle = metadataBuilder.AddProperty( - PropertyAttributes.None, - metadataBuilder.GetOrAddString(node.Identifier.ValueText), - metadataBuilder.GetOrAddBlob(propertySignature)); - currentTypeDeclaration.AddProperty(symbol, propertyDefinitonHandle); - - var isGetPublic = true; - var isSetPublic = true; - - /* - TODO: support for private set with default interface support - - if (node.AccessorList != null) - { - foreach (var accessor in node.AccessorList.Accessors) - { - if(accessor.Keyword.Kind() == SyntaxKind.GetKeyword) - { - isGetPublic = !IsPrivateNode(accessor); - } - else if(accessor.Keyword.Kind() == SyntaxKind.SetKeyword) - { - isSetPublic = !IsPrivateNode(accessor); - } - } - } - */ - - if (symbol.SetMethod != null && isSetPublic) - { - string setMethodName = "put_" + symbol.Name; - var setMethod = AddMethodDefinition( - setMethodName, - new Parameter[] { new Parameter(symbol.Type, "value", ParameterAttributes.In ) }, - null, - false, - node.Parent is InterfaceDeclarationSyntax, - true); - currentTypeDeclaration.AddMethod(symbol, setMethodName, setMethod); - - metadataBuilder.AddMethodSemantics( - propertyDefinitonHandle, - MethodSemanticsAttributes.Setter, - setMethod); - } - - if (!symbol.IsWriteOnly && isGetPublic) - { - string getMethodName = "get_" + symbol.Name; - var getMethod = AddMethodDefinition( - getMethodName, - new Parameter[0], - new Symbol(symbol.Type), - false, - node.Parent is InterfaceDeclarationSyntax, - true); - currentTypeDeclaration.AddMethod(symbol, getMethodName, getMethod); - - metadataBuilder.AddMethodSemantics( - propertyDefinitonHandle, - MethodSemanticsAttributes.Getter, - getMethod); - } - } - - private TypeDefinitionHandle AddTypeDefinition( - TypeAttributes typeAttributes, - string @namespace, - string identifier, - EntityHandle baseType) - { - var fieldDefinitions = currentTypeDeclaration.GetFieldDefinitions(); - var methodDefinitions = currentTypeDeclaration.GetMethodDefinitions(); - - var typeDefinitionHandle = metadataBuilder.AddTypeDefinition( - typeAttributes, - metadataBuilder.GetOrAddString(@namespace), - metadataBuilder.GetOrAddString(identifier), - baseType, - fieldDefinitions.Count == 0 ? - MetadataTokens.FieldDefinitionHandle(metadataBuilder.GetRowCount(TableIndex.Field) + 1) : - fieldDefinitions[0], - methodDefinitions.Count == 0 ? - MetadataTokens.MethodDefinitionHandle(metadataBuilder.GetRowCount(TableIndex.MethodDef) + 1) : - methodDefinitions[0] - ); - - var propertyDefinitions = currentTypeDeclaration.GetPropertyDefinitions(); - if (propertyDefinitions.Count != 0) - { - metadataBuilder.AddPropertyMap( - typeDefinitionHandle, - propertyDefinitions[0]); - } - - var eventDefinitions = currentTypeDeclaration.GetEventDefinitions(); - if (eventDefinitions.Count != 0) - { - metadataBuilder.AddEventMap( - typeDefinitionHandle, - eventDefinitions[0]); - } - - return typeDefinitionHandle; - } - - private void ProcessTypeDeclaration(BaseTypeDeclarationSyntax node, Action visitTypeDeclaration) - { - if(!IsPublicNode(node)) - { - return; - } - - var symbol = Model.GetDeclaredSymbol(node); - currentTypeDeclaration = new TypeDeclaration(symbol); - - visitTypeDeclaration(); - - TypeAttributes typeAttributes = - TypeAttributes.Public | - TypeAttributes.WindowsRuntime | - TypeAttributes.AutoLayout | - TypeAttributes.AnsiClass; - - if (IsSealedNode(node) || - (node is EnumDeclarationSyntax || - node is StructDeclarationSyntax)) - { - typeAttributes |= TypeAttributes.Sealed; - } - - EntityHandle baseType = default; - if(node is InterfaceDeclarationSyntax) - { - typeAttributes |= - TypeAttributes.Interface | - TypeAttributes.Abstract; - } - else if(node is ClassDeclarationSyntax) - { - typeAttributes |= - TypeAttributes.Class | - TypeAttributes.BeforeFieldInit; - - // extends - if (node.BaseList != null) - { - foreach (var type in node.BaseList.Types) - { - var typeSymbol = Model.GetTypeInfo(type.Type).Type; - if(typeSymbol.TypeKind == TypeKind.Class) - { - baseType = GetTypeReference(typeSymbol); - break; - } - } - } - - if (baseType == default) - { - baseType = GetTypeReference("System", "Object", "mscorlib"); - } - } - else if(node is StructDeclarationSyntax) - { - typeAttributes |= TypeAttributes.SequentialLayout; - baseType = GetTypeReference("System", "ValueType", "mscorlib"); - } - else if(node is EnumDeclarationSyntax) - { - baseType = GetTypeReference("System", "Enum", "mscorlib"); - } - - var typeDefinitionHandle = AddTypeDefinition( - typeAttributes, - GetNamespace(), - node.Identifier.ValueText, - baseType); - currentTypeDeclaration.Handle = typeDefinitionHandle; - - if (node.BaseList != null && (node is InterfaceDeclarationSyntax || node is ClassDeclarationSyntax)) - { - foreach (var implementedInterface in symbol.AllInterfaces. - OrderBy(implementedInterface => implementedInterface.ToString())) - { - var interfaceImplHandle = metadataBuilder.AddInterfaceImplementation( - typeDefinitionHandle, - GetTypeReference(implementedInterface)); - currentTypeDeclaration.AddInterfaceImpl(implementedInterface, interfaceImplHandle); - } - } - - typeDefinitionMapping[QualifiedName(node.Identifier.ValueText)] = currentTypeDeclaration; - } - - public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) - { - ProcessTypeDeclaration(node, () => base.VisitInterfaceDeclaration(node)); - - var interfaceTypeDeclaration = currentTypeDeclaration; - AddGuidAttribute(interfaceTypeDeclaration.Handle, interfaceTypeDeclaration.Node.ToString()); - AddOverloadAttributeForInterfaceMethods(interfaceTypeDeclaration); - } - - public override void VisitClassDeclaration(ClassDeclarationSyntax node) - { - void processClassDeclaration() - { - hasConstructor = false; - hasDefaultConstructor = false; - base.VisitClassDeclaration(node); - - // implicit constructor if none defined - if(!hasConstructor) - { - string constructorMethodName = ".ctor"; - var methodDefinitionHandle = AddMethodDefinition( - constructorMethodName, - new Parameter[0], - null, - false, - false, - true, - true, - true); - var symbol = Model.GetDeclaredSymbol(node); - currentTypeDeclaration.AddMethod(symbol, constructorMethodName, methodDefinitionHandle); - hasDefaultConstructor = true; - } - } - - ProcessTypeDeclaration(node, processClassDeclaration); - - if (IsPublicNode(node)) - { - var classDeclaration = currentTypeDeclaration; - var classSymbol = classDeclaration.Node as INamedTypeSymbol; - - if (hasDefaultConstructor) - { - AddActivatableAttribute( - classDeclaration.Handle, - (uint)GetVersion(classSymbol, true), - null); - } - AddSynthesizedInterfaces(classDeclaration); - - // No synthesized default interface generated - if(classDeclaration.DefaultInterface == null && classSymbol.Interfaces.Length != 0) - { - AddDefaultInterfaceImplAttribute(classDeclaration.InterfaceImplDefinitions[classSymbol.Interfaces[0]]); - } - } - } - - public override void VisitStructDeclaration(StructDeclarationSyntax node) - { - ProcessTypeDeclaration(node, () => base.VisitStructDeclaration(node)); - } - - private void EncodeTypedConstant(TypedConstant constant, LiteralEncoder encoder) - { - Logger.Log("typed constant kind: " + constant.Kind); - Logger.Log("typed constant type: " + constant.Type); - Logger.Log("typed constant value: " + constant.Value); - - switch (constant.Kind) - { - case TypedConstantKind.Primitive: - encoder.Scalar().Constant(constant.Value); - break; - case TypedConstantKind.Enum: - encoder.TaggedScalar( - type => type.Enum(constant.Type.ToString()), - scalar => scalar.Constant(constant.Value) - ); - break; - case TypedConstantKind.Type: - encoder.Scalar().SystemType(constant.Type.ToString()); - break; - case TypedConstantKind.Array: - { - LiteralsEncoder arrayEncoder = encoder.Vector().Count(constant.Values.Length); - foreach(var arrayConstant in constant.Values) - { - EncodeTypedConstant(arrayConstant, arrayEncoder.AddLiteral()); - } - break; - } - } - - } - - private void EncodeFixedArguments(IList arguments, FixedArgumentsEncoder argumentsEncoder) - { - foreach(var argument in arguments) - { - EncodeTypedConstant(argument, argumentsEncoder.AddArgument()); - } - } - - private void EncodeCustomElementType(IFieldSymbol field, CustomAttributeElementTypeEncoder typeEncoder) - { - switch (field.Type.SpecialType) - { - case SpecialType.System_Boolean: - typeEncoder.Boolean(); - break; - case SpecialType.System_Byte: - typeEncoder.Byte(); - break; - case SpecialType.System_Int16: - typeEncoder.Int16(); - break; - case SpecialType.System_Int32: - typeEncoder.Int32(); - break; - case SpecialType.System_Int64: - typeEncoder.Int64(); - break; - case SpecialType.System_UInt16: - typeEncoder.UInt16(); - break; - case SpecialType.System_UInt32: - typeEncoder.UInt32(); - break; - case SpecialType.System_UInt64: - typeEncoder.UInt64(); - break; - case SpecialType.System_Single: - typeEncoder.Single(); - break; - case SpecialType.System_Double: - typeEncoder.Double(); - break; - case SpecialType.System_Char: - typeEncoder.Char(); - break; - case SpecialType.System_String: - typeEncoder.String(); - break; - case SpecialType.System_Enum: - typeEncoder.Enum(field.Type.ToString()); - break; - case SpecialType.System_SByte: - typeEncoder.SByte(); - break; - default: - Logger.Log("TODO special type: " + field.Type.SpecialType); - break; - } - } - - private void EncodeNamedArgumentType(INamedTypeSymbol attributeType, string field, NamedArgumentTypeEncoder encoder) - { - Logger.Log("encoding named type"); - var fieldMembers = attributeType.GetMembers(field); - Logger.Log("# fields: " + fieldMembers.Count()); - var fieldSymbol = fieldMembers.First() as IFieldSymbol; - Logger.Log("found field: " + fieldSymbol); - - if(fieldSymbol.Type.SpecialType == SpecialType.System_Object) - { - encoder.Object(); - } - else if(fieldSymbol.Type.SpecialType == SpecialType.System_Array) - { - // TODO array type encoder - encoder.SZArray(); - } - else - { - EncodeCustomElementType(fieldSymbol, encoder.ScalarType()); - } - } - - private void EncodeNamedArguments( - INamedTypeSymbol attributeType, - IList> namedArguments, - CustomAttributeNamedArgumentsEncoder argumentsEncoder) - { - var encoder = argumentsEncoder.Count(namedArguments.Count); - foreach (var argument in namedArguments) - { - Logger.Log("named argument: " + argument.Key); - Logger.Log("value " + argument.Value); - - encoder.AddArgument( - true, - type => EncodeNamedArgumentType(attributeType, argument.Key, type), - name => name.Name(argument.Key), - literal => EncodeTypedConstant(argument.Value, literal) - ); - } - } - - private void EncodeFixedArguments(IList primitiveArguments, FixedArgumentsEncoder argumentsEncoder) - { - foreach (var argument in primitiveArguments) - { - var encoder = argumentsEncoder.AddArgument().Scalar(); - if(argument is string type) - { - encoder.SystemType(type); - } - else - { - encoder.Constant(argument); - } - } - } - - private void AddDefaultVersionAttribute(EntityHandle parentHandle, int version = -1) - { - if(version == -1) - { - version = Version.Parse(this.version).Major; - } - - List types = new List - { - Model.Compilation.GetTypeByMetadataName("System.UInt32") - }; - - List arguments = new List - { - (UInt32) version - }; - - AddCustomAttributes("Windows.Foundation.Metadata.VersionAttribute", types, arguments, parentHandle); - } - - private void AddActivatableAttribute(EntityHandle parentHandle, UInt32 version, string factoryInterface) - { - List types = new List(2); - List arguments = new List(2); - - if(factoryInterface != null) - { - types.Add(Model.Compilation.GetTypeByMetadataName("System.Type")); - arguments.Add(factoryInterface); - } - types.Add(Model.Compilation.GetTypeByMetadataName("System.UInt32")); - arguments.Add(version); - - AddCustomAttributes("Windows.Foundation.Metadata.ActivatableAttribute", types, arguments, parentHandle); - } - - private void AddExclusiveToAttribute(EntityHandle interfaceHandle, string className) - { - List types = new List - { - Model.Compilation.GetTypeByMetadataName("System.Type") - }; - - List arguments = new List - { - className - }; - - AddCustomAttributes("Windows.Foundation.Metadata.ExclusiveToAttribute", types, arguments, interfaceHandle); - } - - private void AddStaticAttribute(EntityHandle parentHandle, UInt32 version, string staticInterface) - { - List types = new List - { - Model.Compilation.GetTypeByMetadataName("System.Type"), - Model.Compilation.GetTypeByMetadataName("System.UInt32") - }; - - List arguments = new List - { - staticInterface, - version - }; - - AddCustomAttributes("Windows.Foundation.Metadata.StaticAttribute", types, arguments, parentHandle); - } - - private void AddDefaultInterfaceImplAttribute(EntityHandle interfaceImplHandle) - { - AddCustomAttributes("Windows.Foundation.Metadata.DefaultAttribute", Array.Empty(), Array.Empty(), interfaceImplHandle); - } - - private void AddOverloadAttribute(EntityHandle methodHandle, string methodName) - { - List types = new List - { - Model.Compilation.GetTypeByMetadataName("System.String") - }; - - List arguments = new List - { - methodName - }; - - AddCustomAttributes("Windows.Foundation.Metadata.OverloadAttribute", types, arguments, methodHandle); - } - - private void AddOverloadAttributeForInterfaceMethods(TypeDeclaration interfaceTypeDeclaration) - { - // Generate unique names for any overloaded methods - foreach (var methodName in interfaceTypeDeclaration.MethodsByName.Where(symbol => symbol.Value.Count > 1)) - { - var methodSymbols = methodName.Value.Where(symbol => symbol is IMethodSymbol); - // Other members that are not methods such as properties and events can generate reserved methods - // which for the purposes of overloading are considered to be the non overloaded version. If there is no - // such function, then we consider the first encountered method to be the non overloaded version. - var skipFirstMethod = methodName.Value.Count == methodSymbols.Count(); - var lastSuffix = 1; - foreach (var method in methodSymbols) - { - if (skipFirstMethod) - { - skipFirstMethod = false; - continue; - } - - string overloadedMethodName = methodName.Key + (++lastSuffix); - while (interfaceTypeDeclaration.MethodsByName.ContainsKey(overloadedMethodName)) - { - overloadedMethodName = methodName.Key + (++lastSuffix); - } - - Logger.Log("Overloading " + methodName.Key + " with " + overloadedMethodName); - AddOverloadAttribute(interfaceTypeDeclaration.MethodDefinitions[method].First(), overloadedMethodName); - interfaceTypeDeclaration.AddMethodOverload(method, overloadedMethodName); - } - } - } - - private void AddGuidAttribute(EntityHandle parentHandle, string name) - { - Guid guid; - using (SHA1 sha = new SHA1CryptoServiceProvider()) - { - var hash = sha.ComputeHash(Encoding.UTF8.GetBytes(name)); - guid = Helper.EncodeGuid(hash); - } - - var uint32Type = Model.Compilation.GetTypeByMetadataName("System.UInt32"); - var uint16Type = Model.Compilation.GetTypeByMetadataName("System.UInt16"); - var byteType = Model.Compilation.GetTypeByMetadataName("System.Byte"); - List types = new List - { - uint32Type, - uint16Type, - uint16Type, - byteType, - byteType, - byteType, - byteType, - byteType, - byteType, - byteType, - byteType - }; - - var byteArray = guid.ToByteArray(); - List arguments = new List - { - BitConverter.ToUInt32(byteArray, 0), - BitConverter.ToUInt16(byteArray, 4), - BitConverter.ToUInt16(byteArray, 6), - byteArray[8], - byteArray[9], - byteArray[10], - byteArray[11], - byteArray[12], - byteArray[13], - byteArray[14], - byteArray[15] - }; - - AddCustomAttributes("Windows.Foundation.Metadata.GuidAttribute", types, arguments, parentHandle); - } - - private void AddCustomAttributes( - string attributeTypeName, - IList primitiveTypes, - IList primitiveValues, - EntityHandle parentHandle) - { - var attributeType = Model.Compilation.GetTypeByMetadataName(attributeTypeName); - Logger.Log("attribute type found " + attributeType); - if (!typeDefinitionMapping.ContainsKey(attributeTypeName)) - { - Logger.Log("adding attribute type"); - AddType(attributeType); - } - - Logger.Log("# constructor found: " + attributeType.Constructors.Length); - var matchingConstructor = attributeType.Constructors.Where(constructor => - constructor.Parameters.Length == primitiveValues.Count && - constructor.Parameters.Select(param => param.Type).SequenceEqual(primitiveTypes)); - - Logger.Log("# matching constructor found: " + matchingConstructor.Count()); - Logger.Log("matching constructor found: " + matchingConstructor.First()); - - var constructorReference = typeDefinitionMapping[attributeTypeName].MethodReferences[matchingConstructor.First()]; - Logger.Log("found constructor handle: " + constructorReference.Count); - - var attributeSignature = new BlobBuilder(); - new BlobEncoder(attributeSignature) - .CustomAttributeSignature( - fixedArguments => EncodeFixedArguments(primitiveValues, fixedArguments), - namedArguments => namedArguments.Count(0) - ); - - metadataBuilder.AddCustomAttribute( - parentHandle, - constructorReference.First(), - metadataBuilder.GetOrAddBlob(attributeSignature)); - } - - private void AddCustomAttributes(IList attributes, EntityHandle parentHandle) - { - foreach (var attribute in attributes) - { - var attributeType = attribute.AttributeClass; - - Logger.Log("attribute: " + attribute); - Logger.Log("attribute type: " + attributeType); - Logger.Log("attribute constructor: " + attribute.AttributeConstructor); - Logger.Log("atttribute # constructor arguments: " + attribute.ConstructorArguments.Length); - Logger.Log("atttribute # named arguments: " + attribute.NamedArguments.Length); - - if (!typeDefinitionMapping.ContainsKey(attributeType.ToString())) - { - AddType(attributeType); - } - - var constructorReference = typeDefinitionMapping[attributeType.ToString()].MethodReferences[attribute.AttributeConstructor]; - Logger.Log("found # constructors: " + constructorReference.Count); - - var attributeSignature = new BlobBuilder(); - new BlobEncoder(attributeSignature) - .CustomAttributeSignature( - fixedArguments => EncodeFixedArguments(attribute.ConstructorArguments, fixedArguments), - namedArguments => EncodeNamedArguments(attributeType, attribute.NamedArguments, namedArguments) - ); - - metadataBuilder.AddCustomAttribute( - parentHandle, - constructorReference.First(), - metadataBuilder.GetOrAddBlob(attributeSignature)); - } - } - - public override void VisitAttributeList(AttributeListSyntax node) - { - base.VisitAttributeList(node); - - // Skip assembly attributes - if(node.Target != null && node.Target.Identifier.ValueText == "assembly") - { - return; - } - - var parentSymbol = Model.GetDeclaredSymbol(node.Parent); - nodesWithAttributes.Add(parentSymbol); - } - - public override void VisitEnumDeclaration(EnumDeclarationSyntax node) - { - void processEnumDeclaration() - { - var enumTypeFieldAttributes = - FieldAttributes.Private | - FieldAttributes.SpecialName | - FieldAttributes.RTSpecialName; - - var symbol = Model.GetDeclaredSymbol(node); - var enumTypeSymbol = symbol.EnumUnderlyingType; - var fieldSignature = new BlobBuilder(); - var encoder = new BlobEncoder(fieldSignature); - // TODO: special type enforcement for 64 bit - EncodeSpecialType(enumTypeSymbol.SpecialType, encoder.FieldSignature()); - - var fieldDefinitionHandle = metadataBuilder.AddFieldDefinition( - enumTypeFieldAttributes, - metadataBuilder.GetOrAddString("value__"), - metadataBuilder.GetOrAddBlob(fieldSignature)); - currentTypeDeclaration.AddField(symbol, fieldDefinitionHandle); - - base.VisitEnumDeclaration(node); - } - - ProcessTypeDeclaration(node, processEnumDeclaration); - } - - public override void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) - { - base.VisitEnumMemberDeclaration(node); - - var enumFieldAttributes = - FieldAttributes.Public | - FieldAttributes.Static | - FieldAttributes.Literal | - FieldAttributes.HasDefault; - - var symbol = Model.GetDeclaredSymbol(node); - var fieldSignature = new BlobBuilder(); - var encoder = new BlobEncoder(fieldSignature); - EncodeSymbol(new Symbol(symbol.ContainingType), encoder.FieldSignature()); - - var fieldDefinitionHandle = metadataBuilder.AddFieldDefinition( - enumFieldAttributes, - metadataBuilder.GetOrAddString(node.Identifier.Text), - metadataBuilder.GetOrAddBlob(fieldSignature)); - currentTypeDeclaration.AddField(symbol, fieldDefinitionHandle); - - if (symbol.HasConstantValue) - { - metadataBuilder.AddConstant(fieldDefinitionHandle, symbol.ConstantValue); - } - } - - public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node) - { - if (!IsPublicNode(node)) - { - return; - } - - var symbol = Model.GetDeclaredSymbol(node); - currentTypeDeclaration = new TypeDeclaration(symbol); - - base.VisitDelegateDeclaration(node); - - var objType = Model.Compilation.GetTypeByMetadataName(typeof(object).FullName); - var nativeIntType = Model.Compilation.GetTypeByMetadataName(typeof(IntPtr).FullName); - - currentTypeDeclaration.AddMethod( - symbol, - ".ctor", - AddMethodDefinition( - ".ctor", - new Parameter[] { - new Parameter(objType, "object", ParameterAttributes.None), - new Parameter(nativeIntType, "method", ParameterAttributes.None) - }, - null, - false, - false, - true, - false, - true - ) - ); - - int numParameters = node.ParameterList.Parameters.Count; - Parameter[] parameters = new Parameter[numParameters]; - for (int idx = 0; idx < numParameters; idx++) - { - parameters[idx] = new Parameter(node.ParameterList.Parameters[idx], ParameterAttributes.In, Model); - } - - currentTypeDeclaration.AddMethod( - symbol, - "Invoke", - AddMethodDefinition( - "Invoke", - parameters, - new Symbol(symbol.DelegateInvokeMethod.ReturnType), - false, - false, - true, - true, - true - ) - ); - - TypeAttributes typeAttributes = - TypeAttributes.Public | - TypeAttributes.WindowsRuntime | - TypeAttributes.AutoLayout | - TypeAttributes.AnsiClass | - TypeAttributes.Sealed; - - var typeDefinitionHandle = AddTypeDefinition( - typeAttributes, - GetNamespace(), - node.Identifier.ValueText, - GetTypeReference("System", "MulticastDelegate", "mscorlib")); - currentTypeDeclaration.Handle = typeDefinitionHandle; - AddGuidAttribute(typeDefinitionHandle, symbol.ToString()); - } - - public void AddEventDeclaration(IEventSymbol @event, bool isInterfaceParent) - { - Logger.Log("defining event " + @event.Name); - - var delegateSymbolType = @event.Type; - EntityHandle typeReferenceHandle = GetTypeReference(delegateSymbolType); - EntityHandle eventRegistrationTokenTypeHandle = GetTypeReference("Windows.Foundation", "EventRegistrationToken", "Windows.Foundation.FoundationContract"); - Symbol eventRegistrationToken = new Symbol(eventRegistrationTokenTypeHandle); - - var eventDefinitionHandle = metadataBuilder.AddEvent( - EventAttributes.None, - metadataBuilder.GetOrAddString(@event.Name), - typeReferenceHandle); - currentTypeDeclaration.AddEvent(@event, eventDefinitionHandle); - - string addMethodName = "add_" + @event.Name; - var addMethod = AddMethodDefinition( - addMethodName, - new Parameter[] { new Parameter(delegateSymbolType, "handler", ParameterAttributes.In) }, - eventRegistrationToken, - false, - isInterfaceParent, - true); - currentTypeDeclaration.AddMethod(@event, addMethodName, addMethod); - - metadataBuilder.AddMethodSemantics( - eventDefinitionHandle, - MethodSemanticsAttributes.Adder, - addMethod); - - string removeMethodName = "remove_" + @event.Name; - var removeMethod = AddMethodDefinition( - removeMethodName, - new Parameter[] { new Parameter(eventRegistrationToken, "token", ParameterAttributes.In) }, - null, - false, - isInterfaceParent, - true); - currentTypeDeclaration.AddMethod(@event, removeMethodName, removeMethod); - - metadataBuilder.AddMethodSemantics( - eventDefinitionHandle, - MethodSemanticsAttributes.Remover, - removeMethod); - } - - public override void VisitEventFieldDeclaration(EventFieldDeclarationSyntax node) - { - if (!IsPublicNode(node)) - { - return; - } - - base.VisitEventFieldDeclaration(node); - - var delegateSymbolType = Model.GetTypeInfo(node.Declaration.Type).Type; - EntityHandle typeReferenceHandle = GetTypeReference(delegateSymbolType); - EntityHandle eventRegistrationTokenTypeHandle = GetTypeReference("Windows.Foundation", "EventRegistrationToken", "Windows.Foundation.FoundationContract"); - Symbol eventRegistrationToken = new Symbol(eventRegistrationTokenTypeHandle); - - foreach (var declaration in node.Declaration.Variables) - { - var eventSymbol = Model.GetDeclaredSymbol(declaration); - var eventDefinitionHandle = metadataBuilder.AddEvent( - EventAttributes.None, - metadataBuilder.GetOrAddString(declaration.Identifier.ValueText), - typeReferenceHandle); - currentTypeDeclaration.AddEvent(eventSymbol, eventDefinitionHandle); - - string addMethodName = "add_" + declaration.Identifier.ValueText; - var addMethod = AddMethodDefinition( - addMethodName, - new Parameter[] { new Parameter(delegateSymbolType, "handler", ParameterAttributes.In) }, - eventRegistrationToken, - false, - node.Parent is InterfaceDeclarationSyntax, - true); - currentTypeDeclaration.AddMethod(eventSymbol, addMethodName, addMethod); - - metadataBuilder.AddMethodSemantics( - eventDefinitionHandle, - MethodSemanticsAttributes.Adder, - addMethod); - - string removeMethodName = "remove_" + declaration.Identifier.ValueText; - var removeMethod = AddMethodDefinition( - removeMethodName, - new Parameter[] { new Parameter(eventRegistrationToken, "token", ParameterAttributes.In) }, - null, - false, - node.Parent is InterfaceDeclarationSyntax, - true); - currentTypeDeclaration.AddMethod(eventSymbol, removeMethodName, removeMethod); - - metadataBuilder.AddMethodSemantics( - eventDefinitionHandle, - MethodSemanticsAttributes.Remover, - removeMethod); - } - } - - public override void VisitConstructorDeclaration(ConstructorDeclarationSyntax node) - { - hasConstructor = true; - - if (!IsPublicNode(node)) - { - return; - } - - base.VisitConstructorDeclaration(node); - - var symbol = Model.GetDeclaredSymbol(node); - int numParameters = node.ParameterList.Parameters.Count; - Parameter[] parameters = new Parameter[numParameters]; - for (int idx = 0; idx < numParameters; idx++) - { - parameters[idx] = new Parameter(node.ParameterList.Parameters[idx], ParameterAttributes.In, Model); - } - - var methodDefinitionHandle = AddMethodDefinition( - ".ctor", - parameters, - null, - false, - false, - true, - true, - true); - currentTypeDeclaration.AddMethod(symbol, ".ctor", methodDefinitionHandle); - hasDefaultConstructor |= (numParameters == 0); - } - - void AddMethodDeclaration(IMethodSymbol method, bool isInterfaceParent) - { - Logger.Log("add method from symbol: " + method.Name); - - int numParameters = method.Parameters.Count(); - Parameter[] parameters = new Parameter[numParameters]; - for (int idx = 0; idx < numParameters; idx++) - { - parameters[idx] = new Parameter(method.Parameters[idx].Type, method.Parameters[idx].Name, ParameterAttributes.In); - } - - string methodName = method.MethodKind == MethodKind.Constructor ? ".ctor" : method.Name; - var methodDefinitionHandle = AddMethodDefinition( - methodName, - parameters, - new Symbol(method.ReturnType), - !isInterfaceParent && method.IsStatic, - isInterfaceParent, - method.MethodKind == MethodKind.Constructor, - true, - true); - currentTypeDeclaration.AddMethod(method, methodName, methodDefinitionHandle); - } - - void AddFactoryMethod(INamedTypeSymbol classSymbol, IMethodSymbol method) - { - Logger.Log("adding factory method: " + method.Name); - - int numParameters = method.Parameters.Count(); - Parameter[] parameters = new Parameter[numParameters]; - for (int idx = 0; idx < numParameters; idx++) - { - parameters[idx] = new Parameter(method.Parameters[idx].Type, method.Parameters[idx].Name, ParameterAttributes.In); - } - - string methodName = "Create" + classSymbol.Name; - var methodDefinitionHandle = AddMethodDefinition( - methodName, - parameters, - new Symbol(classSymbol), - false, - true, - false, - true, - true); - currentTypeDeclaration.AddMethod(method, methodName, methodDefinitionHandle); - } - - void AddExternalType(INamedTypeSymbol type) - { - // TODO: check if custom projected interface - // TODO: block or warn type names with namespaces not meeting WinRT requirements. - // TODO: synthesized interfaces and default interface impl. - // TODO: extends - - var typeDeclaration = new TypeDeclaration(type); - currentTypeDeclaration = typeDeclaration; - bool isInterface = type.TypeKind == TypeKind.Interface; - - foreach (var member in type.GetMembers()) - { - if(member is IMethodSymbol method && - (method.MethodKind == MethodKind.Ordinary || method.MethodKind == MethodKind.Constructor)) - { - AddMethodDeclaration(method, isInterface); - } - else if(member is IPropertySymbol property) - { - AddPropertyDeclaration(property, isInterface); - } - else if(member is IEventSymbol @event) - { - AddEventDeclaration(@event, isInterface); - } - else - { - Logger.Log("member not recognized: " + member.Kind + " name: " + member.Name); - } - } - - TypeAttributes typeAttributes = - TypeAttributes.Public | - TypeAttributes.WindowsRuntime | - TypeAttributes.AutoLayout | - TypeAttributes.AnsiClass | - TypeAttributes.Interface | - TypeAttributes.Abstract; - - var typeDefinitionHandle = AddTypeDefinition( - typeAttributes, - type.ContainingNamespace.ToString(), - type.Name, - default); - typeDeclaration.Handle = typeDefinitionHandle; - typeDefinitionMapping[type.ToString()] = typeDeclaration; - - foreach (var implementedInterface in type.AllInterfaces.OrderBy(implementedInterface => implementedInterface.ToString())) - { - var interfaceImplHandle = metadataBuilder.AddInterfaceImplementation( - typeDefinitionHandle, - GetTypeReference(implementedInterface)); - typeDeclaration.AddInterfaceImpl(implementedInterface, interfaceImplHandle); - } - - if (isInterface) - { - AddGuidAttribute(typeDefinitionHandle, type.ToString()); - AddOverloadAttributeForInterfaceMethods(typeDeclaration); - } - } - - MemberReferenceHandle AddMethodReference( - string name, - Parameter[] parameters, - Symbol returnSymbol, - ISymbol parentType, - bool isStatic) - { - var methodSignature = new BlobBuilder(); - new BlobEncoder(methodSignature) - .MethodSignature( - SignatureCallingConvention.Default, - 0, - !isStatic) - .Parameters( - parameters.Length, - returnType => EncodeReturnType(returnSymbol, returnType), - parametersEncoder => EncodeParameters(parameters, parametersEncoder) - ); - - var referenceHandle = metadataBuilder.AddMemberReference( - GetTypeReference(parentType), - metadataBuilder.GetOrAddString(name), - metadataBuilder.GetOrAddBlob(methodSignature) - ); - return referenceHandle; - } - - MemberReferenceHandle AddMethodReference(IMethodSymbol method) - { - Logger.Log("adding method reference: " + method.Name); - - bool isInterfaceParent = method.ContainingType.TypeKind == TypeKind.Interface; - int numParameters = method.Parameters.Count(); - Parameter[] parameters = new Parameter[numParameters]; - for (int idx = 0; idx < numParameters; idx++) - { - parameters[idx] = new Parameter(method.Parameters[idx].Type, method.Parameters[idx].Name, ParameterAttributes.In); - } - - string methodName = method.MethodKind == MethodKind.Constructor ? ".ctor" : method.Name; - - var referenceHandle = AddMethodReference( - methodName, - parameters, - new Symbol(method.ReturnType), - method.ContainingType, - !isInterfaceParent && method.IsStatic); - currentTypeDeclaration.AddMethodReference(method, referenceHandle); - return referenceHandle; - } - - public void AddPropertyReference(IPropertySymbol property) - { - Logger.Log("adding property reference: " + property.Name); - - if (property.SetMethod != null) - { - var setMethodReference = AddMethodReference( - "put_" + property.Name, - new Parameter[] { new Parameter(property.Type, "value", ParameterAttributes.In) }, - null, - property.ContainingType, - false); - currentTypeDeclaration.AddMethodReference(property, setMethodReference); - } - - var getMethodReference = AddMethodReference( - "get_" + property.Name, - new Parameter[0], - new Symbol(property.Type), - property.ContainingType, - false); - currentTypeDeclaration.AddMethodReference(property, getMethodReference); - } - - public void AddEventReference(IEventSymbol @event) - { - Logger.Log("adding event reference: " + @event.Name); - - var delegateSymbolType = @event.Type; - EntityHandle eventRegistrationTokenTypeHandle = GetTypeReference("Windows.Foundation", "EventRegistrationToken", "Windows.Foundation.FoundationContract"); - Symbol eventRegistrationToken = new Symbol(eventRegistrationTokenTypeHandle); - - var addMethodReference = AddMethodReference( - "add_" + @event.Name, - new Parameter[] { new Parameter(delegateSymbolType, "handler", ParameterAttributes.In) }, - eventRegistrationToken, - @event.ContainingType, - false); - currentTypeDeclaration.AddMethodReference(delegateSymbolType, addMethodReference); - - var removeMethodReference = AddMethodReference( - "remove_" + @event.Name, - new Parameter[] { new Parameter(eventRegistrationToken, "token", ParameterAttributes.In) }, - null, - @event.ContainingType, - false); - currentTypeDeclaration.AddMethodReference(delegateSymbolType, removeMethodReference); - } - - void AddProjectedType(INamedTypeSymbol type) - { - currentTypeDeclaration = new TypeDeclaration(type); - - foreach (var member in type.GetMembers()) - { - if (member is IMethodSymbol method && - (method.MethodKind == MethodKind.Ordinary || method.MethodKind == MethodKind.Constructor)) - { - AddMethodReference(method); - } - else if (member is IPropertySymbol property) - { - AddPropertyReference(property); - } - else if (member is IEventSymbol @event) - { - AddEventReference(@event); - } - else - { - Logger.Log("member not recognized: " + member.Kind + " " + member.Name); - } - } - - typeDefinitionMapping[type.ToString()] = currentTypeDeclaration; - } - - enum SynthesizedInterfaceType - { - Static, - Factory, - Default - } - - string GetSynthesizedInterfaceName(string className, SynthesizedInterfaceType type) - { - // TODO: handle existing types by appending number suffix - return "I" + className + - type switch - { - SynthesizedInterfaceType.Default => "Class", - SynthesizedInterfaceType.Factory => "Factory", - SynthesizedInterfaceType.Static => "Static", - _ => "", - }; - } - - void AddSynthesizedInterfaces(TypeDeclaration classDeclaration) - { - HashSet classMembersFromInterfaces = new HashSet(); - INamedTypeSymbol classSymbol = classDeclaration.Node as INamedTypeSymbol; - foreach (var @interface in classSymbol.AllInterfaces) - { - foreach(var interfaceMember in @interface.GetMembers()) - { - classMembersFromInterfaces.Add(classSymbol.FindImplementationForInterfaceMember(interfaceMember)); - } - } - - AddSynthesizedInterface( - classDeclaration, - SynthesizedInterfaceType.Static, - classMembersFromInterfaces); - - AddSynthesizedInterface( - classDeclaration, - SynthesizedInterfaceType.Factory, - classMembersFromInterfaces); - - AddSynthesizedInterface( - classDeclaration, - SynthesizedInterfaceType.Default, - classMembersFromInterfaces); - - // TODO: address overridable and composable interfaces. - } - - void AddSynthesizedInterface( - TypeDeclaration classDeclaration, - SynthesizedInterfaceType interfaceType, - HashSet classMembersFromInterfaces) - { - var typeDeclaration = new TypeDeclaration(null); - currentTypeDeclaration = typeDeclaration; - - bool hasTypes = false; - INamedTypeSymbol classSymbol = classDeclaration.Node as INamedTypeSymbol; - - // Each class member results in some form of method definition, - // so using that to our advantage to get public members. - foreach (var classMember in classDeclaration.MethodDefinitions) - { - if (interfaceType == SynthesizedInterfaceType.Factory && - classMember.Key is IMethodSymbol constructorMethod && - constructorMethod.MethodKind == MethodKind.Constructor && - constructorMethod.Parameters.Length != 0) - { - hasTypes = true; - AddFactoryMethod(classSymbol, constructorMethod); - } - else if((interfaceType == SynthesizedInterfaceType.Default && !classMember.Key.IsStatic && - !classMembersFromInterfaces.Contains(classMember.Key)) || - (interfaceType == SynthesizedInterfaceType.Static && classMember.Key.IsStatic)) - { - if (classMember.Key is IMethodSymbol method && method.MethodKind == MethodKind.Ordinary) - { - AddMethodDeclaration(method, true); - } - else if (classMember.Key is IPropertySymbol property) - { - AddPropertyDeclaration(property, true); - } - else if (classMember.Key is IEventSymbol @event) - { - AddEventDeclaration(@event, true); - } - else - { - Logger.Log("member for synthesized interface not recognized: " + classMember.Key.Kind + " " + classMember.Key.Name); - continue; - } - - hasTypes = true; - } - } - - TypeAttributes typeAttributes = - TypeAttributes.NotPublic | - TypeAttributes.WindowsRuntime | - TypeAttributes.AutoLayout | - TypeAttributes.AnsiClass | - TypeAttributes.Interface | - TypeAttributes.Abstract; - - if (hasTypes) - { - Logger.Log("writing generated interface " + interfaceType); - var interfaceName = GetSynthesizedInterfaceName(classDeclaration.Node.Name, interfaceType); - var typeDefinitionHandle = AddTypeDefinition( - typeAttributes, - classDeclaration.Node.ContainingNamespace.ToString(), - interfaceName, - default); - typeDeclaration.Handle = typeDefinitionHandle; - - string qualifiedInterfaceName = QualifiedName(classDeclaration.Node.ContainingNamespace.ToString(), interfaceName); - typeDefinitionMapping[qualifiedInterfaceName] = typeDeclaration; - - if(interfaceType == SynthesizedInterfaceType.Default) - { - classDeclaration.DefaultInterface = qualifiedInterfaceName; - var interfaceImplHandle = metadataBuilder.AddInterfaceImplementation( - classDeclaration.Handle, - GetTypeReference(classDeclaration.Node.ContainingNamespace.ToString(), interfaceName, assembly)); - classDeclaration.AddInterfaceImpl(classSymbol, interfaceImplHandle); - AddDefaultInterfaceImplAttribute(interfaceImplHandle); - } - - AddDefaultVersionAttribute(typeDefinitionHandle, GetVersion(classSymbol, true)); - AddGuidAttribute(typeDefinitionHandle, interfaceName); - AddExclusiveToAttribute(typeDefinitionHandle, classSymbol.ToString()); - AddOverloadAttributeForInterfaceMethods(typeDeclaration); - - if (interfaceType == SynthesizedInterfaceType.Factory) - { - AddActivatableAttribute(classDeclaration.Handle, (uint) GetVersion(classSymbol, true), qualifiedInterfaceName); - } - else if(interfaceType == SynthesizedInterfaceType.Static) - { - classDeclaration.StaticInterface = qualifiedInterfaceName; - AddStaticAttribute(classDeclaration.Handle, (uint)GetVersion(classSymbol, true), qualifiedInterfaceName); - } - } - } - - private int GetVersion(INamedTypeSymbol type, bool setDefaultIfNotSet = false) - { - var versionAttribute = type.GetAttributes(). - Where(attribute => attribute.AttributeClass.Name == "VersionAttribute"); - if(!versionAttribute.Any()) - { - return setDefaultIfNotSet ? Version.Parse(this.version).Major : - 1; - } - - uint version = (uint) versionAttribute.First().ConstructorArguments[0].Value; - return (int) version; - } - - void AddType(INamedTypeSymbol type) - { - bool isProjectedType = type.GetAttributes(). - Any(attribute => attribute.AttributeClass.Name == "WindowsRuntimeTypeAttribute"); - if (isProjectedType) - { - AddProjectedType(type); - } - else if(MappedCSharpTypes.ContainsKey(type.ToString())) - { - var mappedType = MappedCSharpTypes[type.ToString()]; - AddProjectedType(Model.Compilation.GetTypeByMetadataName(QualifiedName(mappedType.@namespace, mappedType.name))); - } - else - { - AddExternalType(type); - } - } - - public void FinalizeGeneration() - { - var classTypeDeclarations = typeDefinitionMapping.Values - .Where(declaration => declaration.Node is INamedTypeSymbol symbol && symbol.TypeKind == TypeKind.Class) - .ToList(); - foreach (var classTypeDeclaration in classTypeDeclarations) - { - INamedTypeSymbol classSymbol = classTypeDeclaration.Node as INamedTypeSymbol; - - foreach (var implementedInterface in classSymbol.AllInterfaces) - { - if (!typeDefinitionMapping.ContainsKey(implementedInterface.ToString())) - { - AddType(implementedInterface); - } - - var interfaceTypeDeclaration = typeDefinitionMapping[implementedInterface.ToString()]; - foreach (var interfaceMember in interfaceTypeDeclaration.MethodReferences) - { - var classMember = classSymbol.FindImplementationForInterfaceMember(interfaceMember.Key); - if (classTypeDeclaration.MethodDefinitions.ContainsKey(classMember)) - { - var interfaceMemberMethodDefinitions = interfaceMember.Value; - var classMemberMethodDefinitions = classTypeDeclaration.MethodDefinitions[classMember]; - for (int idx = 0; idx < interfaceMemberMethodDefinitions.Count; idx++) - { - metadataBuilder.AddMethodImplementation( - classTypeDeclaration.Handle, - classMemberMethodDefinitions[idx], - interfaceMemberMethodDefinitions[idx]); - } - - // If method overloaded in interface, overload in class too. - if (interfaceTypeDeclaration.OverloadedMethods.ContainsKey(interfaceMember.Key)) - { - AddOverloadAttribute(classMemberMethodDefinitions.First(), interfaceTypeDeclaration.OverloadedMethods[interfaceMember.Key]); - } - } - } - } - - if (classTypeDeclaration.DefaultInterface != null) - { - var defaultInterfaceTypeDeclaration = typeDefinitionMapping[classTypeDeclaration.DefaultInterface]; - foreach (var interfaceMember in defaultInterfaceTypeDeclaration.MethodReferences) - { - if (classTypeDeclaration.MethodDefinitions.ContainsKey(interfaceMember.Key)) - { - var interfaceMemberMethodDefinitions = interfaceMember.Value; - var classMemberMethodDefinitions = classTypeDeclaration.MethodDefinitions[interfaceMember.Key]; - for (int idx = 0; idx < interfaceMemberMethodDefinitions.Count; idx++) - { - metadataBuilder.AddMethodImplementation( - classTypeDeclaration.Handle, - classMemberMethodDefinitions[idx], - interfaceMemberMethodDefinitions[idx]); - } - - // If method overloaded in interface, overload in class too. - if (defaultInterfaceTypeDeclaration.OverloadedMethods.ContainsKey(interfaceMember.Key)) - { - AddOverloadAttribute(classMemberMethodDefinitions.First(), defaultInterfaceTypeDeclaration.OverloadedMethods[interfaceMember.Key]); - } - } - } - } - - if (classTypeDeclaration.StaticInterface != null) - { - var staticInterfaceTypeDeclaration = typeDefinitionMapping[classTypeDeclaration.StaticInterface]; - foreach (var interfaceMember in staticInterfaceTypeDeclaration.MethodReferences) - { - // If method overloaded in static interface, overload in class too. - if (classTypeDeclaration.MethodDefinitions.ContainsKey(interfaceMember.Key) && - staticInterfaceTypeDeclaration.OverloadedMethods.ContainsKey(interfaceMember.Key)) - { - AddOverloadAttribute( - classTypeDeclaration.MethodDefinitions[interfaceMember.Key].First(), - staticInterfaceTypeDeclaration.OverloadedMethods[interfaceMember.Key] - ); - } - } - } - } - - var interfaceDeclarations = typeDefinitionMapping.Values - .Where(declaration => declaration.Node is INamedTypeSymbol symbol && symbol.TypeKind == TypeKind.Interface) - .ToList(); - foreach (var interfaceDeclaration in interfaceDeclarations) - { - INamedTypeSymbol interfaceSymbol = interfaceDeclaration.Node as INamedTypeSymbol; - if (typeDefinitionMapping[interfaceSymbol.ToString()].Handle != default && GetVersion(interfaceSymbol) == -1) - { - AddDefaultVersionAttribute(typeDefinitionMapping[interfaceSymbol.ToString()].Handle); - } - } - - foreach (var node in nodesWithAttributes) - { - EntityHandle parentHandle = default; - if(node is INamedTypeSymbol namedType) - { - parentHandle = typeDefinitionMapping[namedType.ToString()].Handle; - } - else if (node is IMethodSymbol method) - { - parentHandle = typeDefinitionMapping[method.ContainingType.ToString()].MethodDefinitions[method][0]; - } - else if (node is IPropertySymbol property) - { - parentHandle = typeDefinitionMapping[property.ContainingType.ToString()].PropertyDefinitions[property]; - } - else if (node is IEventSymbol @event) - { - parentHandle = typeDefinitionMapping[@event.ContainingType.ToString()].EventDefinitions[@event]; - } - else - { - Logger.Log("node not recognized " + node.Kind + " name: " + node.Name); - } - - AddCustomAttributes(node.GetAttributes(), parentHandle); - } - } - - public bool IsPublicNode(MemberDeclarationSyntax node) - { - return node.Modifiers.Any(modifier => modifier.ValueText == "public") || - (node.Parent is InterfaceDeclarationSyntax && node.Modifiers.Count == 0); - } - - public bool IsPrivateNode(AccessorDeclarationSyntax node) - { - return node.Modifiers.Any(modifier => modifier.ValueText == "private"); - } - - public bool IsStaticNode(MemberDeclarationSyntax node) - { - return node.Modifiers.Any(modifier => modifier.ValueText == "static"); - } - - public bool IsSealedNode(MemberDeclarationSyntax node) - { - return node.Modifiers.Any(modifier => modifier.ValueText == "sealed"); - } - - public string GetNamespace() - { - return string.Join(".", namespaces); - } - - public string QualifiedName(string identifier) - { - return QualifiedName(GetNamespace(), identifier); - } - - public string QualifiedName(string @namespace, string identifier) - { - return string.Join(".", @namespace, identifier); - } - - public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) - { - namespaces.Push(node.Name.ToString()); - base.VisitNamespaceDeclaration(node); - namespaces.Pop(); - } - } -} +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.CSharp.Syntax; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.Metadata.Ecma335; +using System.Security.Cryptography; +using System.Text; + +namespace Generator +{ + class Parameter + { + public Symbol Type; + public string Name; + public ParameterAttributes Attributes; + + public Parameter(Symbol type, string name, ParameterAttributes attributes) + { + Type = type; + Name = name; + Attributes = attributes; + } + + public Parameter(ITypeSymbol type, string name, ParameterAttributes attributes) + : this(new Symbol(type), name, attributes) + { + } + + public Parameter(EntityHandle type, string name, ParameterAttributes attributes) + : this(new Symbol(type), name, attributes) + { + } + + public Parameter(ParameterSyntax parameter, ParameterAttributes attributes, SemanticModel model) + { + Type = new Symbol(model.GetDeclaredSymbol(parameter).Type); + Name = parameter.Identifier.ValueText; + Attributes = attributes; + } + } + + class Symbol + { + public ITypeSymbol Type; + public EntityHandle Handle; + + public Symbol(ITypeSymbol type) + { + Type = type; + Handle = default; + } + + public Symbol(EntityHandle handle) + { + Type = default; + Handle = handle; + } + + public bool IsHandle() + { + return Handle != default; + } + } + + class TypeDeclaration + { + public readonly ISymbol Node; + public TypeDefinitionHandle Handle; + public string DefaultInterface; + public string StaticInterface; + + public Dictionary> MethodDefinitions = new Dictionary>(); + public Dictionary> MethodReferences = new Dictionary>(); + public Dictionary FieldDefinitions = new Dictionary(); + public Dictionary PropertyDefinitions = new Dictionary(); + public Dictionary EventDefinitions = new Dictionary(); + public Dictionary InterfaceImplDefinitions = new Dictionary(); + public Dictionary> MethodsByName = new Dictionary>(); + public Dictionary OverloadedMethods = new Dictionary(); + + public TypeDeclaration(ISymbol node) + { + Node = node; + Handle = default; + } + + public override string ToString() + { + return Node.ToString(); + } + + public void AddMethod(ISymbol node, string name, MethodDefinitionHandle handle) + { + if(!MethodDefinitions.ContainsKey(node)) + { + MethodDefinitions[node] = new List(); + MethodReferences[node] = new List(); + } + + if(!MethodsByName.ContainsKey(name)) + { + MethodsByName[name] = new List(); + } + + MethodDefinitions[node].Add(handle); + MethodReferences[node].Add(handle); + MethodsByName[name].Add(node); + } + + public void AddMethodReference(ISymbol node, MemberReferenceHandle handle) + { + if (!MethodReferences.ContainsKey(node)) + { + MethodReferences[node] = new List(); + } + + MethodReferences[node].Add(handle); + } + + public void AddMethodOverload(ISymbol node, string overloadedMethodName) + { + OverloadedMethods[node] = overloadedMethodName; + } + + public List GetMethodDefinitions() + { + return MethodDefinitions.Values.SelectMany(list => list).ToList(); + } + + public List GetMethodReferences() + { + return MethodReferences.Values.SelectMany(list => list).ToList(); + } + + public void AddField(ISymbol node, FieldDefinitionHandle handle) + { + FieldDefinitions[node] = handle; + } + + public List GetFieldDefinitions() + { + return FieldDefinitions.Values.ToList(); + } + + public void AddProperty(ISymbol node, PropertyDefinitionHandle handle) + { + PropertyDefinitions[node] = handle; + } + + public List GetPropertyDefinitions() + { + return PropertyDefinitions.Values.ToList(); + } + + public void AddEvent(ISymbol node, EventDefinitionHandle handle) + { + EventDefinitions[node] = handle; + } + + public List GetEventDefinitions() + { + return EventDefinitions.Values.ToList(); + } + + public void AddInterfaceImpl(ISymbol node, InterfaceImplementationHandle handle) + { + InterfaceImplDefinitions[node] = handle; + } + + } + + class WinRTTypeWriter : CSharpSyntaxWalker + { + private struct MappedType + { + public readonly string @namespace; + public readonly string name; + public readonly string assembly; + + public MappedType(string @namespace, string name, string assembly) + { + this.@namespace = @namespace; + this.name = name; + this.assembly = assembly; + } + } + + private static readonly Dictionary MappedCSharpTypes = new Dictionary() + { + { "System.Nullable", new MappedType("Windows.Foundation", "IReference`1", "Windows.Foundation.FoundationContract" ) }, + { "System.FlagsAttribute", new MappedType("System", "FlagsAttribute", "mscorlib" ) } + }; + + public SemanticModel Model; + + private readonly string assembly; + private readonly string version; + + private readonly Stack namespaces = new Stack(); + private readonly Dictionary typeReferenceMapping; + private readonly Dictionary assemblyReferenceMapping; + private readonly List nodesWithAttributes; + private readonly MetadataBuilder metadataBuilder; + private bool hasConstructor, hasDefaultConstructor; + + private readonly Dictionary typeDefinitionMapping; + private TypeDeclaration currentTypeDeclaration; + + public WinRTTypeWriter( + string assembly, + string version, + MetadataBuilder metadataBuilder) + { + this.assembly = assembly; + this.version = version; + this.metadataBuilder = metadataBuilder; + typeReferenceMapping = new Dictionary(); + assemblyReferenceMapping = new Dictionary(); + typeDefinitionMapping = new Dictionary(); + nodesWithAttributes = new List(); + + CreteAssembly(); + } + + private void CreteAssembly() + { + Logger.Log("Generating assembly " + assembly + " version " + version); + metadataBuilder.AddAssembly( + metadataBuilder.GetOrAddString(assembly), + new Version(version), + default, + default, + AssemblyFlags.WindowsRuntime, + AssemblyHashAlgorithm.Sha1); + + var moduleDefinition = metadataBuilder.AddModule( + 0, + metadataBuilder.GetOrAddString(assembly + ".winmd"), + metadataBuilder.GetOrAddGuid(Guid.NewGuid()), + default, + default); + assemblyReferenceMapping[assembly] = moduleDefinition; + + metadataBuilder.AddTypeDefinition( + default, + default, + metadataBuilder.GetOrAddString(""), + default, + MetadataTokens.FieldDefinitionHandle(1), + MetadataTokens.MethodDefinitionHandle(1)); + } + + private void EncodeSpecialType(SpecialType specialType, SignatureTypeEncoder typeEncoder) + { + switch (specialType) + { + case SpecialType.System_Boolean: + typeEncoder.Boolean(); + break; + case SpecialType.System_Byte: + typeEncoder.Byte(); + break; + case SpecialType.System_Int16: + typeEncoder.Int16(); + break; + case SpecialType.System_Int32: + typeEncoder.Int32(); + break; + case SpecialType.System_Int64: + typeEncoder.Int64(); + break; + case SpecialType.System_UInt16: + typeEncoder.UInt16(); + break; + case SpecialType.System_UInt32: + typeEncoder.UInt32(); + break; + case SpecialType.System_UInt64: + typeEncoder.UInt64(); + break; + case SpecialType.System_Single: + typeEncoder.Single(); + break; + case SpecialType.System_Double: + typeEncoder.Double(); + break; + case SpecialType.System_Char: + typeEncoder.Char(); + break; + case SpecialType.System_String: + typeEncoder.String(); + break; + case SpecialType.System_Object: + typeEncoder.Object(); + break; + case SpecialType.System_IntPtr: + typeEncoder.IntPtr(); + break; + default: + Logger.Log("TODO special type: " + specialType); + break; + } + + // TODO: handle C# interface mappings for special types + } + + private BlobHandle GetStrongNameKey(string assembly) + { + if(assembly == "mscorlib") + { + byte[] mscorlibStrongName = { 0xb7, 0x7a, 0x5c, 0x56, 0x19, 0x34, 0xe0, 0x89 }; + return metadataBuilder.GetOrAddBlob(mscorlibStrongName); + } + + return default; + } + + private EntityHandle GetTypeReference(string @namespace, string name, string assembly) + { + string fullname = QualifiedName(@namespace, name); + if (typeReferenceMapping.ContainsKey(fullname)) + { + return typeReferenceMapping[fullname]; + } + + if (!assemblyReferenceMapping.ContainsKey(assembly)) + { + EntityHandle assemblyReference = metadataBuilder.AddAssemblyReference( + metadataBuilder.GetOrAddString(assembly), + new Version(0xff, 0xff, 0xff, 0xff), + default, + GetStrongNameKey(assembly), + assembly == "mscorlib" ? default : AssemblyFlags.WindowsRuntime, + default); + assemblyReferenceMapping[assembly] = assemblyReference; + } + + var typeRef = metadataBuilder.AddTypeReference( + assemblyReferenceMapping[assembly], + metadataBuilder.GetOrAddString(@namespace), + metadataBuilder.GetOrAddString(name)); + typeReferenceMapping[fullname] = typeRef; + return typeRef; + } + + public string GetAssemblyForWinRTType(ISymbol type) + { + var winrtTypeAttribute = type.GetAttributes(). + Where(attribute => attribute.AttributeClass.Name == "WindowsRuntimeTypeAttribute"); + if (winrtTypeAttribute.Any()) + { + return (string) winrtTypeAttribute.First().ConstructorArguments[0].Value; + } + + return null; + } + + private EntityHandle GetTypeReference(ISymbol symbol) + { + string @namespace = symbol.ContainingNamespace.ToString(); + string name = symbol.Name; + string fullType = QualifiedName(@namespace, name); + + var assembly = GetAssemblyForWinRTType(symbol); + if (assembly == null) + { + if (MappedCSharpTypes.ContainsKey(fullType)) + { + Logger.Log("Mapping known type: " + fullType); + var newType = MappedCSharpTypes[fullType]; + @namespace = newType.@namespace; + name = newType.name; + assembly = newType.assembly; + + Logger.Log("Mapping " + fullType + " to " + QualifiedName(@namespace, name) + " from " + assembly); + } + else + { + assembly = symbol.ContainingAssembly.Name; + } + } + + return GetTypeReference(@namespace, name, assembly); + } + + private void EncodeSymbol(Symbol symbol, SignatureTypeEncoder typeEncoder) + { + if (symbol.IsHandle()) + { + typeEncoder.Type(symbol.Handle, false); + } + else if(symbol.Type is INamedTypeSymbol namedType && namedType.TypeArguments.Length != 0) + { + Logger.Log("generic type"); + var genericType = typeEncoder.GenericInstantiation(GetTypeReference(symbol.Type), namedType.TypeArguments.Length, false); + foreach (var typeArgument in namedType.TypeArguments) + { + EncodeSymbol(new Symbol(typeArgument), genericType.AddArgument()); + } + } + else if(symbol.Type.SpecialType != SpecialType.None) + { + EncodeSpecialType(symbol.Type.SpecialType, typeEncoder); + } + else + { + typeEncoder.Type(GetTypeReference(symbol.Type), symbol.Type.TypeKind == TypeKind.Enum); + } + } + + private void EncodeReturnType(Symbol symbol, ReturnTypeEncoder returnTypeEncoder) + { + if(symbol == null) + { + returnTypeEncoder.Void(); + } + else if(symbol.IsHandle() || symbol.Type.SpecialType == SpecialType.None) + { + EncodeSymbol(symbol, returnTypeEncoder.Type()); + } + else if(symbol.Type.SpecialType == SpecialType.System_Void) + { + returnTypeEncoder.Void(); + } + else + { + EncodeSpecialType(symbol.Type.SpecialType, returnTypeEncoder.Type()); + } + } + + private void EncodeParameters(Parameter[] parameters, ParametersEncoder parametersEncoder) + { + foreach (var parameter in parameters) + { + var parameterType = parameter.Type; + var parameterTypeEncoder = parametersEncoder.AddParameter(); + + if (!parameterType.IsHandle() && parameterType.Type.SpecialType != SpecialType.None) + { + EncodeSpecialType(parameterType.Type.SpecialType, parameterTypeEncoder.Type()); + } + else + { + EncodeSymbol(parameterType, parameterTypeEncoder.Type()); + } + } + } + + public MethodDefinitionHandle AddMethodDefinition( + string name, + Parameter[] parameters, + Symbol returnSymbol, + bool isStatic, + bool isInterfaceParent, + bool isSpecialMethod = false, + bool isPublic = true, + bool isOverridable = false) + { + var methodSignature = new BlobBuilder(); + new BlobEncoder(methodSignature) + .MethodSignature( + SignatureCallingConvention.Default, + 0, + !isStatic) + .Parameters( + parameters.Length, + returnType => EncodeReturnType(returnSymbol, returnType), + parametersEncoder => EncodeParameters(parameters, parametersEncoder) + ); + + List parameterHandles = new List(); + for (int idx = 0; idx < parameters.Length; idx++) + { + parameterHandles.Add(metadataBuilder.AddParameter( + parameters[idx].Attributes, + metadataBuilder.GetOrAddString(parameters[idx].Name), + idx + 1)); + } + + var methodAttributes = + (isPublic ? MethodAttributes.Public : MethodAttributes.Private) | + MethodAttributes.HideBySig; + + var methodImplAttributes = MethodImplAttributes.Managed; + + if (isInterfaceParent) + { + methodAttributes |= MethodAttributes.Abstract; + } + else + { + // TODO check if from overridable interface + if (!isOverridable) + { + methodAttributes |= MethodAttributes.Final; + } + methodImplAttributes |= MethodImplAttributes.Runtime; + } + + if (isSpecialMethod && name == ".ctor") + { + methodAttributes |= MethodAttributes.RTSpecialName; + } + else if(isStatic) + { + methodAttributes |= MethodAttributes.Static; + } + else + { + methodAttributes |= + MethodAttributes.Virtual | + MethodAttributes.NewSlot; + } + + if (isSpecialMethod) + { + methodAttributes |= MethodAttributes.SpecialName; + } + + var methodDefinitionHandle = metadataBuilder.AddMethodDefinition( + methodAttributes, + methodImplAttributes, + metadataBuilder.GetOrAddString(name), + metadataBuilder.GetOrAddBlob(methodSignature), + -1, + parameterHandles.Count == 0 ? + MetadataTokens.ParameterHandle(metadataBuilder.GetRowCount(TableIndex.Param) + 1) : + parameterHandles[0]); + return methodDefinitionHandle; + } + + public override void VisitMethodDeclaration(MethodDeclarationSyntax node) + { + Logger.Log("method: " + node.Identifier.ValueText); + if(!IsPublicNode(node)) + { + return; + } + + base.VisitMethodDeclaration(node); + + int numParameters = node.ParameterList.Parameters.Count; + Parameter[] parameters = new Parameter[numParameters]; + for(int idx = 0; idx < numParameters; idx++) + { + parameters[idx] = new Parameter(node.ParameterList.Parameters[idx], ParameterAttributes.In, Model); + } + + var methodSymbol = Model.GetDeclaredSymbol(node); + var methodDefinitionHandle = AddMethodDefinition( + methodSymbol.Name, + parameters, + new Symbol(methodSymbol.ReturnType), + IsStaticNode(node), + node.Parent is InterfaceDeclarationSyntax); + currentTypeDeclaration.AddMethod(methodSymbol, methodSymbol.Name, methodDefinitionHandle); + } + + public override void VisitFieldDeclaration(FieldDeclarationSyntax node) + { + if (!IsPublicNode(node) || node.Parent is not StructDeclarationSyntax) + { + return; + } + + base.VisitFieldDeclaration(node); + + var symbol = Model.GetTypeInfo(node.Declaration.Type).Type; + var fieldSignature = new BlobBuilder(); + var encoder = new BlobEncoder(fieldSignature); + + if (symbol.SpecialType != SpecialType.None) + { + EncodeSpecialType(symbol.SpecialType, encoder.FieldSignature()); + } + else + { + EncodeSymbol(new Symbol(symbol), encoder.FieldSignature()); + } + + foreach (var variable in node.Declaration.Variables) + { + var fieldSymbol = Model.GetDeclaredSymbol(variable); + var fieldDefinitionHandle = metadataBuilder.AddFieldDefinition( + FieldAttributes.Public, + metadataBuilder.GetOrAddString(variable.Identifier.Text), + metadataBuilder.GetOrAddBlob(fieldSignature)); + currentTypeDeclaration.AddField(fieldSymbol, fieldDefinitionHandle); + } + } + + public void AddPropertyDeclaration(IPropertySymbol property, bool isInterfaceParent) + { + Logger.Log("defining property " + property.Name); + Logger.Log("parent: " + property.ContainingType.Name); + + var propertySignature = new BlobBuilder(); + new BlobEncoder(propertySignature) + .PropertySignature(true) + .Parameters( + 0, + returnType => EncodeReturnType(new Symbol(property.Type), returnType), + parameters => { } + ); + + var propertyDefinitonHandle = metadataBuilder.AddProperty( + PropertyAttributes.None, + metadataBuilder.GetOrAddString(property.Name), + metadataBuilder.GetOrAddBlob(propertySignature)); + currentTypeDeclaration.AddProperty(property, propertyDefinitonHandle); + + if (property.SetMethod != null) + { + string setMethodName = "put_" + property.Name; + var setMethod = AddMethodDefinition( + setMethodName, + new Parameter[] { new Parameter(property.Type, "value", ParameterAttributes.In) }, + null, + false, + isInterfaceParent, + true); + currentTypeDeclaration.AddMethod(property, setMethodName, setMethod); + + metadataBuilder.AddMethodSemantics( + propertyDefinitonHandle, + MethodSemanticsAttributes.Setter, + setMethod); + } + + string getMethodName = "get_" + property.Name; + var getMethod = AddMethodDefinition( + getMethodName, + new Parameter[0], + new Symbol(property.Type), + false, + isInterfaceParent, + true); + currentTypeDeclaration.AddMethod(property, getMethodName, getMethod); + + metadataBuilder.AddMethodSemantics( + propertyDefinitonHandle, + MethodSemanticsAttributes.Getter, + getMethod); + } + + public override void VisitPropertyDeclaration(PropertyDeclarationSyntax node) + { + if (!IsPublicNode(node)) + { + return; + } + + base.VisitPropertyDeclaration(node); + + var symbol = Model.GetDeclaredSymbol(node); + + var propertySignature = new BlobBuilder(); + new BlobEncoder(propertySignature) + .PropertySignature(true) + .Parameters( + 0, + returnType => EncodeReturnType(new Symbol(symbol.Type), returnType), + parameters => { } + ); + + var propertyDefinitonHandle = metadataBuilder.AddProperty( + PropertyAttributes.None, + metadataBuilder.GetOrAddString(node.Identifier.ValueText), + metadataBuilder.GetOrAddBlob(propertySignature)); + currentTypeDeclaration.AddProperty(symbol, propertyDefinitonHandle); + + var isGetPublic = true; + var isSetPublic = true; + + /* + TODO: support for private set with default interface support + + if (node.AccessorList != null) + { + foreach (var accessor in node.AccessorList.Accessors) + { + if(accessor.Keyword.Kind() == SyntaxKind.GetKeyword) + { + isGetPublic = !IsPrivateNode(accessor); + } + else if(accessor.Keyword.Kind() == SyntaxKind.SetKeyword) + { + isSetPublic = !IsPrivateNode(accessor); + } + } + } + */ + + if (symbol.SetMethod != null && isSetPublic) + { + string setMethodName = "put_" + symbol.Name; + var setMethod = AddMethodDefinition( + setMethodName, + new Parameter[] { new Parameter(symbol.Type, "value", ParameterAttributes.In ) }, + null, + false, + node.Parent is InterfaceDeclarationSyntax, + true); + currentTypeDeclaration.AddMethod(symbol, setMethodName, setMethod); + + metadataBuilder.AddMethodSemantics( + propertyDefinitonHandle, + MethodSemanticsAttributes.Setter, + setMethod); + } + + if (!symbol.IsWriteOnly && isGetPublic) + { + string getMethodName = "get_" + symbol.Name; + var getMethod = AddMethodDefinition( + getMethodName, + new Parameter[0], + new Symbol(symbol.Type), + false, + node.Parent is InterfaceDeclarationSyntax, + true); + currentTypeDeclaration.AddMethod(symbol, getMethodName, getMethod); + + metadataBuilder.AddMethodSemantics( + propertyDefinitonHandle, + MethodSemanticsAttributes.Getter, + getMethod); + } + } + + private TypeDefinitionHandle AddTypeDefinition( + TypeAttributes typeAttributes, + string @namespace, + string identifier, + EntityHandle baseType) + { + var fieldDefinitions = currentTypeDeclaration.GetFieldDefinitions(); + var methodDefinitions = currentTypeDeclaration.GetMethodDefinitions(); + + var typeDefinitionHandle = metadataBuilder.AddTypeDefinition( + typeAttributes, + metadataBuilder.GetOrAddString(@namespace), + metadataBuilder.GetOrAddString(identifier), + baseType, + fieldDefinitions.Count == 0 ? + MetadataTokens.FieldDefinitionHandle(metadataBuilder.GetRowCount(TableIndex.Field) + 1) : + fieldDefinitions[0], + methodDefinitions.Count == 0 ? + MetadataTokens.MethodDefinitionHandle(metadataBuilder.GetRowCount(TableIndex.MethodDef) + 1) : + methodDefinitions[0] + ); + + var propertyDefinitions = currentTypeDeclaration.GetPropertyDefinitions(); + if (propertyDefinitions.Count != 0) + { + metadataBuilder.AddPropertyMap( + typeDefinitionHandle, + propertyDefinitions[0]); + } + + var eventDefinitions = currentTypeDeclaration.GetEventDefinitions(); + if (eventDefinitions.Count != 0) + { + metadataBuilder.AddEventMap( + typeDefinitionHandle, + eventDefinitions[0]); + } + + return typeDefinitionHandle; + } + + private void ProcessTypeDeclaration(BaseTypeDeclarationSyntax node, Action visitTypeDeclaration) + { + if(!IsPublicNode(node)) + { + return; + } + + var symbol = Model.GetDeclaredSymbol(node); + currentTypeDeclaration = new TypeDeclaration(symbol); + + visitTypeDeclaration(); + + TypeAttributes typeAttributes = + TypeAttributes.Public | + TypeAttributes.WindowsRuntime | + TypeAttributes.AutoLayout | + TypeAttributes.AnsiClass; + + if (IsSealedNode(node) || + (node is EnumDeclarationSyntax || + node is StructDeclarationSyntax)) + { + typeAttributes |= TypeAttributes.Sealed; + } + + EntityHandle baseType = default; + if(node is InterfaceDeclarationSyntax) + { + typeAttributes |= + TypeAttributes.Interface | + TypeAttributes.Abstract; + } + else if(node is ClassDeclarationSyntax) + { + typeAttributes |= + TypeAttributes.Class | + TypeAttributes.BeforeFieldInit; + + // extends + if (node.BaseList != null) + { + foreach (var type in node.BaseList.Types) + { + var typeSymbol = Model.GetTypeInfo(type.Type).Type; + if(typeSymbol.TypeKind == TypeKind.Class) + { + baseType = GetTypeReference(typeSymbol); + break; + } + } + } + + if (baseType == default) + { + baseType = GetTypeReference("System", "Object", "mscorlib"); + } + } + else if(node is StructDeclarationSyntax) + { + typeAttributes |= TypeAttributes.SequentialLayout; + baseType = GetTypeReference("System", "ValueType", "mscorlib"); + } + else if(node is EnumDeclarationSyntax) + { + baseType = GetTypeReference("System", "Enum", "mscorlib"); + } + + var typeDefinitionHandle = AddTypeDefinition( + typeAttributes, + GetNamespace(), + node.Identifier.ValueText, + baseType); + currentTypeDeclaration.Handle = typeDefinitionHandle; + + if (node.BaseList != null && (node is InterfaceDeclarationSyntax || node is ClassDeclarationSyntax)) + { + foreach (var implementedInterface in symbol.AllInterfaces. + OrderBy(implementedInterface => implementedInterface.ToString())) + { + var interfaceImplHandle = metadataBuilder.AddInterfaceImplementation( + typeDefinitionHandle, + GetTypeReference(implementedInterface)); + currentTypeDeclaration.AddInterfaceImpl(implementedInterface, interfaceImplHandle); + } + } + + typeDefinitionMapping[QualifiedName(node.Identifier.ValueText)] = currentTypeDeclaration; + } + + public override void VisitInterfaceDeclaration(InterfaceDeclarationSyntax node) + { + ProcessTypeDeclaration(node, () => base.VisitInterfaceDeclaration(node)); + + var interfaceTypeDeclaration = currentTypeDeclaration; + AddGuidAttribute(interfaceTypeDeclaration.Handle, interfaceTypeDeclaration.Node.ToString()); + AddOverloadAttributeForInterfaceMethods(interfaceTypeDeclaration); + } + + public override void VisitClassDeclaration(ClassDeclarationSyntax node) + { + void processClassDeclaration() + { + hasConstructor = false; + hasDefaultConstructor = false; + base.VisitClassDeclaration(node); + + // implicit constructor if none defined + if(!hasConstructor) + { + string constructorMethodName = ".ctor"; + var methodDefinitionHandle = AddMethodDefinition( + constructorMethodName, + new Parameter[0], + null, + false, + false, + true, + true, + true); + var symbol = Model.GetDeclaredSymbol(node); + currentTypeDeclaration.AddMethod(symbol, constructorMethodName, methodDefinitionHandle); + hasDefaultConstructor = true; + } + } + + ProcessTypeDeclaration(node, processClassDeclaration); + + if (IsPublicNode(node)) + { + var classDeclaration = currentTypeDeclaration; + var classSymbol = classDeclaration.Node as INamedTypeSymbol; + + if (hasDefaultConstructor) + { + AddActivatableAttribute( + classDeclaration.Handle, + (uint)GetVersion(classSymbol, true), + null); + } + AddSynthesizedInterfaces(classDeclaration); + + // No synthesized default interface generated + if(classDeclaration.DefaultInterface == null && classSymbol.Interfaces.Length != 0) + { + AddDefaultInterfaceImplAttribute(classDeclaration.InterfaceImplDefinitions[classSymbol.Interfaces[0]]); + } + } + } + + public override void VisitStructDeclaration(StructDeclarationSyntax node) + { + ProcessTypeDeclaration(node, () => base.VisitStructDeclaration(node)); + } + + private void EncodeTypedConstant(TypedConstant constant, LiteralEncoder encoder) + { + Logger.Log("typed constant kind: " + constant.Kind); + Logger.Log("typed constant type: " + constant.Type); + Logger.Log("typed constant value: " + constant.Value); + + switch (constant.Kind) + { + case TypedConstantKind.Primitive: + encoder.Scalar().Constant(constant.Value); + break; + case TypedConstantKind.Enum: + encoder.TaggedScalar( + type => type.Enum(constant.Type.ToString()), + scalar => scalar.Constant(constant.Value) + ); + break; + case TypedConstantKind.Type: + encoder.Scalar().SystemType(constant.Type.ToString()); + break; + case TypedConstantKind.Array: + { + LiteralsEncoder arrayEncoder = encoder.Vector().Count(constant.Values.Length); + foreach(var arrayConstant in constant.Values) + { + EncodeTypedConstant(arrayConstant, arrayEncoder.AddLiteral()); + } + break; + } + } + + } + + private void EncodeFixedArguments(IList arguments, FixedArgumentsEncoder argumentsEncoder) + { + foreach(var argument in arguments) + { + EncodeTypedConstant(argument, argumentsEncoder.AddArgument()); + } + } + + private void EncodeCustomElementType(IFieldSymbol field, CustomAttributeElementTypeEncoder typeEncoder) + { + switch (field.Type.SpecialType) + { + case SpecialType.System_Boolean: + typeEncoder.Boolean(); + break; + case SpecialType.System_Byte: + typeEncoder.Byte(); + break; + case SpecialType.System_Int16: + typeEncoder.Int16(); + break; + case SpecialType.System_Int32: + typeEncoder.Int32(); + break; + case SpecialType.System_Int64: + typeEncoder.Int64(); + break; + case SpecialType.System_UInt16: + typeEncoder.UInt16(); + break; + case SpecialType.System_UInt32: + typeEncoder.UInt32(); + break; + case SpecialType.System_UInt64: + typeEncoder.UInt64(); + break; + case SpecialType.System_Single: + typeEncoder.Single(); + break; + case SpecialType.System_Double: + typeEncoder.Double(); + break; + case SpecialType.System_Char: + typeEncoder.Char(); + break; + case SpecialType.System_String: + typeEncoder.String(); + break; + case SpecialType.System_Enum: + typeEncoder.Enum(field.Type.ToString()); + break; + case SpecialType.System_SByte: + typeEncoder.SByte(); + break; + default: + Logger.Log("TODO special type: " + field.Type.SpecialType); + break; + } + } + + private void EncodeNamedArgumentType(INamedTypeSymbol attributeType, string field, NamedArgumentTypeEncoder encoder) + { + Logger.Log("encoding named type"); + var fieldMembers = attributeType.GetMembers(field); + Logger.Log("# fields: " + fieldMembers.Count()); + var fieldSymbol = fieldMembers.First() as IFieldSymbol; + Logger.Log("found field: " + fieldSymbol); + + if(fieldSymbol.Type.SpecialType == SpecialType.System_Object) + { + encoder.Object(); + } + else if(fieldSymbol.Type.SpecialType == SpecialType.System_Array) + { + // TODO array type encoder + encoder.SZArray(); + } + else + { + EncodeCustomElementType(fieldSymbol, encoder.ScalarType()); + } + } + + private void EncodeNamedArguments( + INamedTypeSymbol attributeType, + IList> namedArguments, + CustomAttributeNamedArgumentsEncoder argumentsEncoder) + { + var encoder = argumentsEncoder.Count(namedArguments.Count); + foreach (var argument in namedArguments) + { + Logger.Log("named argument: " + argument.Key); + Logger.Log("value " + argument.Value); + + encoder.AddArgument( + true, + type => EncodeNamedArgumentType(attributeType, argument.Key, type), + name => name.Name(argument.Key), + literal => EncodeTypedConstant(argument.Value, literal) + ); + } + } + + private void EncodeFixedArguments(IList primitiveArguments, FixedArgumentsEncoder argumentsEncoder) + { + foreach (var argument in primitiveArguments) + { + var encoder = argumentsEncoder.AddArgument().Scalar(); + if(argument is string type) + { + encoder.SystemType(type); + } + else + { + encoder.Constant(argument); + } + } + } + + private void AddDefaultVersionAttribute(EntityHandle parentHandle, int version = -1) + { + if(version == -1) + { + version = Version.Parse(this.version).Major; + } + + List types = new List + { + Model.Compilation.GetTypeByMetadataName("System.UInt32") + }; + + List arguments = new List + { + (UInt32) version + }; + + AddCustomAttributes("Windows.Foundation.Metadata.VersionAttribute", types, arguments, parentHandle); + } + + private void AddActivatableAttribute(EntityHandle parentHandle, UInt32 version, string factoryInterface) + { + List types = new List(2); + List arguments = new List(2); + + if(factoryInterface != null) + { + types.Add(Model.Compilation.GetTypeByMetadataName("System.Type")); + arguments.Add(factoryInterface); + } + types.Add(Model.Compilation.GetTypeByMetadataName("System.UInt32")); + arguments.Add(version); + + AddCustomAttributes("Windows.Foundation.Metadata.ActivatableAttribute", types, arguments, parentHandle); + } + + private void AddExclusiveToAttribute(EntityHandle interfaceHandle, string className) + { + List types = new List + { + Model.Compilation.GetTypeByMetadataName("System.Type") + }; + + List arguments = new List + { + className + }; + + AddCustomAttributes("Windows.Foundation.Metadata.ExclusiveToAttribute", types, arguments, interfaceHandle); + } + + private void AddStaticAttribute(EntityHandle parentHandle, UInt32 version, string staticInterface) + { + List types = new List + { + Model.Compilation.GetTypeByMetadataName("System.Type"), + Model.Compilation.GetTypeByMetadataName("System.UInt32") + }; + + List arguments = new List + { + staticInterface, + version + }; + + AddCustomAttributes("Windows.Foundation.Metadata.StaticAttribute", types, arguments, parentHandle); + } + + private void AddDefaultInterfaceImplAttribute(EntityHandle interfaceImplHandle) + { + AddCustomAttributes("Windows.Foundation.Metadata.DefaultAttribute", Array.Empty(), Array.Empty(), interfaceImplHandle); + } + + private void AddOverloadAttribute(EntityHandle methodHandle, string methodName) + { + List types = new List + { + Model.Compilation.GetTypeByMetadataName("System.String") + }; + + List arguments = new List + { + methodName + }; + + AddCustomAttributes("Windows.Foundation.Metadata.OverloadAttribute", types, arguments, methodHandle); + } + + private void AddOverloadAttributeForInterfaceMethods(TypeDeclaration interfaceTypeDeclaration) + { + // Generate unique names for any overloaded methods + foreach (var methodName in interfaceTypeDeclaration.MethodsByName.Where(symbol => symbol.Value.Count > 1)) + { + var methodSymbols = methodName.Value.Where(symbol => symbol is IMethodSymbol); + // Other members that are not methods such as properties and events can generate reserved methods + // which for the purposes of overloading are considered to be the non overloaded version. If there is no + // such function, then we consider the first encountered method to be the non overloaded version. + var skipFirstMethod = methodName.Value.Count == methodSymbols.Count(); + var lastSuffix = 1; + foreach (var method in methodSymbols) + { + if (skipFirstMethod) + { + skipFirstMethod = false; + continue; + } + + string overloadedMethodName = methodName.Key + (++lastSuffix); + while (interfaceTypeDeclaration.MethodsByName.ContainsKey(overloadedMethodName)) + { + overloadedMethodName = methodName.Key + (++lastSuffix); + } + + Logger.Log("Overloading " + methodName.Key + " with " + overloadedMethodName); + AddOverloadAttribute(interfaceTypeDeclaration.MethodDefinitions[method].First(), overloadedMethodName); + interfaceTypeDeclaration.AddMethodOverload(method, overloadedMethodName); + } + } + } + + private void AddGuidAttribute(EntityHandle parentHandle, string name) + { + Guid guid; + using (SHA1 sha = new SHA1CryptoServiceProvider()) + { + var hash = sha.ComputeHash(Encoding.UTF8.GetBytes(name)); + guid = Helper.EncodeGuid(hash); + } + + var uint32Type = Model.Compilation.GetTypeByMetadataName("System.UInt32"); + var uint16Type = Model.Compilation.GetTypeByMetadataName("System.UInt16"); + var byteType = Model.Compilation.GetTypeByMetadataName("System.Byte"); + List types = new List + { + uint32Type, + uint16Type, + uint16Type, + byteType, + byteType, + byteType, + byteType, + byteType, + byteType, + byteType, + byteType + }; + + var byteArray = guid.ToByteArray(); + List arguments = new List + { + BitConverter.ToUInt32(byteArray, 0), + BitConverter.ToUInt16(byteArray, 4), + BitConverter.ToUInt16(byteArray, 6), + byteArray[8], + byteArray[9], + byteArray[10], + byteArray[11], + byteArray[12], + byteArray[13], + byteArray[14], + byteArray[15] + }; + + AddCustomAttributes("Windows.Foundation.Metadata.GuidAttribute", types, arguments, parentHandle); + } + + private void AddCustomAttributes( + string attributeTypeName, + IList primitiveTypes, + IList primitiveValues, + EntityHandle parentHandle) + { + var attributeType = Model.Compilation.GetTypeByMetadataName(attributeTypeName); + Logger.Log("attribute type found " + attributeType); + if (!typeDefinitionMapping.ContainsKey(attributeTypeName)) + { + Logger.Log("adding attribute type"); + AddType(attributeType); + } + + Logger.Log("# constructor found: " + attributeType.Constructors.Length); + var matchingConstructor = attributeType.Constructors.Where(constructor => + constructor.Parameters.Length == primitiveValues.Count && + constructor.Parameters.Select(param => param.Type).SequenceEqual(primitiveTypes)); + + Logger.Log("# matching constructor found: " + matchingConstructor.Count()); + Logger.Log("matching constructor found: " + matchingConstructor.First()); + + var constructorReference = typeDefinitionMapping[attributeTypeName].MethodReferences[matchingConstructor.First()]; + Logger.Log("found constructor handle: " + constructorReference.Count); + + var attributeSignature = new BlobBuilder(); + new BlobEncoder(attributeSignature) + .CustomAttributeSignature( + fixedArguments => EncodeFixedArguments(primitiveValues, fixedArguments), + namedArguments => namedArguments.Count(0) + ); + + metadataBuilder.AddCustomAttribute( + parentHandle, + constructorReference.First(), + metadataBuilder.GetOrAddBlob(attributeSignature)); + } + + private void AddCustomAttributes(IList attributes, EntityHandle parentHandle) + { + foreach (var attribute in attributes) + { + var attributeType = attribute.AttributeClass; + + Logger.Log("attribute: " + attribute); + Logger.Log("attribute type: " + attributeType); + Logger.Log("attribute constructor: " + attribute.AttributeConstructor); + Logger.Log("atttribute # constructor arguments: " + attribute.ConstructorArguments.Length); + Logger.Log("atttribute # named arguments: " + attribute.NamedArguments.Length); + + if (!typeDefinitionMapping.ContainsKey(attributeType.ToString())) + { + AddType(attributeType); + } + + var constructorReference = typeDefinitionMapping[attributeType.ToString()].MethodReferences[attribute.AttributeConstructor]; + Logger.Log("found # constructors: " + constructorReference.Count); + + var attributeSignature = new BlobBuilder(); + new BlobEncoder(attributeSignature) + .CustomAttributeSignature( + fixedArguments => EncodeFixedArguments(attribute.ConstructorArguments, fixedArguments), + namedArguments => EncodeNamedArguments(attributeType, attribute.NamedArguments, namedArguments) + ); + + metadataBuilder.AddCustomAttribute( + parentHandle, + constructorReference.First(), + metadataBuilder.GetOrAddBlob(attributeSignature)); + } + } + + public override void VisitAttributeList(AttributeListSyntax node) + { + base.VisitAttributeList(node); + + // Skip assembly attributes + if(node.Target != null && node.Target.Identifier.ValueText == "assembly") + { + return; + } + + var parentSymbol = Model.GetDeclaredSymbol(node.Parent); + nodesWithAttributes.Add(parentSymbol); + } + + public override void VisitEnumDeclaration(EnumDeclarationSyntax node) + { + void processEnumDeclaration() + { + var enumTypeFieldAttributes = + FieldAttributes.Private | + FieldAttributes.SpecialName | + FieldAttributes.RTSpecialName; + + var symbol = Model.GetDeclaredSymbol(node); + var enumTypeSymbol = symbol.EnumUnderlyingType; + var fieldSignature = new BlobBuilder(); + var encoder = new BlobEncoder(fieldSignature); + // TODO: special type enforcement for 64 bit + EncodeSpecialType(enumTypeSymbol.SpecialType, encoder.FieldSignature()); + + var fieldDefinitionHandle = metadataBuilder.AddFieldDefinition( + enumTypeFieldAttributes, + metadataBuilder.GetOrAddString("value__"), + metadataBuilder.GetOrAddBlob(fieldSignature)); + currentTypeDeclaration.AddField(symbol, fieldDefinitionHandle); + + base.VisitEnumDeclaration(node); + } + + ProcessTypeDeclaration(node, processEnumDeclaration); + } + + public override void VisitEnumMemberDeclaration(EnumMemberDeclarationSyntax node) + { + base.VisitEnumMemberDeclaration(node); + + var enumFieldAttributes = + FieldAttributes.Public | + FieldAttributes.Static | + FieldAttributes.Literal | + FieldAttributes.HasDefault; + + var symbol = Model.GetDeclaredSymbol(node); + var fieldSignature = new BlobBuilder(); + var encoder = new BlobEncoder(fieldSignature); + EncodeSymbol(new Symbol(symbol.ContainingType), encoder.FieldSignature()); + + var fieldDefinitionHandle = metadataBuilder.AddFieldDefinition( + enumFieldAttributes, + metadataBuilder.GetOrAddString(node.Identifier.Text), + metadataBuilder.GetOrAddBlob(fieldSignature)); + currentTypeDeclaration.AddField(symbol, fieldDefinitionHandle); + + if (symbol.HasConstantValue) + { + metadataBuilder.AddConstant(fieldDefinitionHandle, symbol.ConstantValue); + } + } + + public override void VisitDelegateDeclaration(DelegateDeclarationSyntax node) + { + if (!IsPublicNode(node)) + { + return; + } + + var symbol = Model.GetDeclaredSymbol(node); + currentTypeDeclaration = new TypeDeclaration(symbol); + + base.VisitDelegateDeclaration(node); + + var objType = Model.Compilation.GetTypeByMetadataName(typeof(object).FullName); + var nativeIntType = Model.Compilation.GetTypeByMetadataName(typeof(IntPtr).FullName); + + currentTypeDeclaration.AddMethod( + symbol, + ".ctor", + AddMethodDefinition( + ".ctor", + new Parameter[] { + new Parameter(objType, "object", ParameterAttributes.None), + new Parameter(nativeIntType, "method", ParameterAttributes.None) + }, + null, + false, + false, + true, + false, + true + ) + ); + + int numParameters = node.ParameterList.Parameters.Count; + Parameter[] parameters = new Parameter[numParameters]; + for (int idx = 0; idx < numParameters; idx++) + { + parameters[idx] = new Parameter(node.ParameterList.Parameters[idx], ParameterAttributes.In, Model); + } + + currentTypeDeclaration.AddMethod( + symbol, + "Invoke", + AddMethodDefinition( + "Invoke", + parameters, + new Symbol(symbol.DelegateInvokeMethod.ReturnType), + false, + false, + true, + true, + true + ) + ); + + TypeAttributes typeAttributes = + TypeAttributes.Public | + TypeAttributes.WindowsRuntime | + TypeAttributes.AutoLayout | + TypeAttributes.AnsiClass | + TypeAttributes.Sealed; + + var typeDefinitionHandle = AddTypeDefinition( + typeAttributes, + GetNamespace(), + node.Identifier.ValueText, + GetTypeReference("System", "MulticastDelegate", "mscorlib")); + currentTypeDeclaration.Handle = typeDefinitionHandle; + AddGuidAttribute(typeDefinitionHandle, symbol.ToString()); + } + + public void AddEventDeclaration(IEventSymbol @event, bool isInterfaceParent) + { + Logger.Log("defining event " + @event.Name); + + var delegateSymbolType = @event.Type; + EntityHandle typeReferenceHandle = GetTypeReference(delegateSymbolType); + EntityHandle eventRegistrationTokenTypeHandle = GetTypeReference("Windows.Foundation", "EventRegistrationToken", "Windows.Foundation.FoundationContract"); + Symbol eventRegistrationToken = new Symbol(eventRegistrationTokenTypeHandle); + + var eventDefinitionHandle = metadataBuilder.AddEvent( + EventAttributes.None, + metadataBuilder.GetOrAddString(@event.Name), + typeReferenceHandle); + currentTypeDeclaration.AddEvent(@event, eventDefinitionHandle); + + string addMethodName = "add_" + @event.Name; + var addMethod = AddMethodDefinition( + addMethodName, + new Parameter[] { new Parameter(delegateSymbolType, "handler", ParameterAttributes.In) }, + eventRegistrationToken, + false, + isInterfaceParent, + true); + currentTypeDeclaration.AddMethod(@event, addMethodName, addMethod); + + metadataBuilder.AddMethodSemantics( + eventDefinitionHandle, + MethodSemanticsAttributes.Adder, + addMethod); + + string removeMethodName = "remove_" + @event.Name; + var removeMethod = AddMethodDefinition( + removeMethodName, + new Parameter[] { new Parameter(eventRegistrationToken, "token", ParameterAttributes.In) }, + null, + false, + isInterfaceParent, + true); + currentTypeDeclaration.AddMethod(@event, removeMethodName, removeMethod); + + metadataBuilder.AddMethodSemantics( + eventDefinitionHandle, + MethodSemanticsAttributes.Remover, + removeMethod); + } + + public override void VisitEventFieldDeclaration(EventFieldDeclarationSyntax node) + { + if (!IsPublicNode(node)) + { + return; + } + + base.VisitEventFieldDeclaration(node); + + var delegateSymbolType = Model.GetTypeInfo(node.Declaration.Type).Type; + EntityHandle typeReferenceHandle = GetTypeReference(delegateSymbolType); + EntityHandle eventRegistrationTokenTypeHandle = GetTypeReference("Windows.Foundation", "EventRegistrationToken", "Windows.Foundation.FoundationContract"); + Symbol eventRegistrationToken = new Symbol(eventRegistrationTokenTypeHandle); + + foreach (var declaration in node.Declaration.Variables) + { + var eventSymbol = Model.GetDeclaredSymbol(declaration); + var eventDefinitionHandle = metadataBuilder.AddEvent( + EventAttributes.None, + metadataBuilder.GetOrAddString(declaration.Identifier.ValueText), + typeReferenceHandle); + currentTypeDeclaration.AddEvent(eventSymbol, eventDefinitionHandle); + + string addMethodName = "add_" + declaration.Identifier.ValueText; + var addMethod = AddMethodDefinition( + addMethodName, + new Parameter[] { new Parameter(delegateSymbolType, "handler", ParameterAttributes.In) }, + eventRegistrationToken, + false, + node.Parent is InterfaceDeclarationSyntax, + true); + currentTypeDeclaration.AddMethod(eventSymbol, addMethodName, addMethod); + + metadataBuilder.AddMethodSemantics( + eventDefinitionHandle, + MethodSemanticsAttributes.Adder, + addMethod); + + string removeMethodName = "remove_" + declaration.Identifier.ValueText; + var removeMethod = AddMethodDefinition( + removeMethodName, + new Parameter[] { new Parameter(eventRegistrationToken, "token", ParameterAttributes.In) }, + null, + false, + node.Parent is InterfaceDeclarationSyntax, + true); + currentTypeDeclaration.AddMethod(eventSymbol, removeMethodName, removeMethod); + + metadataBuilder.AddMethodSemantics( + eventDefinitionHandle, + MethodSemanticsAttributes.Remover, + removeMethod); + } + } + + public override void VisitConstructorDeclaration(ConstructorDeclarationSyntax node) + { + hasConstructor = true; + + if (!IsPublicNode(node)) + { + return; + } + + base.VisitConstructorDeclaration(node); + + var symbol = Model.GetDeclaredSymbol(node); + int numParameters = node.ParameterList.Parameters.Count; + Parameter[] parameters = new Parameter[numParameters]; + for (int idx = 0; idx < numParameters; idx++) + { + parameters[idx] = new Parameter(node.ParameterList.Parameters[idx], ParameterAttributes.In, Model); + } + + var methodDefinitionHandle = AddMethodDefinition( + ".ctor", + parameters, + null, + false, + false, + true, + true, + true); + currentTypeDeclaration.AddMethod(symbol, ".ctor", methodDefinitionHandle); + hasDefaultConstructor |= (numParameters == 0); + } + + void AddMethodDeclaration(IMethodSymbol method, bool isInterfaceParent) + { + Logger.Log("add method from symbol: " + method.Name); + + int numParameters = method.Parameters.Count(); + Parameter[] parameters = new Parameter[numParameters]; + for (int idx = 0; idx < numParameters; idx++) + { + parameters[idx] = new Parameter(method.Parameters[idx].Type, method.Parameters[idx].Name, ParameterAttributes.In); + } + + string methodName = method.MethodKind == MethodKind.Constructor ? ".ctor" : method.Name; + var methodDefinitionHandle = AddMethodDefinition( + methodName, + parameters, + new Symbol(method.ReturnType), + !isInterfaceParent && method.IsStatic, + isInterfaceParent, + method.MethodKind == MethodKind.Constructor, + true, + true); + currentTypeDeclaration.AddMethod(method, methodName, methodDefinitionHandle); + } + + void AddFactoryMethod(INamedTypeSymbol classSymbol, IMethodSymbol method) + { + Logger.Log("adding factory method: " + method.Name); + + int numParameters = method.Parameters.Count(); + Parameter[] parameters = new Parameter[numParameters]; + for (int idx = 0; idx < numParameters; idx++) + { + parameters[idx] = new Parameter(method.Parameters[idx].Type, method.Parameters[idx].Name, ParameterAttributes.In); + } + + string methodName = "Create" + classSymbol.Name; + var methodDefinitionHandle = AddMethodDefinition( + methodName, + parameters, + new Symbol(classSymbol), + false, + true, + false, + true, + true); + currentTypeDeclaration.AddMethod(method, methodName, methodDefinitionHandle); + } + + void AddExternalType(INamedTypeSymbol type) + { + // TODO: check if custom projected interface + // TODO: block or warn type names with namespaces not meeting WinRT requirements. + // TODO: synthesized interfaces and default interface impl. + // TODO: extends + + var typeDeclaration = new TypeDeclaration(type); + currentTypeDeclaration = typeDeclaration; + bool isInterface = type.TypeKind == TypeKind.Interface; + + foreach (var member in type.GetMembers()) + { + if(member is IMethodSymbol method && + (method.MethodKind == MethodKind.Ordinary || method.MethodKind == MethodKind.Constructor)) + { + AddMethodDeclaration(method, isInterface); + } + else if(member is IPropertySymbol property) + { + AddPropertyDeclaration(property, isInterface); + } + else if(member is IEventSymbol @event) + { + AddEventDeclaration(@event, isInterface); + } + else + { + Logger.Log("member not recognized: " + member.Kind + " name: " + member.Name); + } + } + + TypeAttributes typeAttributes = + TypeAttributes.Public | + TypeAttributes.WindowsRuntime | + TypeAttributes.AutoLayout | + TypeAttributes.AnsiClass | + TypeAttributes.Interface | + TypeAttributes.Abstract; + + var typeDefinitionHandle = AddTypeDefinition( + typeAttributes, + type.ContainingNamespace.ToString(), + type.Name, + default); + typeDeclaration.Handle = typeDefinitionHandle; + typeDefinitionMapping[type.ToString()] = typeDeclaration; + + foreach (var implementedInterface in type.AllInterfaces.OrderBy(implementedInterface => implementedInterface.ToString())) + { + var interfaceImplHandle = metadataBuilder.AddInterfaceImplementation( + typeDefinitionHandle, + GetTypeReference(implementedInterface)); + typeDeclaration.AddInterfaceImpl(implementedInterface, interfaceImplHandle); + } + + if (isInterface) + { + AddGuidAttribute(typeDefinitionHandle, type.ToString()); + AddOverloadAttributeForInterfaceMethods(typeDeclaration); + } + } + + MemberReferenceHandle AddMethodReference( + string name, + Parameter[] parameters, + Symbol returnSymbol, + ISymbol parentType, + bool isStatic) + { + var methodSignature = new BlobBuilder(); + new BlobEncoder(methodSignature) + .MethodSignature( + SignatureCallingConvention.Default, + 0, + !isStatic) + .Parameters( + parameters.Length, + returnType => EncodeReturnType(returnSymbol, returnType), + parametersEncoder => EncodeParameters(parameters, parametersEncoder) + ); + + var referenceHandle = metadataBuilder.AddMemberReference( + GetTypeReference(parentType), + metadataBuilder.GetOrAddString(name), + metadataBuilder.GetOrAddBlob(methodSignature) + ); + return referenceHandle; + } + + MemberReferenceHandle AddMethodReference(IMethodSymbol method) + { + Logger.Log("adding method reference: " + method.Name); + + bool isInterfaceParent = method.ContainingType.TypeKind == TypeKind.Interface; + int numParameters = method.Parameters.Count(); + Parameter[] parameters = new Parameter[numParameters]; + for (int idx = 0; idx < numParameters; idx++) + { + parameters[idx] = new Parameter(method.Parameters[idx].Type, method.Parameters[idx].Name, ParameterAttributes.In); + } + + string methodName = method.MethodKind == MethodKind.Constructor ? ".ctor" : method.Name; + + var referenceHandle = AddMethodReference( + methodName, + parameters, + new Symbol(method.ReturnType), + method.ContainingType, + !isInterfaceParent && method.IsStatic); + currentTypeDeclaration.AddMethodReference(method, referenceHandle); + return referenceHandle; + } + + public void AddPropertyReference(IPropertySymbol property) + { + Logger.Log("adding property reference: " + property.Name); + + if (property.SetMethod != null) + { + var setMethodReference = AddMethodReference( + "put_" + property.Name, + new Parameter[] { new Parameter(property.Type, "value", ParameterAttributes.In) }, + null, + property.ContainingType, + false); + currentTypeDeclaration.AddMethodReference(property, setMethodReference); + } + + var getMethodReference = AddMethodReference( + "get_" + property.Name, + new Parameter[0], + new Symbol(property.Type), + property.ContainingType, + false); + currentTypeDeclaration.AddMethodReference(property, getMethodReference); + } + + public void AddEventReference(IEventSymbol @event) + { + Logger.Log("adding event reference: " + @event.Name); + + var delegateSymbolType = @event.Type; + EntityHandle eventRegistrationTokenTypeHandle = GetTypeReference("Windows.Foundation", "EventRegistrationToken", "Windows.Foundation.FoundationContract"); + Symbol eventRegistrationToken = new Symbol(eventRegistrationTokenTypeHandle); + + var addMethodReference = AddMethodReference( + "add_" + @event.Name, + new Parameter[] { new Parameter(delegateSymbolType, "handler", ParameterAttributes.In) }, + eventRegistrationToken, + @event.ContainingType, + false); + currentTypeDeclaration.AddMethodReference(delegateSymbolType, addMethodReference); + + var removeMethodReference = AddMethodReference( + "remove_" + @event.Name, + new Parameter[] { new Parameter(eventRegistrationToken, "token", ParameterAttributes.In) }, + null, + @event.ContainingType, + false); + currentTypeDeclaration.AddMethodReference(delegateSymbolType, removeMethodReference); + } + + void AddProjectedType(INamedTypeSymbol type) + { + currentTypeDeclaration = new TypeDeclaration(type); + + foreach (var member in type.GetMembers()) + { + if (member is IMethodSymbol method && + (method.MethodKind == MethodKind.Ordinary || method.MethodKind == MethodKind.Constructor)) + { + AddMethodReference(method); + } + else if (member is IPropertySymbol property) + { + AddPropertyReference(property); + } + else if (member is IEventSymbol @event) + { + AddEventReference(@event); + } + else + { + Logger.Log("member not recognized: " + member.Kind + " " + member.Name); + } + } + + typeDefinitionMapping[type.ToString()] = currentTypeDeclaration; + } + + enum SynthesizedInterfaceType + { + Static, + Factory, + Default + } + + string GetSynthesizedInterfaceName(string className, SynthesizedInterfaceType type) + { + // TODO: handle existing types by appending number suffix + return "I" + className + + type switch + { + SynthesizedInterfaceType.Default => "Class", + SynthesizedInterfaceType.Factory => "Factory", + SynthesizedInterfaceType.Static => "Static", + _ => "", + }; + } + + void AddSynthesizedInterfaces(TypeDeclaration classDeclaration) + { + HashSet classMembersFromInterfaces = new HashSet(); + INamedTypeSymbol classSymbol = classDeclaration.Node as INamedTypeSymbol; + foreach (var @interface in classSymbol.AllInterfaces) + { + foreach(var interfaceMember in @interface.GetMembers()) + { + classMembersFromInterfaces.Add(classSymbol.FindImplementationForInterfaceMember(interfaceMember)); + } + } + + AddSynthesizedInterface( + classDeclaration, + SynthesizedInterfaceType.Static, + classMembersFromInterfaces); + + AddSynthesizedInterface( + classDeclaration, + SynthesizedInterfaceType.Factory, + classMembersFromInterfaces); + + AddSynthesizedInterface( + classDeclaration, + SynthesizedInterfaceType.Default, + classMembersFromInterfaces); + + // TODO: address overridable and composable interfaces. + } + + void AddSynthesizedInterface( + TypeDeclaration classDeclaration, + SynthesizedInterfaceType interfaceType, + HashSet classMembersFromInterfaces) + { + var typeDeclaration = new TypeDeclaration(null); + currentTypeDeclaration = typeDeclaration; + + bool hasTypes = false; + INamedTypeSymbol classSymbol = classDeclaration.Node as INamedTypeSymbol; + + // Each class member results in some form of method definition, + // so using that to our advantage to get public members. + foreach (var classMember in classDeclaration.MethodDefinitions) + { + if (interfaceType == SynthesizedInterfaceType.Factory && + classMember.Key is IMethodSymbol constructorMethod && + constructorMethod.MethodKind == MethodKind.Constructor && + constructorMethod.Parameters.Length != 0) + { + hasTypes = true; + AddFactoryMethod(classSymbol, constructorMethod); + } + else if((interfaceType == SynthesizedInterfaceType.Default && !classMember.Key.IsStatic && + !classMembersFromInterfaces.Contains(classMember.Key)) || + (interfaceType == SynthesizedInterfaceType.Static && classMember.Key.IsStatic)) + { + if (classMember.Key is IMethodSymbol method && method.MethodKind == MethodKind.Ordinary) + { + AddMethodDeclaration(method, true); + } + else if (classMember.Key is IPropertySymbol property) + { + AddPropertyDeclaration(property, true); + } + else if (classMember.Key is IEventSymbol @event) + { + AddEventDeclaration(@event, true); + } + else + { + Logger.Log("member for synthesized interface not recognized: " + classMember.Key.Kind + " " + classMember.Key.Name); + continue; + } + + hasTypes = true; + } + } + + TypeAttributes typeAttributes = + TypeAttributes.NotPublic | + TypeAttributes.WindowsRuntime | + TypeAttributes.AutoLayout | + TypeAttributes.AnsiClass | + TypeAttributes.Interface | + TypeAttributes.Abstract; + + if (hasTypes) + { + Logger.Log("writing generated interface " + interfaceType); + var interfaceName = GetSynthesizedInterfaceName(classDeclaration.Node.Name, interfaceType); + var typeDefinitionHandle = AddTypeDefinition( + typeAttributes, + classDeclaration.Node.ContainingNamespace.ToString(), + interfaceName, + default); + typeDeclaration.Handle = typeDefinitionHandle; + + string qualifiedInterfaceName = QualifiedName(classDeclaration.Node.ContainingNamespace.ToString(), interfaceName); + typeDefinitionMapping[qualifiedInterfaceName] = typeDeclaration; + + if(interfaceType == SynthesizedInterfaceType.Default) + { + classDeclaration.DefaultInterface = qualifiedInterfaceName; + var interfaceImplHandle = metadataBuilder.AddInterfaceImplementation( + classDeclaration.Handle, + GetTypeReference(classDeclaration.Node.ContainingNamespace.ToString(), interfaceName, assembly)); + classDeclaration.AddInterfaceImpl(classSymbol, interfaceImplHandle); + AddDefaultInterfaceImplAttribute(interfaceImplHandle); + } + + AddDefaultVersionAttribute(typeDefinitionHandle, GetVersion(classSymbol, true)); + AddGuidAttribute(typeDefinitionHandle, interfaceName); + AddExclusiveToAttribute(typeDefinitionHandle, classSymbol.ToString()); + AddOverloadAttributeForInterfaceMethods(typeDeclaration); + + if (interfaceType == SynthesizedInterfaceType.Factory) + { + AddActivatableAttribute(classDeclaration.Handle, (uint) GetVersion(classSymbol, true), qualifiedInterfaceName); + } + else if(interfaceType == SynthesizedInterfaceType.Static) + { + classDeclaration.StaticInterface = qualifiedInterfaceName; + AddStaticAttribute(classDeclaration.Handle, (uint)GetVersion(classSymbol, true), qualifiedInterfaceName); + } + } + } + + private int GetVersion(INamedTypeSymbol type, bool setDefaultIfNotSet = false) + { + var versionAttribute = type.GetAttributes(). + Where(attribute => attribute.AttributeClass.Name == "VersionAttribute"); + if(!versionAttribute.Any()) + { + return setDefaultIfNotSet ? Version.Parse(this.version).Major : - 1; + } + + uint version = (uint) versionAttribute.First().ConstructorArguments[0].Value; + return (int) version; + } + + void AddType(INamedTypeSymbol type) + { + bool isProjectedType = type.GetAttributes(). + Any(attribute => attribute.AttributeClass.Name == "WindowsRuntimeTypeAttribute"); + if (isProjectedType) + { + AddProjectedType(type); + } + else if(MappedCSharpTypes.ContainsKey(type.ToString())) + { + var mappedType = MappedCSharpTypes[type.ToString()]; + AddProjectedType(Model.Compilation.GetTypeByMetadataName(QualifiedName(mappedType.@namespace, mappedType.name))); + } + else + { + AddExternalType(type); + } + } + + public void FinalizeGeneration() + { + var classTypeDeclarations = typeDefinitionMapping.Values + .Where(declaration => declaration.Node is INamedTypeSymbol symbol && symbol.TypeKind == TypeKind.Class) + .ToList(); + foreach (var classTypeDeclaration in classTypeDeclarations) + { + INamedTypeSymbol classSymbol = classTypeDeclaration.Node as INamedTypeSymbol; + + foreach (var implementedInterface in classSymbol.AllInterfaces) + { + if (!typeDefinitionMapping.ContainsKey(implementedInterface.ToString())) + { + AddType(implementedInterface); + } + + var interfaceTypeDeclaration = typeDefinitionMapping[implementedInterface.ToString()]; + foreach (var interfaceMember in interfaceTypeDeclaration.MethodReferences) + { + var classMember = classSymbol.FindImplementationForInterfaceMember(interfaceMember.Key); + if (classTypeDeclaration.MethodDefinitions.ContainsKey(classMember)) + { + var interfaceMemberMethodDefinitions = interfaceMember.Value; + var classMemberMethodDefinitions = classTypeDeclaration.MethodDefinitions[classMember]; + for (int idx = 0; idx < interfaceMemberMethodDefinitions.Count; idx++) + { + metadataBuilder.AddMethodImplementation( + classTypeDeclaration.Handle, + classMemberMethodDefinitions[idx], + interfaceMemberMethodDefinitions[idx]); + } + + // If method overloaded in interface, overload in class too. + if (interfaceTypeDeclaration.OverloadedMethods.ContainsKey(interfaceMember.Key)) + { + AddOverloadAttribute(classMemberMethodDefinitions.First(), interfaceTypeDeclaration.OverloadedMethods[interfaceMember.Key]); + } + } + } + } + + if (classTypeDeclaration.DefaultInterface != null) + { + var defaultInterfaceTypeDeclaration = typeDefinitionMapping[classTypeDeclaration.DefaultInterface]; + foreach (var interfaceMember in defaultInterfaceTypeDeclaration.MethodReferences) + { + if (classTypeDeclaration.MethodDefinitions.ContainsKey(interfaceMember.Key)) + { + var interfaceMemberMethodDefinitions = interfaceMember.Value; + var classMemberMethodDefinitions = classTypeDeclaration.MethodDefinitions[interfaceMember.Key]; + for (int idx = 0; idx < interfaceMemberMethodDefinitions.Count; idx++) + { + metadataBuilder.AddMethodImplementation( + classTypeDeclaration.Handle, + classMemberMethodDefinitions[idx], + interfaceMemberMethodDefinitions[idx]); + } + + // If method overloaded in interface, overload in class too. + if (defaultInterfaceTypeDeclaration.OverloadedMethods.ContainsKey(interfaceMember.Key)) + { + AddOverloadAttribute(classMemberMethodDefinitions.First(), defaultInterfaceTypeDeclaration.OverloadedMethods[interfaceMember.Key]); + } + } + } + } + + if (classTypeDeclaration.StaticInterface != null) + { + var staticInterfaceTypeDeclaration = typeDefinitionMapping[classTypeDeclaration.StaticInterface]; + foreach (var interfaceMember in staticInterfaceTypeDeclaration.MethodReferences) + { + // If method overloaded in static interface, overload in class too. + if (classTypeDeclaration.MethodDefinitions.ContainsKey(interfaceMember.Key) && + staticInterfaceTypeDeclaration.OverloadedMethods.ContainsKey(interfaceMember.Key)) + { + AddOverloadAttribute( + classTypeDeclaration.MethodDefinitions[interfaceMember.Key].First(), + staticInterfaceTypeDeclaration.OverloadedMethods[interfaceMember.Key] + ); + } + } + } + } + + var interfaceDeclarations = typeDefinitionMapping.Values + .Where(declaration => declaration.Node is INamedTypeSymbol symbol && symbol.TypeKind == TypeKind.Interface) + .ToList(); + foreach (var interfaceDeclaration in interfaceDeclarations) + { + INamedTypeSymbol interfaceSymbol = interfaceDeclaration.Node as INamedTypeSymbol; + if (typeDefinitionMapping[interfaceSymbol.ToString()].Handle != default && GetVersion(interfaceSymbol) == -1) + { + AddDefaultVersionAttribute(typeDefinitionMapping[interfaceSymbol.ToString()].Handle); + } + } + + foreach (var node in nodesWithAttributes) + { + EntityHandle parentHandle = default; + if(node is INamedTypeSymbol namedType) + { + parentHandle = typeDefinitionMapping[namedType.ToString()].Handle; + } + else if (node is IMethodSymbol method) + { + parentHandle = typeDefinitionMapping[method.ContainingType.ToString()].MethodDefinitions[method][0]; + } + else if (node is IPropertySymbol property) + { + parentHandle = typeDefinitionMapping[property.ContainingType.ToString()].PropertyDefinitions[property]; + } + else if (node is IEventSymbol @event) + { + parentHandle = typeDefinitionMapping[@event.ContainingType.ToString()].EventDefinitions[@event]; + } + else + { + Logger.Log("node not recognized " + node.Kind + " name: " + node.Name); + } + + AddCustomAttributes(node.GetAttributes(), parentHandle); + } + } + + public bool IsPublicNode(MemberDeclarationSyntax node) + { + return node.Modifiers.Any(modifier => modifier.ValueText == "public") || + (node.Parent is InterfaceDeclarationSyntax && node.Modifiers.Count == 0); + } + + public bool IsPrivateNode(AccessorDeclarationSyntax node) + { + return node.Modifiers.Any(modifier => modifier.ValueText == "private"); + } + + public bool IsStaticNode(MemberDeclarationSyntax node) + { + return node.Modifiers.Any(modifier => modifier.ValueText == "static"); + } + + public bool IsSealedNode(MemberDeclarationSyntax node) + { + return node.Modifiers.Any(modifier => modifier.ValueText == "sealed"); + } + + public string GetNamespace() + { + return string.Join(".", namespaces); + } + + public string QualifiedName(string identifier) + { + return QualifiedName(GetNamespace(), identifier); + } + + public string QualifiedName(string @namespace, string identifier) + { + return string.Join(".", @namespace, identifier); + } + + public override void VisitNamespaceDeclaration(NamespaceDeclarationSyntax node) + { + namespaces.Push(node.Name.ToString()); + base.VisitNamespaceDeclaration(node); + namespaces.Pop(); + } + } +} diff --git a/Benchmarks/Benchmarks.csproj b/src/Benchmarks/Benchmarks.csproj similarity index 98% rename from Benchmarks/Benchmarks.csproj rename to src/Benchmarks/Benchmarks.csproj index 608989965..f1a880ce1 100644 --- a/Benchmarks/Benchmarks.csproj +++ b/src/Benchmarks/Benchmarks.csproj @@ -1,59 +1,59 @@ - - - - Exe - x64;x86 - netcoreapp2.0;net5.0;netcoreapp3.1 - false - false - - true - Benchmarks.manifest - - - - - - - - - - - - - - - - BenchmarkComponent.dll - PreserveNewest - True - - - - $(MSBuildThisFileDirectory)..\_build\$(Platform)\$(Configuration)\BenchmarkComponent\bin\BenchmarkComponent\BenchmarkComponent.winmd - true - - - - - Benchmarks.manifest - PreserveNewest - True - - - - - - - - - - - - - - - - - - + + + + Exe + x64;x86 + netcoreapp2.0;net5.0;netcoreapp3.1 + false + false + + true + Benchmarks.manifest + + + + + + + + + + + + + + + + BenchmarkComponent.dll + PreserveNewest + True + + + + $(MSBuildThisFileDirectory)..\_build\$(Platform)\$(Configuration)\BenchmarkComponent\bin\BenchmarkComponent\BenchmarkComponent.winmd + true + + + + + Benchmarks.manifest + PreserveNewest + True + + + + + + + + + + + + + + + + + + diff --git a/Benchmarks/Benchmarks.manifest b/src/Benchmarks/Benchmarks.manifest similarity index 97% rename from Benchmarks/Benchmarks.manifest rename to src/Benchmarks/Benchmarks.manifest index e8095ea19..3c9e5e0c3 100644 --- a/Benchmarks/Benchmarks.manifest +++ b/src/Benchmarks/Benchmarks.manifest @@ -1,16 +1,16 @@ - - - - - - - - - - + + + + + + + + + + diff --git a/Benchmarks/Program.cs b/src/Benchmarks/Program.cs similarity index 97% rename from Benchmarks/Program.cs rename to src/Benchmarks/Program.cs index 89255f080..16ed34a72 100644 --- a/Benchmarks/Program.cs +++ b/src/Benchmarks/Program.cs @@ -1,95 +1,95 @@ -using BenchmarkDotNet.Running; -using System; -using BenchmarkDotNet.Configs; -using BenchmarkDotNet.Jobs; -using BenchmarkDotNet.Toolchains.CsProj; -using BenchmarkDotNet.Toolchains.DotNetCli; -using BenchmarkDotNet.Toolchains; -using BenchmarkDotNet.Loggers; -using BenchmarkDotNet.Characteristics; -using System.IO; - -namespace Benchmarks -{ - public class Program - { - static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, new CustomConfig().Config); - - private class CustomConfig : Attribute, IConfigSource - { - public IConfig Config { get; } = DefaultConfig.Instance; - - public CustomConfig() - { - // Test CsWinRT projection - var job = Job.Default - .WithPlatform(BenchmarkDotNet.Environments.Platform.X64) - .WithArguments( - new Argument[] { - new MsBuildArgument("/p:platform=x64") - } - ).AsDefault(); - - // Test WinMD support -#if NETCOREAPP3_1 - // BenchmarkDotNet will rebuild the project with a project reference to this project when this project's output exe is ran. It - // will be ran from the same folder as where we have the application manifest binplaced which we want to embed in the new exe. - string manifestFile = Path.Combine( - Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), - "Benchmarks.manifest"); - - var winmdJob = Job.Default - .WithPlatform(BenchmarkDotNet.Environments.Platform.X64) - .WithToolchain(new NetCore3ToolChainWithNativeExecution()) - .WithArguments( - new Argument[] { - new MsBuildArgument("/p:platform=x64"), - new MsBuildArgument("/p:ApplicationManifest=" + manifestFile), - new MsBuildArgument("/p:BenchmarkWinmdSupport=true") - } - ) - .WithId("WinMD NetCoreApp31"); - - // Optimizer needs to be diabled as it errors on WinMDs - Config = Config.WithOption(ConfigOptions.DisableOptimizationsValidator, true) - .AddJob(winmdJob); -#else - Config = Config.AddJob(job); -#endif - } - } - - // Custom tool chain for building the benchmark with WinMDs as we need to execute the - // exe version of the benchmark rather than the dll version which runs under dotnet cli. - // This is because we need to be able to embed a side by side manifest for reg free winrt - // and we need COM to be able to find the WinMDs. - private class NetCore3ToolChainWithNativeExecution : Toolchain - { - public NetCore3ToolChainWithNativeExecution() - : base("netcoreapp3.1-native", - new CsProjGeneratorWithNativeExe(NetCoreAppSettings.NetCoreApp31), - CsProjCoreToolchain.NetCoreApp31.Builder, - new Executor()) - { - } - - public override bool IsSupported(BenchmarkCase benchmarkCase, ILogger logger, IResolver resolver) - { - return CsProjCoreToolchain.NetCoreApp31.IsSupported(benchmarkCase, logger, resolver); - } - } - - private class CsProjGeneratorWithNativeExe : CsProjGenerator - { - public CsProjGeneratorWithNativeExe(NetCoreAppSettings settings) - :base(settings.TargetFrameworkMoniker, settings.CustomDotNetCliPath, settings.PackagesPath, settings.RuntimeFrameworkVersion) - { - } - - protected override string GetExecutableExtension() - { - return ".exe"; - } - } - } -} +using BenchmarkDotNet.Running; +using System; +using BenchmarkDotNet.Configs; +using BenchmarkDotNet.Jobs; +using BenchmarkDotNet.Toolchains.CsProj; +using BenchmarkDotNet.Toolchains.DotNetCli; +using BenchmarkDotNet.Toolchains; +using BenchmarkDotNet.Loggers; +using BenchmarkDotNet.Characteristics; +using System.IO; + +namespace Benchmarks +{ + public class Program + { + static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args, new CustomConfig().Config); + + private class CustomConfig : Attribute, IConfigSource + { + public IConfig Config { get; } = DefaultConfig.Instance; + + public CustomConfig() + { + // Test CsWinRT projection + var job = Job.Default + .WithPlatform(BenchmarkDotNet.Environments.Platform.X64) + .WithArguments( + new Argument[] { + new MsBuildArgument("/p:platform=x64") + } + ).AsDefault(); + + // Test WinMD support +#if NETCOREAPP3_1 + // BenchmarkDotNet will rebuild the project with a project reference to this project when this project's output exe is ran. It + // will be ran from the same folder as where we have the application manifest binplaced which we want to embed in the new exe. + string manifestFile = Path.Combine( + Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), + "Benchmarks.manifest"); + + var winmdJob = Job.Default + .WithPlatform(BenchmarkDotNet.Environments.Platform.X64) + .WithToolchain(new NetCore3ToolChainWithNativeExecution()) + .WithArguments( + new Argument[] { + new MsBuildArgument("/p:platform=x64"), + new MsBuildArgument("/p:ApplicationManifest=" + manifestFile), + new MsBuildArgument("/p:BenchmarkWinmdSupport=true") + } + ) + .WithId("WinMD NetCoreApp31"); + + // Optimizer needs to be diabled as it errors on WinMDs + Config = Config.WithOption(ConfigOptions.DisableOptimizationsValidator, true) + .AddJob(winmdJob); +#else + Config = Config.AddJob(job); +#endif + } + } + + // Custom tool chain for building the benchmark with WinMDs as we need to execute the + // exe version of the benchmark rather than the dll version which runs under dotnet cli. + // This is because we need to be able to embed a side by side manifest for reg free winrt + // and we need COM to be able to find the WinMDs. + private class NetCore3ToolChainWithNativeExecution : Toolchain + { + public NetCore3ToolChainWithNativeExecution() + : base("netcoreapp3.1-native", + new CsProjGeneratorWithNativeExe(NetCoreAppSettings.NetCoreApp31), + CsProjCoreToolchain.NetCoreApp31.Builder, + new Executor()) + { + } + + public override bool IsSupported(BenchmarkCase benchmarkCase, ILogger logger, IResolver resolver) + { + return CsProjCoreToolchain.NetCoreApp31.IsSupported(benchmarkCase, logger, resolver); + } + } + + private class CsProjGeneratorWithNativeExe : CsProjGenerator + { + public CsProjGeneratorWithNativeExe(NetCoreAppSettings settings) + :base(settings.TargetFrameworkMoniker, settings.CustomDotNetCliPath, settings.PackagesPath, settings.RuntimeFrameworkVersion) + { + } + + protected override string GetExecutableExtension() + { + return ".exe"; + } + } + } +} diff --git a/Benchmarks/QueryInterface.cs b/src/Benchmarks/QueryInterface.cs similarity index 96% rename from Benchmarks/QueryInterface.cs rename to src/Benchmarks/QueryInterface.cs index 567ef3aa9..28c9b196a 100644 --- a/Benchmarks/QueryInterface.cs +++ b/src/Benchmarks/QueryInterface.cs @@ -1,79 +1,79 @@ -using BenchmarkComponent; -using BenchmarkDotNet.Attributes; -using Windows.ApplicationModel.Chat; - -namespace Benchmarks -{ - [MemoryDiagnoser] - public class QueryInterfacePerf - { - ClassWithMultipleInterfaces instance; - ChatMessage message; - - [GlobalSetup] - public void Setup() - { - instance = new ClassWithMultipleInterfaces(); - message = new ChatMessage(); - } - - [Benchmark] - public int QueryDefaultInterface() - { - return instance.DefaultIntProperty; - } - - [Benchmark] - public int QueryNonDefaultInterface() - { - return instance.IntProperty; - } - - [Benchmark] - public bool QueryNonDefaultInterface2() - { - return instance.BoolProperty; - } - - [Benchmark] - public void QueryDefaultInterfaceSetProperty() - { - instance.DefaultIntProperty = 4; - } - - [Benchmark] - public void QueryNonDefaultInterfaceSetProperty() - { - instance.IntProperty = 4; - } - - [Benchmark] - public bool QuerySDKDefaultInterface() - { - return message.IsForwardingDisabled; - } - - [Benchmark] - public bool QuerySDKNonDefaultInterface() - { - return message.IsSeen; - } - - // The following 2 benchmarks try to benchmark the time taken for the first call - // rather than the mean time over several calls. It has the overhead of the object - // construction, but it can be used to track regressions to performance. - [Benchmark] - public int ConstructAndQueryDefaultInterfaceFirstCall() - { - ClassWithMultipleInterfaces instance2 = new ClassWithMultipleInterfaces(); - return instance2.DefaultIntProperty; - } - - [Benchmark] - public int ConstructAndQueryNonDefaultInterfaceFirstCall() - { - ClassWithMultipleInterfaces instance2 = new ClassWithMultipleInterfaces(); - return instance2.IntProperty; - } - } +using BenchmarkComponent; +using BenchmarkDotNet.Attributes; +using Windows.ApplicationModel.Chat; + +namespace Benchmarks +{ + [MemoryDiagnoser] + public class QueryInterfacePerf + { + ClassWithMultipleInterfaces instance; + ChatMessage message; + + [GlobalSetup] + public void Setup() + { + instance = new ClassWithMultipleInterfaces(); + message = new ChatMessage(); + } + + [Benchmark] + public int QueryDefaultInterface() + { + return instance.DefaultIntProperty; + } + + [Benchmark] + public int QueryNonDefaultInterface() + { + return instance.IntProperty; + } + + [Benchmark] + public bool QueryNonDefaultInterface2() + { + return instance.BoolProperty; + } + + [Benchmark] + public void QueryDefaultInterfaceSetProperty() + { + instance.DefaultIntProperty = 4; + } + + [Benchmark] + public void QueryNonDefaultInterfaceSetProperty() + { + instance.IntProperty = 4; + } + + [Benchmark] + public bool QuerySDKDefaultInterface() + { + return message.IsForwardingDisabled; + } + + [Benchmark] + public bool QuerySDKNonDefaultInterface() + { + return message.IsSeen; + } + + // The following 2 benchmarks try to benchmark the time taken for the first call + // rather than the mean time over several calls. It has the overhead of the object + // construction, but it can be used to track regressions to performance. + [Benchmark] + public int ConstructAndQueryDefaultInterfaceFirstCall() + { + ClassWithMultipleInterfaces instance2 = new ClassWithMultipleInterfaces(); + return instance2.DefaultIntProperty; + } + + [Benchmark] + public int ConstructAndQueryNonDefaultInterfaceFirstCall() + { + ClassWithMultipleInterfaces instance2 = new ClassWithMultipleInterfaces(); + return instance2.IntProperty; + } + } } \ No newline at end of file diff --git a/Benchmarks/ReflectionPerf.cs b/src/Benchmarks/ReflectionPerf.cs similarity index 100% rename from Benchmarks/ReflectionPerf.cs rename to src/Benchmarks/ReflectionPerf.cs diff --git a/Directory.Build.props b/src/Directory.Build.props similarity index 97% rename from Directory.Build.props rename to src/Directory.Build.props index 2d9ea1c9e..e1173c08e 100644 --- a/Directory.Build.props +++ b/src/Directory.Build.props @@ -84,6 +84,6 @@ - + diff --git a/Directory.Build.targets b/src/Directory.Build.targets similarity index 93% rename from Directory.Build.targets rename to src/Directory.Build.targets index 8ebb918e5..7e4a81496 100644 --- a/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -30,6 +30,6 @@ - + diff --git a/Projections/Benchmark/Benchmark.csproj b/src/Projections/Benchmark/Benchmark.csproj similarity index 100% rename from Projections/Benchmark/Benchmark.csproj rename to src/Projections/Benchmark/Benchmark.csproj diff --git a/Projections/Directory.Build.props b/src/Projections/Directory.Build.props similarity index 100% rename from Projections/Directory.Build.props rename to src/Projections/Directory.Build.props diff --git a/Projections/Test/Test.csproj b/src/Projections/Test/Test.csproj similarity index 89% rename from Projections/Test/Test.csproj rename to src/Projections/Test/Test.csproj index 666d63bc3..ad43fb7d5 100644 --- a/Projections/Test/Test.csproj +++ b/src/Projections/Test/Test.csproj @@ -1,31 +1,31 @@ - - - - netstandard2.0;net5.0 - x64;x86 - - - - - - - - - - - - - - - - - TestComponent;TestComponentCSharp;test_component_base;test_component_derived; - - $([MSBuild]::NormalizeDirectory('$(NuGetPackageRoot)', 'microsoft.winui', '$(MicrosoftWinUIVersion)')) - - - - - - - + + + + netstandard2.0;net5.0 + x64;x86 + + + + + + + + + + + + + + + + + TestComponent;TestComponentCSharp;test_component_base;test_component_derived; + + $([MSBuild]::NormalizeDirectory('$(NuGetPackageRoot)', 'microsoft.winui', '$(MicrosoftWinUIVersion)')) + + + + + + + \ No newline at end of file diff --git a/Projections/Test/TestHost.ProbeByHost.cs b/src/Projections/Test/TestHost.ProbeByHost.cs similarity index 97% rename from Projections/Test/TestHost.ProbeByHost.cs rename to src/Projections/Test/TestHost.ProbeByHost.cs index 67c27dfe9..60d7b7c8f 100644 --- a/Projections/Test/TestHost.ProbeByHost.cs +++ b/src/Projections/Test/TestHost.ProbeByHost.cs @@ -1,144 +1,144 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using Windows.Foundation; -using WinRT; - - -#region Temporary, until authoring support generates activation factory support - -namespace Windows.Foundation -{ - [global::WinRT.WindowsRuntimeType] - [Guid("00000035-0000-0000-c000-000000000046")] - internal interface IActivationFactory - { - Object ActivateInstance(); - } -} - -namespace ABI.Windows.Foundation -{ - [global::WinRT.ObjectReferenceWrapper(nameof(_obj))] - [Guid("00000035-0000-0000-c000-000000000046")] - internal class IActivationFactory : global::Windows.Foundation.IActivationFactory - { - public unsafe delegate int ActivateInstance_0(IntPtr thisPtr, out IntPtr instance); - - [Guid("00000035-0000-0000-c000-000000000046")] - public struct Vftbl - { - internal IInspectable.Vftbl IInspectableVftbl; - public ActivateInstance_0 ActivateInstance_0; - - private static readonly Vftbl AbiToProjectionVftable; - public static readonly IntPtr AbiToProjectionVftablePtr; - static unsafe Vftbl() - { - AbiToProjectionVftable = new Vftbl - { - IInspectableVftbl = global::WinRT.IInspectable.Vftbl.AbiToProjectionVftable, - ActivateInstance_0 = Do_Abi_ActivateInstance_0 - }; - var nativeVftbl = (IntPtr*)ComWrappersSupport.AllocateVtableMemory(typeof(Vftbl), Marshal.SizeOf() + sizeof(IntPtr) * 1); - Marshal.StructureToPtr(AbiToProjectionVftable, (IntPtr)nativeVftbl, false); - AbiToProjectionVftablePtr = (IntPtr)nativeVftbl; - } - - private static unsafe int Do_Abi_ActivateInstance_0(IntPtr thisPtr, out IntPtr instance) - { - object __instance = default; - instance = default; - try - { - __instance = global::WinRT.ComWrappersSupport.FindObject(thisPtr).ActivateInstance(); - instance = MarshalInspectable.FromManaged(__instance); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - internal static ObjectReference FromAbi(IntPtr thisPtr) => ObjectReference.FromAbi(thisPtr); - - public static implicit operator IActivationFactory(IObjectReference obj) => (obj != null) ? new IActivationFactory(obj) : null; - protected readonly ObjectReference _obj; - public IObjectReference ObjRef { get => _obj; } - public IntPtr ThisPtr => _obj.ThisPtr; - public ObjectReference AsInterface() => _obj.As(); - public A As() => _obj.AsType(); - public IActivationFactory(IObjectReference obj) : this(obj.As()) { } - internal IActivationFactory(ObjectReference obj) - { - _obj = obj; - } - - public unsafe object ActivateInstance() - { - IntPtr __retval = default; - try - { - global::WinRT.ExceptionHelpers.ThrowExceptionForHR(_obj.Vftbl.ActivateInstance_0(ThisPtr, out __retval)); - return MarshalInspectable.FromAbi(__retval); - } - finally - { - MarshalInspectable.DisposeAbi(__retval); - } - } - } -} - -namespace WinRT.Host -{ - internal class ActivationFactory : IActivationFactory - { - public ConstructorInfo Constructor { get; private set; } - - public ActivationFactory(ConstructorInfo constructor) => Constructor = constructor; - - public object ActivateInstance() => Constructor.Invoke(null); - } -} - -#endregion - -namespace WinRT -{ - public static class Module - { - public static unsafe IntPtr GetActivationFactory(String runtimeClassId) - { - if (runtimeClassId == "TestHost.ProbeByHost") - { - var type = Type.GetType(runtimeClassId); - if (type != null) - { - var ctor = type.GetConstructor(Type.EmptyTypes); - if (ctor != null) - { - var factory = new WinRT.Host.ActivationFactory(ctor); - return MarshalInspectable.FromManaged(factory); - } - } - } - return IntPtr.Zero; - } - } -} - -namespace TestHost -{ - public class ProbeByHost : IStringable - { - public override string ToString() - { - return new System.IO.FileInfo(Assembly.GetExecutingAssembly().Location).Name; - } - } -} +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using Windows.Foundation; +using WinRT; + + +#region Temporary, until authoring support generates activation factory support + +namespace Windows.Foundation +{ + [global::WinRT.WindowsRuntimeType] + [Guid("00000035-0000-0000-c000-000000000046")] + internal interface IActivationFactory + { + Object ActivateInstance(); + } +} + +namespace ABI.Windows.Foundation +{ + [global::WinRT.ObjectReferenceWrapper(nameof(_obj))] + [Guid("00000035-0000-0000-c000-000000000046")] + internal class IActivationFactory : global::Windows.Foundation.IActivationFactory + { + public unsafe delegate int ActivateInstance_0(IntPtr thisPtr, out IntPtr instance); + + [Guid("00000035-0000-0000-c000-000000000046")] + public struct Vftbl + { + internal IInspectable.Vftbl IInspectableVftbl; + public ActivateInstance_0 ActivateInstance_0; + + private static readonly Vftbl AbiToProjectionVftable; + public static readonly IntPtr AbiToProjectionVftablePtr; + static unsafe Vftbl() + { + AbiToProjectionVftable = new Vftbl + { + IInspectableVftbl = global::WinRT.IInspectable.Vftbl.AbiToProjectionVftable, + ActivateInstance_0 = Do_Abi_ActivateInstance_0 + }; + var nativeVftbl = (IntPtr*)ComWrappersSupport.AllocateVtableMemory(typeof(Vftbl), Marshal.SizeOf() + sizeof(IntPtr) * 1); + Marshal.StructureToPtr(AbiToProjectionVftable, (IntPtr)nativeVftbl, false); + AbiToProjectionVftablePtr = (IntPtr)nativeVftbl; + } + + private static unsafe int Do_Abi_ActivateInstance_0(IntPtr thisPtr, out IntPtr instance) + { + object __instance = default; + instance = default; + try + { + __instance = global::WinRT.ComWrappersSupport.FindObject(thisPtr).ActivateInstance(); + instance = MarshalInspectable.FromManaged(__instance); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + internal static ObjectReference FromAbi(IntPtr thisPtr) => ObjectReference.FromAbi(thisPtr); + + public static implicit operator IActivationFactory(IObjectReference obj) => (obj != null) ? new IActivationFactory(obj) : null; + protected readonly ObjectReference _obj; + public IObjectReference ObjRef { get => _obj; } + public IntPtr ThisPtr => _obj.ThisPtr; + public ObjectReference AsInterface() => _obj.As(); + public A As() => _obj.AsType(); + public IActivationFactory(IObjectReference obj) : this(obj.As()) { } + internal IActivationFactory(ObjectReference obj) + { + _obj = obj; + } + + public unsafe object ActivateInstance() + { + IntPtr __retval = default; + try + { + global::WinRT.ExceptionHelpers.ThrowExceptionForHR(_obj.Vftbl.ActivateInstance_0(ThisPtr, out __retval)); + return MarshalInspectable.FromAbi(__retval); + } + finally + { + MarshalInspectable.DisposeAbi(__retval); + } + } + } +} + +namespace WinRT.Host +{ + internal class ActivationFactory : IActivationFactory + { + public ConstructorInfo Constructor { get; private set; } + + public ActivationFactory(ConstructorInfo constructor) => Constructor = constructor; + + public object ActivateInstance() => Constructor.Invoke(null); + } +} + +#endregion + +namespace WinRT +{ + public static class Module + { + public static unsafe IntPtr GetActivationFactory(String runtimeClassId) + { + if (runtimeClassId == "TestHost.ProbeByHost") + { + var type = Type.GetType(runtimeClassId); + if (type != null) + { + var ctor = type.GetConstructor(Type.EmptyTypes); + if (ctor != null) + { + var factory = new WinRT.Host.ActivationFactory(ctor); + return MarshalInspectable.FromManaged(factory); + } + } + } + return IntPtr.Zero; + } + } +} + +namespace TestHost +{ + public class ProbeByHost : IStringable + { + public override string ToString() + { + return new System.IO.FileInfo(Assembly.GetExecutingAssembly().Location).Name; + } + } +} diff --git a/Projections/TestHost.ProbeByClass/TestHost.ProbeByClass.cs b/src/Projections/TestHost.ProbeByClass/TestHost.ProbeByClass.cs similarity index 97% rename from Projections/TestHost.ProbeByClass/TestHost.ProbeByClass.cs rename to src/Projections/TestHost.ProbeByClass/TestHost.ProbeByClass.cs index c198ba995..ac9341217 100644 --- a/Projections/TestHost.ProbeByClass/TestHost.ProbeByClass.cs +++ b/src/Projections/TestHost.ProbeByClass/TestHost.ProbeByClass.cs @@ -1,144 +1,144 @@ -using System; -using System.Collections.Generic; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Text; -using Windows.Foundation; -using WinRT; - - -#region Temporary, until authoring support generates activation factory support - -namespace Windows.Foundation -{ - [global::WinRT.WindowsRuntimeType] - [Guid("00000035-0000-0000-c000-000000000046")] - internal interface IActivationFactory - { - Object ActivateInstance(); - } -} - -namespace ABI.Windows.Foundation -{ - [global::WinRT.ObjectReferenceWrapper(nameof(_obj))] - [Guid("00000035-0000-0000-c000-000000000046")] - internal class IActivationFactory : global::Windows.Foundation.IActivationFactory - { - public unsafe delegate int ActivateInstance_0(IntPtr thisPtr, out IntPtr instance); - - [Guid("00000035-0000-0000-c000-000000000046")] - public struct Vftbl - { - internal IInspectable.Vftbl IInspectableVftbl; - public ActivateInstance_0 ActivateInstance_0; - - private static readonly Vftbl AbiToProjectionVftable; - public static readonly IntPtr AbiToProjectionVftablePtr; - static unsafe Vftbl() - { - AbiToProjectionVftable = new Vftbl - { - IInspectableVftbl = global::WinRT.IInspectable.Vftbl.AbiToProjectionVftable, - ActivateInstance_0 = Do_Abi_ActivateInstance_0 - }; - var nativeVftbl = (IntPtr*)ComWrappersSupport.AllocateVtableMemory(typeof(Vftbl), Marshal.SizeOf() + sizeof(IntPtr) * 1); - Marshal.StructureToPtr(AbiToProjectionVftable, (IntPtr)nativeVftbl, false); - AbiToProjectionVftablePtr = (IntPtr)nativeVftbl; - } - - private static unsafe int Do_Abi_ActivateInstance_0(IntPtr thisPtr, out IntPtr instance) - { - object __instance = default; - instance = default; - try - { - __instance = global::WinRT.ComWrappersSupport.FindObject(thisPtr).ActivateInstance(); - instance = MarshalInspectable.FromManaged(__instance); - } - catch (Exception __exception__) - { - global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); - return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); - } - return 0; - } - } - internal static ObjectReference FromAbi(IntPtr thisPtr) => ObjectReference.FromAbi(thisPtr); - - public static implicit operator IActivationFactory(IObjectReference obj) => (obj != null) ? new IActivationFactory(obj) : null; - protected readonly ObjectReference _obj; - public IObjectReference ObjRef { get => _obj; } - public IntPtr ThisPtr => _obj.ThisPtr; - public ObjectReference AsInterface() => _obj.As(); - public A As() => _obj.AsType(); - public IActivationFactory(IObjectReference obj) : this(obj.As()) { } - internal IActivationFactory(ObjectReference obj) - { - _obj = obj; - } - - public unsafe object ActivateInstance() - { - IntPtr __retval = default; - try - { - global::WinRT.ExceptionHelpers.ThrowExceptionForHR(_obj.Vftbl.ActivateInstance_0(ThisPtr, out __retval)); - return MarshalInspectable.FromAbi(__retval); - } - finally - { - MarshalInspectable.DisposeAbi(__retval); - } - } - } -} - -namespace WinRT.Host -{ - internal class ActivationFactory : IActivationFactory - { - public ConstructorInfo Constructor { get; private set; } - - public ActivationFactory(ConstructorInfo constructor) => Constructor = constructor; - - public object ActivateInstance() => Constructor.Invoke(null); - } -} - -#endregion - -namespace WinRT -{ - public static class Module - { - public static unsafe IntPtr GetActivationFactory(String runtimeClassId) - { - if (runtimeClassId == "TestHost.ProbeByClass") - { - var type = Type.GetType(runtimeClassId); - if (type != null) - { - var ctor = type.GetConstructor(Type.EmptyTypes); - if (ctor != null) - { - var factory = new WinRT.Host.ActivationFactory(ctor); - return MarshalInspectable.FromManaged(factory); - } - } - } - return IntPtr.Zero; - } - } -} - -namespace TestHost -{ - public class ProbeByClass : IStringable - { - public override string ToString() - { - return new System.IO.FileInfo(Assembly.GetExecutingAssembly().Location).Name; - } - } -} +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Text; +using Windows.Foundation; +using WinRT; + + +#region Temporary, until authoring support generates activation factory support + +namespace Windows.Foundation +{ + [global::WinRT.WindowsRuntimeType] + [Guid("00000035-0000-0000-c000-000000000046")] + internal interface IActivationFactory + { + Object ActivateInstance(); + } +} + +namespace ABI.Windows.Foundation +{ + [global::WinRT.ObjectReferenceWrapper(nameof(_obj))] + [Guid("00000035-0000-0000-c000-000000000046")] + internal class IActivationFactory : global::Windows.Foundation.IActivationFactory + { + public unsafe delegate int ActivateInstance_0(IntPtr thisPtr, out IntPtr instance); + + [Guid("00000035-0000-0000-c000-000000000046")] + public struct Vftbl + { + internal IInspectable.Vftbl IInspectableVftbl; + public ActivateInstance_0 ActivateInstance_0; + + private static readonly Vftbl AbiToProjectionVftable; + public static readonly IntPtr AbiToProjectionVftablePtr; + static unsafe Vftbl() + { + AbiToProjectionVftable = new Vftbl + { + IInspectableVftbl = global::WinRT.IInspectable.Vftbl.AbiToProjectionVftable, + ActivateInstance_0 = Do_Abi_ActivateInstance_0 + }; + var nativeVftbl = (IntPtr*)ComWrappersSupport.AllocateVtableMemory(typeof(Vftbl), Marshal.SizeOf() + sizeof(IntPtr) * 1); + Marshal.StructureToPtr(AbiToProjectionVftable, (IntPtr)nativeVftbl, false); + AbiToProjectionVftablePtr = (IntPtr)nativeVftbl; + } + + private static unsafe int Do_Abi_ActivateInstance_0(IntPtr thisPtr, out IntPtr instance) + { + object __instance = default; + instance = default; + try + { + __instance = global::WinRT.ComWrappersSupport.FindObject(thisPtr).ActivateInstance(); + instance = MarshalInspectable.FromManaged(__instance); + } + catch (Exception __exception__) + { + global::WinRT.ExceptionHelpers.SetErrorInfo(__exception__); + return global::WinRT.ExceptionHelpers.GetHRForException(__exception__); + } + return 0; + } + } + internal static ObjectReference FromAbi(IntPtr thisPtr) => ObjectReference.FromAbi(thisPtr); + + public static implicit operator IActivationFactory(IObjectReference obj) => (obj != null) ? new IActivationFactory(obj) : null; + protected readonly ObjectReference _obj; + public IObjectReference ObjRef { get => _obj; } + public IntPtr ThisPtr => _obj.ThisPtr; + public ObjectReference AsInterface() => _obj.As(); + public A As() => _obj.AsType(); + public IActivationFactory(IObjectReference obj) : this(obj.As()) { } + internal IActivationFactory(ObjectReference obj) + { + _obj = obj; + } + + public unsafe object ActivateInstance() + { + IntPtr __retval = default; + try + { + global::WinRT.ExceptionHelpers.ThrowExceptionForHR(_obj.Vftbl.ActivateInstance_0(ThisPtr, out __retval)); + return MarshalInspectable.FromAbi(__retval); + } + finally + { + MarshalInspectable.DisposeAbi(__retval); + } + } + } +} + +namespace WinRT.Host +{ + internal class ActivationFactory : IActivationFactory + { + public ConstructorInfo Constructor { get; private set; } + + public ActivationFactory(ConstructorInfo constructor) => Constructor = constructor; + + public object ActivateInstance() => Constructor.Invoke(null); + } +} + +#endregion + +namespace WinRT +{ + public static class Module + { + public static unsafe IntPtr GetActivationFactory(String runtimeClassId) + { + if (runtimeClassId == "TestHost.ProbeByClass") + { + var type = Type.GetType(runtimeClassId); + if (type != null) + { + var ctor = type.GetConstructor(Type.EmptyTypes); + if (ctor != null) + { + var factory = new WinRT.Host.ActivationFactory(ctor); + return MarshalInspectable.FromManaged(factory); + } + } + } + return IntPtr.Zero; + } + } +} + +namespace TestHost +{ + public class ProbeByClass : IStringable + { + public override string ToString() + { + return new System.IO.FileInfo(Assembly.GetExecutingAssembly().Location).Name; + } + } +} diff --git a/Projections/TestHost.ProbeByClass/TestHost.ProbeByClass.csproj b/src/Projections/TestHost.ProbeByClass/TestHost.ProbeByClass.csproj similarity index 93% rename from Projections/TestHost.ProbeByClass/TestHost.ProbeByClass.csproj rename to src/Projections/TestHost.ProbeByClass/TestHost.ProbeByClass.csproj index cc1d91428..16f85c34a 100644 --- a/Projections/TestHost.ProbeByClass/TestHost.ProbeByClass.csproj +++ b/src/Projections/TestHost.ProbeByClass/TestHost.ProbeByClass.csproj @@ -6,7 +6,7 @@ - + diff --git a/Projections/WinUI/WinUI.csproj b/src/Projections/WinUI/WinUI.csproj similarity index 100% rename from Projections/WinUI/WinUI.csproj rename to src/Projections/WinUI/WinUI.csproj diff --git a/Projections/Windows/Windows.csproj b/src/Projections/Windows/Windows.csproj similarity index 97% rename from Projections/Windows/Windows.csproj rename to src/Projections/Windows/Windows.csproj index 8bf35a3da..f0e9d5265 100644 --- a/Projections/Windows/Windows.csproj +++ b/src/Projections/Windows/Windows.csproj @@ -1,35 +1,35 @@ - - - - netstandard2.0;net5.0 - x64;x86 - - - - - - - - - - --include Windows -# Exclude Windows.UI, Windows.UI.Text, Windows.UI.Xaml per Microsoft.Windows.SDK.WinUI.Contracts NuGet --include Windows.UI.Popups --exclude Windows.UI.Colors --exclude Windows.UI.IColors --exclude Windows.UI.ColorHelper --exclude Windows.UI.IColorHelper -#-exclude Windows.UI.Text (must include Windows.UI.Text to work around WinUI nuget issues) --exclude Windows.UI.Xaml --exclude Windows.ApplicationModel.Store.Preview -# Allow Windows.UI.Text, Windows.UI.Xaml types used in other namespaces --include Windows.UI.Text.FontStretch --include Windows.UI.Text.FontStyle --include Windows.UI.Text.FontWeight --include Windows.UI.Text.UnderlineType --include Windows.UI.Xaml.Media.Animation.ConditionallyIndependentlyAnimatableAttribute - - - - + + + + netstandard2.0;net5.0 + x64;x86 + + + + + + + + + + +-include Windows +# Exclude Windows.UI, Windows.UI.Text, Windows.UI.Xaml per Microsoft.Windows.SDK.WinUI.Contracts NuGet +-include Windows.UI.Popups +-exclude Windows.UI.Colors +-exclude Windows.UI.IColors +-exclude Windows.UI.ColorHelper +-exclude Windows.UI.IColorHelper +#-exclude Windows.UI.Text (must include Windows.UI.Text to work around WinUI nuget issues) +-exclude Windows.UI.Xaml +-exclude Windows.ApplicationModel.Store.Preview +# Allow Windows.UI.Text, Windows.UI.Xaml types used in other namespaces +-include Windows.UI.Text.FontStretch +-include Windows.UI.Text.FontStyle +-include Windows.UI.Text.FontWeight +-include Windows.UI.Text.UnderlineType +-include Windows.UI.Xaml.Media.Animation.ConditionallyIndependentlyAnimatableAttribute + + + + diff --git a/Samples/Net5ProjectionSample/ConsoleAppSample.sln b/src/Samples/Net5ProjectionSample/ConsoleAppSample.sln similarity index 100% rename from Samples/Net5ProjectionSample/ConsoleAppSample.sln rename to src/Samples/Net5ProjectionSample/ConsoleAppSample.sln diff --git a/Samples/Net5ProjectionSample/ConsoleAppSample/ConsoleAppSample.csproj b/src/Samples/Net5ProjectionSample/ConsoleAppSample/ConsoleAppSample.csproj similarity index 100% rename from Samples/Net5ProjectionSample/ConsoleAppSample/ConsoleAppSample.csproj rename to src/Samples/Net5ProjectionSample/ConsoleAppSample/ConsoleAppSample.csproj diff --git a/Samples/Net5ProjectionSample/ConsoleAppSample/Program.cs b/src/Samples/Net5ProjectionSample/ConsoleAppSample/Program.cs similarity index 100% rename from Samples/Net5ProjectionSample/ConsoleAppSample/Program.cs rename to src/Samples/Net5ProjectionSample/ConsoleAppSample/Program.cs diff --git a/Samples/Net5ProjectionSample/CppWinRTComponentProjectionSample.sln b/src/Samples/Net5ProjectionSample/CppWinRTComponentProjectionSample.sln similarity index 100% rename from Samples/Net5ProjectionSample/CppWinRTComponentProjectionSample.sln rename to src/Samples/Net5ProjectionSample/CppWinRTComponentProjectionSample.sln diff --git a/Samples/Net5ProjectionSample/Directory.Build.props b/src/Samples/Net5ProjectionSample/Directory.Build.props similarity index 100% rename from Samples/Net5ProjectionSample/Directory.Build.props rename to src/Samples/Net5ProjectionSample/Directory.Build.props diff --git a/Samples/Net5ProjectionSample/Directory.Build.targets b/src/Samples/Net5ProjectionSample/Directory.Build.targets similarity index 100% rename from Samples/Net5ProjectionSample/Directory.Build.targets rename to src/Samples/Net5ProjectionSample/Directory.Build.targets diff --git a/Samples/Net5ProjectionSample/README.md b/src/Samples/Net5ProjectionSample/README.md similarity index 100% rename from Samples/Net5ProjectionSample/README.md rename to src/Samples/Net5ProjectionSample/README.md diff --git a/Samples/Net5ProjectionSample/SimpleMathComponent/PropertySheet.props b/src/Samples/Net5ProjectionSample/SimpleMathComponent/PropertySheet.props similarity index 100% rename from Samples/Net5ProjectionSample/SimpleMathComponent/PropertySheet.props rename to src/Samples/Net5ProjectionSample/SimpleMathComponent/PropertySheet.props diff --git a/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMath.cpp b/src/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMath.cpp similarity index 100% rename from Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMath.cpp rename to src/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMath.cpp diff --git a/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMath.h b/src/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMath.h similarity index 100% rename from Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMath.h rename to src/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMath.h diff --git a/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMath.idl b/src/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMath.idl similarity index 100% rename from Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMath.idl rename to src/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMath.idl diff --git a/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMathComponent.def b/src/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMathComponent.def similarity index 100% rename from Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMathComponent.def rename to src/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMathComponent.def diff --git a/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMathComponent.vcxproj b/src/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMathComponent.vcxproj similarity index 100% rename from Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMathComponent.vcxproj rename to src/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMathComponent.vcxproj diff --git a/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMathComponent.vcxproj.filters b/src/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMathComponent.vcxproj.filters similarity index 100% rename from Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMathComponent.vcxproj.filters rename to src/Samples/Net5ProjectionSample/SimpleMathComponent/SimpleMathComponent.vcxproj.filters diff --git a/Samples/Net5ProjectionSample/SimpleMathComponent/packages.config b/src/Samples/Net5ProjectionSample/SimpleMathComponent/packages.config similarity index 100% rename from Samples/Net5ProjectionSample/SimpleMathComponent/packages.config rename to src/Samples/Net5ProjectionSample/SimpleMathComponent/packages.config diff --git a/Samples/Net5ProjectionSample/SimpleMathComponent/pch.cpp b/src/Samples/Net5ProjectionSample/SimpleMathComponent/pch.cpp similarity index 100% rename from Samples/Net5ProjectionSample/SimpleMathComponent/pch.cpp rename to src/Samples/Net5ProjectionSample/SimpleMathComponent/pch.cpp diff --git a/Samples/Net5ProjectionSample/SimpleMathComponent/pch.h b/src/Samples/Net5ProjectionSample/SimpleMathComponent/pch.h similarity index 100% rename from Samples/Net5ProjectionSample/SimpleMathComponent/pch.h rename to src/Samples/Net5ProjectionSample/SimpleMathComponent/pch.h diff --git a/Samples/Net5ProjectionSample/SimpleMathProjection/SimpleMathProjection.csproj b/src/Samples/Net5ProjectionSample/SimpleMathProjection/SimpleMathProjection.csproj similarity index 100% rename from Samples/Net5ProjectionSample/SimpleMathProjection/SimpleMathProjection.csproj rename to src/Samples/Net5ProjectionSample/SimpleMathProjection/SimpleMathProjection.csproj diff --git a/Samples/Net5ProjectionSample/SimpleMathProjection/nuget/SimpleMathProjection.nuspec b/src/Samples/Net5ProjectionSample/SimpleMathProjection/nuget/SimpleMathProjection.nuspec similarity index 100% rename from Samples/Net5ProjectionSample/SimpleMathProjection/nuget/SimpleMathProjection.nuspec rename to src/Samples/Net5ProjectionSample/SimpleMathProjection/nuget/SimpleMathProjection.nuspec diff --git a/WinUIDesktopSample/App.xaml b/src/Samples/WinUIDesktopSample/App.xaml similarity index 100% rename from WinUIDesktopSample/App.xaml rename to src/Samples/WinUIDesktopSample/App.xaml diff --git a/WinUIDesktopSample/App.xaml.cs b/src/Samples/WinUIDesktopSample/App.xaml.cs similarity index 99% rename from WinUIDesktopSample/App.xaml.cs rename to src/Samples/WinUIDesktopSample/App.xaml.cs index 5d6b505fb..da8260319 100644 --- a/WinUIDesktopSample/App.xaml.cs +++ b/src/Samples/WinUIDesktopSample/App.xaml.cs @@ -7,8 +7,8 @@ using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Media; -using Windows.Web.Http; - +using Windows.Web.Http; + namespace WinUIDesktopSample { /// @@ -42,7 +42,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs args) } private void Button_Click(object sender, RoutedEventArgs e) - { + { myWindow.Content = new MainPage(); } } diff --git a/WinUIDesktopSample/MainPage.xaml b/src/Samples/WinUIDesktopSample/MainPage.xaml similarity index 100% rename from WinUIDesktopSample/MainPage.xaml rename to src/Samples/WinUIDesktopSample/MainPage.xaml diff --git a/WinUIDesktopSample/MainPage.xaml.cs b/src/Samples/WinUIDesktopSample/MainPage.xaml.cs similarity index 100% rename from WinUIDesktopSample/MainPage.xaml.cs rename to src/Samples/WinUIDesktopSample/MainPage.xaml.cs diff --git a/WinUIDesktopSample/Net5_WinUI_Fixup.Targets b/src/Samples/WinUIDesktopSample/Net5_WinUI_Fixup.Targets similarity index 97% rename from WinUIDesktopSample/Net5_WinUI_Fixup.Targets rename to src/Samples/WinUIDesktopSample/Net5_WinUI_Fixup.Targets index 4366e8253..635c96d31 100644 --- a/WinUIDesktopSample/Net5_WinUI_Fixup.Targets +++ b/src/Samples/WinUIDesktopSample/Net5_WinUI_Fixup.Targets @@ -1,78 +1,78 @@ - - - - - Windows - 10.0.18362.0 - $(TargetPlatformMinVersion) - $([Microsoft.Build.Utilities.ToolLocationHelper]::GetPlatformSdkLocation("Windows", "10.0")) - $(WindowsSdkPath)\Platforms\UAP\$(TargetPlatformVersion)\ - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\AppxPackage\Microsoft.AppXPackage.Targets - - - - - - - - - - - - - - UAP - $(TargetPlatformMinVersion) - - - - - - - - - - - - - UAP - $(TargetPlatformMinVersion) - - - - - - - - - - - - - UAP - $(TargetPlatformMinVersion) - - - - - - - - - - - - - UAP - $(TargetPlatformMinVersion) - - - - - - - - - - - + + + + + Windows + 10.0.18362.0 + $(TargetPlatformMinVersion) + $([Microsoft.Build.Utilities.ToolLocationHelper]::GetPlatformSdkLocation("Windows", "10.0")) + $(WindowsSdkPath)\Platforms\UAP\$(TargetPlatformVersion)\ + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\AppxPackage\Microsoft.AppXPackage.Targets + + + + + + + + + + + + + + UAP + $(TargetPlatformMinVersion) + + + + + + + + + + + + + UAP + $(TargetPlatformMinVersion) + + + + + + + + + + + + + UAP + $(TargetPlatformMinVersion) + + + + + + + + + + + + + UAP + $(TargetPlatformMinVersion) + + + + + + + + + + + diff --git a/WinUIDesktopSample/Properties/launchSettings.json b/src/Samples/WinUIDesktopSample/Properties/launchSettings.json similarity index 100% rename from WinUIDesktopSample/Properties/launchSettings.json rename to src/Samples/WinUIDesktopSample/Properties/launchSettings.json diff --git a/WinUIDesktopSample/WeakReference.cs b/src/Samples/WinUIDesktopSample/WeakReference.cs similarity index 96% rename from WinUIDesktopSample/WeakReference.cs rename to src/Samples/WinUIDesktopSample/WeakReference.cs index 94329733c..b97ea9dd5 100644 --- a/WinUIDesktopSample/WeakReference.cs +++ b/src/Samples/WinUIDesktopSample/WeakReference.cs @@ -1,36 +1,36 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -// Wrapper around System.WeakReference until XAML removes its dependency on it. -namespace WinRT -{ - public sealed class WeakReference - where T : class - { - private System.WeakReference _managedWeakReference; - - public WeakReference(T target) - { - _managedWeakReference = new System.WeakReference(target); - } - - public void SetTarget(T target) - { - lock (_managedWeakReference) - { - _managedWeakReference.SetTarget(target); - } - } - - public bool TryGetTarget(out T target) - { - lock (_managedWeakReference) - { - return _managedWeakReference.TryGetTarget(out target); - } - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +// Wrapper around System.WeakReference until XAML removes its dependency on it. +namespace WinRT +{ + public sealed class WeakReference + where T : class + { + private System.WeakReference _managedWeakReference; + + public WeakReference(T target) + { + _managedWeakReference = new System.WeakReference(target); + } + + public void SetTarget(T target) + { + lock (_managedWeakReference) + { + _managedWeakReference.SetTarget(target); + } + } + + public bool TryGetTarget(out T target) + { + lock (_managedWeakReference) + { + return _managedWeakReference.TryGetTarget(out target); + } + } + } +} diff --git a/WinUIDesktopSample/WinUIDesktopSample.csproj b/src/Samples/WinUIDesktopSample/WinUIDesktopSample.csproj similarity index 93% rename from WinUIDesktopSample/WinUIDesktopSample.csproj rename to src/Samples/WinUIDesktopSample/WinUIDesktopSample.csproj index 7cdabc0fd..18f40a0b2 100644 --- a/WinUIDesktopSample/WinUIDesktopSample.csproj +++ b/src/Samples/WinUIDesktopSample/WinUIDesktopSample.csproj @@ -22,8 +22,8 @@ - - + +