Skip to content

Commit

Permalink
Produce custom winmd files. Still need to fix being able to mix XAML …
Browse files Browse the repository at this point in the history
…and custom winmd in the generated output
  • Loading branch information
asklar committed Mar 4, 2021
1 parent 4cb044d commit 6673226
Show file tree
Hide file tree
Showing 17 changed files with 471 additions and 8 deletions.
60 changes: 52 additions & 8 deletions codegen/Codegen/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.IO;
using System.Reflection;
using System.Diagnostics.CodeAnalysis;
using System;

namespace Codegen
{
Expand Down Expand Up @@ -72,26 +73,27 @@ public int GetHashCode([DisallowNull] MrTypeAndMemberBase obj)

class Program
{
const string Windows_winmd = @"C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.19041.0\Windows.winmd";
private void DumpTypes()
{
var context = new MrLoadContext(true);
context.FakeTypeRequired += (sender, e) =>
{
var ctx = sender as MrLoadContext;
if (e.AssemblyName == "Windows.Foundation.FoundationContract")
if (e.AssemblyName == "Windows.Foundation.FoundationContract" || e.AssemblyName == "Windows.Foundation.UniversalApiContract")
{
e.ReplacementType = ctx.GetTypeFromAssembly(e.TypeName, "Windows");
}
};
var windows_winmd = context.LoadAssemblyFromPath(@"C:\Program Files (x86)\Windows Kits\10\UnionMetadata\10.0.19041.0\Windows.winmd");//, "Windows.winmd");
// var assembly = context.LoadAssemblyFromPath(path); // @"C:\rnw\vnext\target\x86\Debug\Microsoft.ReactNative\Microsoft.ReactNative.winmd");
var windows_winmd = context.LoadAssemblyFromPath(Windows_winmd);
var winmd = winmdPath != null ? context.LoadAssemblyFromPath(winmdPath) : windows_winmd;
context.FinishLoading();
var types = windows_winmd.GetAllTypes().Skip(1);
var types = winmd.GetAllTypes().Skip(1);
Util.LoadContext = context;
var fe = types.Where(type => Util.DerivesFrom(type, "Windows.UI.Xaml.UIElement"));
var assemblyLocation = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var generatedDirPath = Path.GetFullPath(Path.Join(assemblyLocation, @"..\..\..\..", @"..\package\windows\ReactNativeXaml\Codegen"));
var packageSrcPath = Path.GetFullPath(Path.Join(assemblyLocation, @"..\..\..\..", @"..\package\src"));
var generatedDirPath = Path.GetFullPath(cppOutPath ?? Path.Join(assemblyLocation, @"..\..\..\..", @"..\package\windows\ReactNativeXaml\Codegen"));
var packageSrcPath = Path.GetFullPath(tsOutPath ?? Path.Join(assemblyLocation, @"..\..\..\..", @"..\package\src"));

var creatableTypes = fe.Where(x => Util.HasCtor(x)).ToList();
creatableTypes.Sort((a, b) => a.GetName().CompareTo(b.GetName()));
Expand All @@ -107,7 +109,8 @@ private void DumpTypes()
var events = new List<MrEvent>();
foreach (var type in fe)
{
var propsToAdd = type.GetProperties().Where(p => Util.ShouldEmitPropertyMetadata(p));
var props = type.GetProperties();
var propsToAdd = props.Where(p => Util.ShouldEmitPropertyMetadata(p));
properties.AddRange(propsToAdd);

var eventsToAdd = type.GetEvents().Where(e => Util.ShouldEmitEventMetadata(e));
Expand All @@ -131,9 +134,50 @@ private void DumpTypes()
File.WriteAllText(Path.Join(generatedDirPath, "TypeEvents.g.h"), eventsGen);
}

private string winmdPath { get; set; }
private string cppOutPath { get; set; }
private string tsOutPath { get; set; }
class OptionDef
{
public int NumberOfParams { get; set; }
public Action<Program, string> Action { get; set; }
}

static void PrintHelp()
{
foreach (var k in optionDefs.Keys)
{
Console.WriteLine(k);
}
}

static Dictionary<string, OptionDef> optionDefs = new Dictionary<string, OptionDef>() {
{ "-help", new OptionDef (){ NumberOfParams = 1, Action = (_, _2) => { PrintHelp(); } } },
{ "-winmd", new OptionDef (){ NumberOfParams = 2, Action = (p, v) => { p.winmdPath = v; } } },
{ "-cppout", new OptionDef (){ NumberOfParams = 2, Action = (p, v) => { p.cppOutPath = v; } } },
{ "-tsout", new OptionDef (){ NumberOfParams = 2, Action = (p, v) => { p.tsOutPath = v; } } },
};

static void Main(string[] args)
{
new Program().DumpTypes();
var p = new Program();
for (int i = 0; i < args.Length;)
{
if (optionDefs.ContainsKey(args[i]))
{
var def = optionDefs[args[i]];
string v = null;
if (def.NumberOfParams == 2 && i < args.Length - 1) {
v = args[i + 1];
}
i += def.NumberOfParams;
def.Action(p, v);
} else
{
throw new ArgumentException($"Unkown option {args[i]}");
}
}
p.DumpTypes();
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions codegen/Codegen/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"profiles": {
"Codegen": {
"commandName": "Project",
"commandLineArgs": "-winmd \"C:\\Users\\asklar\\source\\repos\\react-native-xaml\\example\\windows\\RuntimeComponent1\\Debug\\Merged\\RuntimeComponent1.winmd\" -cppout C:\\temp\\1 -tsout C:\\temp\\1"
}
}
}
47 changes: 47 additions & 0 deletions example/windows/RuntimeComponent1/BlankUserControl.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "pch.h"
#include "BlankUserControl.h"
#if __has_include("BlankUserControl.g.cpp")
#include "BlankUserControl.g.cpp"
#endif

using namespace winrt;
using namespace Windows::UI::Xaml;

namespace winrt::RuntimeComponent1::implementation
{
BlankUserControl::BlankUserControl()
{
InitializeComponent();
}

int32_t BlankUserControl::MyProperty()
{
throw hresult_not_implemented();
}

void BlankUserControl::MyProperty(int32_t /* value */)
{
throw hresult_not_implemented();
}

void BlankUserControl::ClickHandler(IInspectable const&, RoutedEventArgs const&)
{
Button().Content(box_value(L"Clicked"));
}

winrt::Windows::UI::Xaml::DependencyProperty BlankUserControl::MyPropertyProperty() {
if (m_myPropertyProperty == nullptr) {
auto typeMetadata = PropertyMetadata::Create(winrt::box_value(0), [](const DependencyObject& sender, const DependencyPropertyChangedEventArgs& args) {
if (auto control = sender.try_as<winrt::RuntimeComponent1::BlankUserControl>()) {
auto v = winrt::unbox_value<int32_t>(args.NewValue());
control.MyProperty(v);
}
});
m_myPropertyProperty = winrt::Windows::UI::Xaml::DependencyProperty::Register(L"MyProperty", winrt::xaml_typename<int32_t>(), winrt::xaml_typename<winrt::RuntimeComponent1::BlankUserControl>(), typeMetadata);
}
return m_myPropertyProperty;
}
winrt::Windows::UI::Xaml::DependencyProperty BlankUserControl::m_myPropertyProperty = nullptr;

}

32 changes: 32 additions & 0 deletions example/windows/RuntimeComponent1/BlankUserControl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#pragma once

#include "winrt/Windows.UI.Xaml.h"
#include "winrt/Windows.UI.Xaml.Markup.h"
#include "winrt/Windows.UI.Xaml.Interop.h"
#include "winrt/Windows.UI.Xaml.Controls.Primitives.h"
#include "BlankUserControl.g.h"

namespace winrt::RuntimeComponent1::implementation
{
struct BlankUserControl : BlankUserControlT<BlankUserControl>
{
BlankUserControl();

int32_t MyProperty();
void MyProperty(int32_t value);

void ClickHandler(Windows::Foundation::IInspectable const& sender, Windows::UI::Xaml::RoutedEventArgs const& args);

static winrt::Windows::UI::Xaml::DependencyProperty MyPropertyProperty();
private:
static winrt::Windows::UI::Xaml::DependencyProperty m_myPropertyProperty;

};
}

namespace winrt::RuntimeComponent1::factory_implementation
{
struct BlankUserControl : BlankUserControlT<BlankUserControl, implementation::BlankUserControl>
{
};
}
11 changes: 11 additions & 0 deletions example/windows/RuntimeComponent1/BlankUserControl.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace RuntimeComponent1
{
[default_interface]
runtimeclass BlankUserControl : Windows.UI.Xaml.Controls.UserControl
{
BlankUserControl();
Int32 MyProperty;

static Windows.UI.Xaml.DependencyProperty MyPropertyProperty{ get; };
}
}
13 changes: 13 additions & 0 deletions example/windows/RuntimeComponent1/BlankUserControl.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<UserControl
x:Class="RuntimeComponent1.BlankUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:RuntimeComponent1"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="Button" Click="ClickHandler">Click Me</Button>
</StackPanel>
</UserControl>
16 changes: 16 additions & 0 deletions example/windows/RuntimeComponent1/Class.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#include "pch.h"
#include "Class.h"
#include "Class.g.cpp"

namespace winrt::RuntimeComponent1::implementation
{
int32_t Class::MyProperty()
{
throw hresult_not_implemented();
}

void Class::MyProperty(int32_t /* value */)
{
throw hresult_not_implemented();
}
}
21 changes: 21 additions & 0 deletions example/windows/RuntimeComponent1/Class.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include "Class.g.h"

namespace winrt::RuntimeComponent1::implementation
{
struct Class : ClassT<Class>
{
Class() = default;

int32_t MyProperty();
void MyProperty(int32_t value);
};
}

namespace winrt::RuntimeComponent1::factory_implementation
{
struct Class : ClassT<Class, implementation::Class>
{
};
}
9 changes: 9 additions & 0 deletions example/windows/RuntimeComponent1/Class.idl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace RuntimeComponent1
{
[default_interface]
runtimeclass Class
{
Class();
Int32 MyProperty;
}
}
16 changes: 16 additions & 0 deletions example/windows/RuntimeComponent1/PropertySheet.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<!--
To customize common C++/WinRT project properties:
* right-click the project node
* expand the Common Properties item
* select the C++/WinRT property page
For more advanced scenarios, and complete documentation, please see:
https://github.com/Microsoft/cppwinrt/tree/master/nuget
-->
<PropertyGroup />
<ItemDefinitionGroup />
</Project>
3 changes: 3 additions & 0 deletions example/windows/RuntimeComponent1/RuntimeComponent1.def
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
EXPORTS
DllCanUnloadNow = WINRT_CanUnloadNow PRIVATE
DllGetActivationFactory = WINRT_GetActivationFactory PRIVATE
Loading

0 comments on commit 6673226

Please sign in to comment.