Browse Source

Merge branch 'master' into feature/keyboard-focus-within

pull/4974/head
Dan Walmsley 5 years ago
committed by GitHub
parent
commit
23d19e66ba
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      .editorconfig
  2. 53
      Avalonia.sln
  3. 13
      azure-pipelines.yml
  4. 4
      build.ps1
  5. 2
      build.sh
  6. 1
      build/CoreLibraries.props
  7. 1
      native/Avalonia.Native/inc/.gitignore
  8. 516
      native/Avalonia.Native/inc/avalonia-native.h
  9. 2
      native/Avalonia.Native/src/OSX/clipboard.mm
  10. 4
      native/Avalonia.Native/src/OSX/main.mm
  11. 6
      native/Avalonia.Native/src/OSX/menu.h
  12. 6
      native/Avalonia.Native/src/OSX/menu.mm
  13. 2
      native/Avalonia.Native/src/OSX/window.mm
  14. 16
      nukebuild/Build.cs
  15. 2
      nukebuild/BuildParameters.cs
  16. 14
      nukebuild/MicroComGen.cs
  17. 4
      nukebuild/_build.csproj
  18. 7
      packages/Avalonia/Avalonia.csproj
  19. 4
      packages/Avalonia/AvaloniaBuildTasks.targets
  20. 130
      src/Avalonia.Build.Tasks/ComInteropHelper.cs
  21. 7
      src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs
  22. 3
      src/Avalonia.Build.Tasks/Program.cs
  23. 53
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  24. 84
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/HtmlTransport.cs
  25. 41
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/FramePresenter.tsx
  26. 11
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/InputEventMessageBase.ts
  27. 9
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/InputModifiers.ts
  28. 6
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/MouseButton.ts
  29. 39
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/MouseEventHelpers.ts
  30. 13
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/PointerEventMessageBase.ts
  31. 12
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/PointerMovedEventMessage.ts
  32. 17
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/PointerPressedEventMessage.ts
  33. 17
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/PointerReleasedEventMessage.ts
  34. 17
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/ScrollEventMessage.ts
  35. 6
      src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/PreviewerServerConnection.ts
  36. 17
      src/Avalonia.MicroCom/Avalonia.MicroCom.csproj
  37. 9
      src/Avalonia.MicroCom/IMicroComExceptionCallback.cs
  38. 9
      src/Avalonia.MicroCom/IMicroComShadowContainer.cs
  39. 8
      src/Avalonia.MicroCom/IUnknown.cs
  40. 17
      src/Avalonia.MicroCom/LocalInterop.cs
  41. 110
      src/Avalonia.MicroCom/MicroComProxyBase.cs
  42. 98
      src/Avalonia.MicroCom/MicroComRuntime.cs
  43. 171
      src/Avalonia.MicroCom/MicroComShadow.cs
  44. 42
      src/Avalonia.MicroCom/MicroComVtblBase.cs
  45. 1
      src/Avalonia.Native/.gitignore
  46. 40
      src/Avalonia.Native/Avalonia.Native.csproj
  47. 7
      src/Avalonia.Native/AvaloniaNativeMenuExporter.cs
  48. 12
      src/Avalonia.Native/AvaloniaNativePlatform.cs
  49. 4
      src/Avalonia.Native/AvaloniaNativePlatformOpenGlInterface.cs
  50. 22
      src/Avalonia.Native/AvnString.cs
  51. 78
      src/Avalonia.Native/CallbackBase.cs
  52. 16
      src/Avalonia.Native/ClipboardImpl.cs
  53. 7
      src/Avalonia.Native/DeferredFramebuffer.cs
  54. 628
      src/Avalonia.Native/Generated/Enumerations.cs
  55. 5
      src/Avalonia.Native/Generated/Functions.cs
  56. 3092
      src/Avalonia.Native/Generated/Interfaces.cs
  57. 202
      src/Avalonia.Native/Generated/LocalInterop.cs
  58. 246
      src/Avalonia.Native/Generated/Structures.cs
  59. 2
      src/Avalonia.Native/Helpers.cs
  60. 45
      src/Avalonia.Native/IAvnMenu.cs
  61. 41
      src/Avalonia.Native/IAvnMenuItem.cs
  62. 4
      src/Avalonia.Native/NativeControlHostImpl.cs
  63. 5
      src/Avalonia.Native/PlatformThreadingInterface.cs
  64. 2
      src/Avalonia.Native/ScreenImpl.cs
  65. 8
      src/Avalonia.Native/SystemDialogs.cs
  66. 28
      src/Avalonia.Native/WindowImpl.cs
  67. 18
      src/Avalonia.Native/WindowImplBase.cs
  68. 522
      src/Avalonia.Native/avn.idl
  69. 23
      src/Avalonia.ReactiveUI/ReactiveUserControl.cs
  70. 31
      src/Avalonia.ReactiveUI/ReactiveWindow.cs
  71. 55
      src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs
  72. 241
      src/tools/MicroComGenerator/Ast.cs
  73. 231
      src/tools/MicroComGenerator/AstParser.cs
  74. 459
      src/tools/MicroComGenerator/CSharpGen.InterfaceGen.cs
  75. 110
      src/tools/MicroComGenerator/CSharpGen.Utils.cs
  76. 133
      src/tools/MicroComGenerator/CSharpGen.cs
  77. 116
      src/tools/MicroComGenerator/CppGen.cs
  78. 97
      src/tools/MicroComGenerator/Extensions.cs
  79. 10
      src/tools/MicroComGenerator/MicroComGenerator.csproj
  80. 27
      src/tools/MicroComGenerator/ParseException.cs
  81. 44
      src/tools/MicroComGenerator/Program.cs
  82. 417
      src/tools/MicroComGenerator/TokenParser.cs
  83. 61
      tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs
  84. 3
      tests/Avalonia.DesignerSupport.Tests/Remote/HtmlTransport/webapp/.gitignore
  85. 94
      tests/Avalonia.DesignerSupport.Tests/Remote/HtmlTransport/webapp/Models/InputEventTests.ts
  86. 2414
      tests/Avalonia.DesignerSupport.Tests/Remote/HtmlTransport/webapp/package-lock.json
  87. 26
      tests/Avalonia.DesignerSupport.Tests/Remote/HtmlTransport/webapp/package.json
  88. 12
      tests/Avalonia.DesignerSupport.Tests/Remote/HtmlTransport/webapp/tsconfig.json
  89. 71
      tests/Avalonia.ReactiveUI.UnitTests/ReactiveUserControlTest.cs

3
.editorconfig

@ -156,6 +156,9 @@ indent_size = 2
[*.{props,targets,config,nuspec}]
indent_size = 2
[*.json]
indent_size = 2
# Shell scripts
[*.sh]
end_of_line = lf

53
Avalonia.sln

@ -226,6 +226,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI.Events"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sandbox", "samples\Sandbox\Sandbox.csproj", "{11BE52AF-E2DD-4CF0-B19A-05285ACAF571}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MicroComGenerator", "src\tools\MicroComGenerator\MicroComGenerator.csproj", "{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.MicroCom", "src\Avalonia.MicroCom\Avalonia.MicroCom.csproj", "{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
@ -2064,6 +2068,54 @@ Global
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|iPhone.Build.0 = Release|Any CPU
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.AppStore|iPhone.Build.0 = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Debug|iPhone.Build.0 = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Release|Any CPU.Build.0 = Release|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Release|iPhone.ActiveCfg = Release|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Release|iPhone.Build.0 = Release|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.AppStore|iPhone.Build.0 = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Debug|iPhone.Build.0 = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|Any CPU.Build.0 = Release|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhone.ActiveCfg = Release|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhone.Build.0 = Release|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -2123,6 +2175,7 @@ Global
{3C84E04B-36CF-4D0D-B965-C26DD649D1F3} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
{909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

13
azure-pipelines.yml

@ -3,13 +3,6 @@ jobs:
pool:
vmImage: 'ubuntu-16.04'
steps:
- task: CmdLine@2
displayName: 'Install CastXML'
inputs:
script: |
sudo apt-get update
sudo apt-get install castxml
- task: CmdLine@2
displayName: 'Install Nuke'
inputs:
@ -48,6 +41,12 @@ jobs:
curl -o ./mono.pkg https://download.mono-project.com/archive/5.18.0/macos-10-universal/MonoFramework-MDK-5.18.0.225.macos10.xamarin.universal.pkg
sudo installer -verbose -pkg ./mono.pkg -target /
- task: CmdLine@2
displayName: 'Generate avalonia-native'
inputs:
script: |
cd src/tools/MicroComGenerator; dotnet run -i ../../Avalonia.Native/avn.idl --cpp ../../../native/Avalonia.Native/inc/avalonia-native.h
- task: Xcode@5
inputs:
actions: 'build'

4
build.ps1

@ -43,7 +43,7 @@ if (Test-Path $DotNetGlobalFile) {
}
# If dotnet is installed locally, and expected version is not set or installation matches the expected version
if ((Get-Command "dotnet" -ErrorAction SilentlyContinue) -ne $null -and `
if ($null -ne (Get-Command "dotnet" -ErrorAction SilentlyContinue) -and `
(!(Test-Path variable:DotNetVersion) -or $(& dotnet --version) -eq $DotNetVersion)) {
$env:DOTNET_EXE = (Get-Command "dotnet").Path
}
@ -53,7 +53,7 @@ else {
# Download install script
$DotNetInstallFile = "$TempDirectory\dotnet-install.ps1"
md -force $TempDirectory > $null
mkdir -force $TempDirectory > $null
(New-Object System.Net.WebClient).DownloadFile($DotNetInstallUrl, $DotNetInstallFile)
# Install by channel or version

2
build.sh

@ -47,7 +47,7 @@ if [ -f "$DOTNET_GLOBAL_FILE" ]; then
fi
# If dotnet is installed locally, and expected version is not set or installation matches the expected version
if [[ -x "$(command -v dotnet)" && (-z ${DOTNET_VERSION+x} || $(dotnet --version) == "$DOTNET_VERSION") ]]; then
if [[ -x "$(command -v dotnet)" && (-z ${DOTNET_VERSION+x} || $(dotnet --version) == "$DOTNET_VERSION") || "$SKIP_DOTNET_DOWNLOAD" == "1" ]]; then
export DOTNET_EXE="$(command -v dotnet)"
else
DOTNET_DIRECTORY="$TEMP_DIRECTORY/dotnet-unix"

1
build/CoreLibraries.props

@ -15,6 +15,7 @@
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.Dialogs/Avalonia.Dialogs.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup/Avalonia.Markup.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.MicroCom/Avalonia.MicroCom.csproj" />
<ProjectReference Include="$(MSBuildThisFileDirectory)/../src/Avalonia.DesktopRuntime/Avalonia.DesktopRuntime.csproj" Condition="'$(TargetFramework)' != 'netstandard2.0'" />
</ItemGroup>
</Project>

1
native/Avalonia.Native/inc/.gitignore

@ -0,0 +1 @@
avalonia-native.h

516
native/Avalonia.Native/inc/avalonia-native.h

@ -1,516 +0,0 @@
#include "com.h"
#include "key.h"
#include "stddef.h"
#define AVNCOM(name, id) COMINTERFACE(name, 2e2cda0a, 9ae5, 4f1b, 8e, 20, 08, 1a, 04, 27, 9f, id)
struct IAvnWindowEvents;
struct IAvnWindow;
struct IAvnPopup;
struct IAvnMacOptions;
struct IAvnPlatformThreadingInterface;
struct IAvnSystemDialogEvents;
struct IAvnSystemDialogs;
struct IAvnScreens;
struct IAvnClipboard;
struct IAvnCursor;
struct IAvnCursorFactory;
struct IAvnGlFeature;
struct IAvnGlContext;
struct IAvnGlDisplay;
struct IAvnGlSurfaceRenderTarget;
struct IAvnGlSurfaceRenderingSession;
struct IAvnMenu;
struct IAvnMenuItem;
struct IAvnStringArray;
struct IAvnDndResultCallback;
struct IAvnGCHandleDeallocatorCallback;
struct IAvnMenuEvents;
struct IAvnNativeControlHost;
struct IAvnNativeControlHostTopLevelAttachment;
enum SystemDecorations {
SystemDecorationsNone = 0,
SystemDecorationsBorderOnly = 1,
SystemDecorationsFull = 2,
};
struct AvnSize
{
double Width, Height;
};
struct AvnPixelSize
{
int Width, Height;
};
struct AvnRect
{
double X, Y, Width, Height;
};
struct AvnVector
{
double X, Y;
};
struct AvnPoint
{
double X, Y;
};
struct AvnScreen
{
AvnRect Bounds;
AvnRect WorkingArea;
float PixelDensity;
bool Primary;
};
enum AvnPixelFormat
{
kAvnRgb565,
kAvnRgba8888,
kAvnBgra8888
};
struct AvnFramebuffer
{
void* Data;
int Width;
int Height;
int Stride;
AvnVector Dpi;
AvnPixelFormat PixelFormat;
};
struct AvnColor
{
unsigned char Alpha;
unsigned char Red;
unsigned char Green;
unsigned char Blue;
};
enum AvnRawMouseEventType
{
LeaveWindow,
LeftButtonDown,
LeftButtonUp,
RightButtonDown,
RightButtonUp,
MiddleButtonDown,
MiddleButtonUp,
XButton1Down,
XButton1Up,
XButton2Down,
XButton2Up,
Move,
Wheel,
NonClientLeftButtonDown,
TouchBegin,
TouchUpdate,
TouchEnd,
TouchCancel
};
enum AvnRawKeyEventType
{
KeyDown,
KeyUp
};
enum AvnInputModifiers
{
AvnInputModifiersNone = 0,
Alt = 1,
Control = 2,
Shift = 4,
Windows = 8,
LeftMouseButton = 16,
RightMouseButton = 32,
MiddleMouseButton = 64,
XButton1MouseButton = 128,
XButton2MouseButton = 256
};
enum class AvnDragDropEffects
{
None = 0,
Copy = 1,
Move = 2,
Link = 4,
};
enum class AvnDragEventType
{
Enter,
Over,
Leave,
Drop
};
enum AvnWindowState
{
Normal,
Minimized,
Maximized,
FullScreen,
};
enum AvnStandardCursorType
{
CursorArrow,
CursorIbeam,
CursorWait,
CursorCross,
CursorUpArrow,
CursorSizeWestEast,
CursorSizeNorthSouth,
CursorSizeAll,
CursorNo,
CursorHand,
CursorAppStarting,
CursorHelp,
CursorTopSide,
CursorBottomSize,
CursorLeftSide,
CursorRightSide,
CursorTopLeftCorner,
CursorTopRightCorner,
CursorBottomLeftCorner,
CursorBottomRightCorner,
CursorDragMove,
CursorDragCopy,
CursorDragLink,
CursorNone
};
enum AvnWindowEdge
{
WindowEdgeNorthWest,
WindowEdgeNorth,
WindowEdgeNorthEast,
WindowEdgeWest,
WindowEdgeEast,
WindowEdgeSouthWest,
WindowEdgeSouth,
WindowEdgeSouthEast
};
enum AvnMenuItemToggleType
{
None,
CheckMark,
Radio
};
enum AvnExtendClientAreaChromeHints
{
AvnNoChrome = 0,
AvnSystemChrome = 0x01,
AvnPreferSystemChrome = 0x02,
AvnOSXThickTitleBar = 0x08,
AvnDefaultChrome = AvnSystemChrome,
};
AVNCOM(IAvaloniaNativeFactory, 01) : IUnknown
{
public:
virtual HRESULT Initialize(IAvnGCHandleDeallocatorCallback* deallocator) = 0;
virtual IAvnMacOptions* GetMacOptions() = 0;
virtual HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnGlContext* gl, IAvnWindow** ppv) = 0;
virtual HRESULT CreatePopup (IAvnWindowEvents* cb, IAvnGlContext* gl, IAvnPopup** ppv) = 0;
virtual HRESULT CreatePlatformThreadingInterface(IAvnPlatformThreadingInterface** ppv) = 0;
virtual HRESULT CreateSystemDialogs (IAvnSystemDialogs** ppv) = 0;
virtual HRESULT CreateScreens (IAvnScreens** ppv) = 0;
virtual HRESULT CreateClipboard(IAvnClipboard** ppv) = 0;
virtual HRESULT CreateDndClipboard(IAvnClipboard** ppv) = 0;
virtual HRESULT CreateCursorFactory(IAvnCursorFactory** ppv) = 0;
virtual HRESULT ObtainGlDisplay(IAvnGlDisplay** ppv) = 0;
virtual HRESULT SetAppMenu(IAvnMenu* menu) = 0;
virtual HRESULT CreateMenu (IAvnMenuEvents* cb, IAvnMenu** ppv) = 0;
virtual HRESULT CreateMenuItem (IAvnMenuItem** ppv) = 0;
virtual HRESULT CreateMenuItemSeperator (IAvnMenuItem** ppv) = 0;
};
AVNCOM(IAvnString, 17) : IUnknown
{
virtual HRESULT Pointer(void**retOut) = 0;
virtual HRESULT Length(int*ret) = 0;
};
AVNCOM(IAvnWindowBase, 02) : IUnknown
{
virtual HRESULT Show() = 0;
virtual HRESULT Hide () = 0;
virtual HRESULT Close() = 0;
virtual HRESULT Activate () = 0;
virtual HRESULT GetClientSize(AvnSize*ret) = 0;
virtual HRESULT GetScaling(double*ret)=0;
virtual HRESULT SetMinMaxSize(AvnSize minSize, AvnSize maxSize) = 0;
virtual HRESULT Resize(double width, double height) = 0;
virtual HRESULT Invalidate (AvnRect rect) = 0;
virtual HRESULT BeginMoveDrag () = 0;
virtual HRESULT BeginResizeDrag (AvnWindowEdge edge) = 0;
virtual HRESULT GetPosition (AvnPoint*ret) = 0;
virtual HRESULT SetPosition (AvnPoint point) = 0;
virtual HRESULT PointToClient (AvnPoint point, AvnPoint*ret) = 0;
virtual HRESULT PointToScreen (AvnPoint point, AvnPoint*ret) = 0;
virtual HRESULT ThreadSafeSetSwRenderedFrame(AvnFramebuffer* fb, IUnknown* dispose) = 0;
virtual HRESULT SetTopMost (bool value) = 0;
virtual HRESULT SetCursor(IAvnCursor* cursor) = 0;
virtual HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget** ret) = 0;
virtual HRESULT SetMainMenu(IAvnMenu* menu) = 0;
virtual HRESULT ObtainNSWindowHandle(void** retOut) = 0;
virtual HRESULT ObtainNSWindowHandleRetained(void** retOut) = 0;
virtual HRESULT ObtainNSViewHandle(void** retOut) = 0;
virtual HRESULT ObtainNSViewHandleRetained(void** retOut) = 0;
virtual HRESULT CreateNativeControlHost(IAvnNativeControlHost** retOut) = 0;
virtual HRESULT BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point,
IAvnClipboard* clipboard, IAvnDndResultCallback* cb, void* sourceHandle) = 0;
virtual HRESULT SetBlurEnabled (bool enable) = 0;
};
AVNCOM(IAvnPopup, 03) : virtual IAvnWindowBase
{
};
AVNCOM(IAvnWindow, 04) : virtual IAvnWindowBase
{
virtual HRESULT SetEnabled (bool enable) = 0;
virtual HRESULT SetParent (IAvnWindow* parent) = 0;
virtual HRESULT SetCanResize(bool value) = 0;
virtual HRESULT SetDecorations(SystemDecorations value) = 0;
virtual HRESULT SetTitle (void* utf8Title) = 0;
virtual HRESULT SetTitleBarColor (AvnColor color) = 0;
virtual HRESULT SetWindowState(AvnWindowState state) = 0;
virtual HRESULT GetWindowState(AvnWindowState*ret) = 0;
virtual HRESULT TakeFocusFromChildren() = 0;
virtual HRESULT SetExtendClientArea (bool enable) = 0;
virtual HRESULT SetExtendClientAreaHints (AvnExtendClientAreaChromeHints hints) = 0;
virtual HRESULT GetExtendTitleBarHeight (double*ret) = 0;
virtual HRESULT SetExtendTitleBarHeight (double value) = 0;
};
AVNCOM(IAvnWindowBaseEvents, 05) : IUnknown
{
virtual HRESULT Paint() = 0;
virtual void Closed() = 0;
virtual void Activated() = 0;
virtual void Deactivated() = 0;
virtual void Resized(const AvnSize& size) = 0;
virtual void PositionChanged (AvnPoint position) = 0;
virtual void RawMouseEvent (AvnRawMouseEventType type,
unsigned int timeStamp,
AvnInputModifiers modifiers,
AvnPoint point,
AvnVector delta) = 0;
virtual bool RawKeyEvent (AvnRawKeyEventType type, unsigned int timeStamp, AvnInputModifiers modifiers, unsigned int key) = 0;
virtual bool RawTextInputEvent (unsigned int timeStamp, const char* text) = 0;
virtual void ScalingChanged(double scaling) = 0;
virtual void RunRenderPriorityJobs() = 0;
virtual void LostFocus() = 0;
virtual AvnDragDropEffects DragEvent(AvnDragEventType type, AvnPoint position,
AvnInputModifiers modifiers, AvnDragDropEffects effects,
IAvnClipboard* clipboard, void* dataObjectHandle) = 0;
};
AVNCOM(IAvnWindowEvents, 06) : IAvnWindowBaseEvents
{
/**
* Closing Event
* Called when the user presses the OS window close button.
* return true to allow the close, return false to prevent close.
*/
virtual bool Closing () = 0;
virtual void WindowStateChanged (AvnWindowState state) = 0;
virtual void GotInputWhenDisabled () = 0;
};
AVNCOM(IAvnMacOptions, 07) : IUnknown
{
virtual HRESULT SetShowInDock(int show) = 0;
virtual HRESULT SetApplicationTitle (void* utf8string) = 0;
};
AVNCOM(IAvnActionCallback, 08) : IUnknown
{
virtual void Run() = 0;
};
AVNCOM(IAvnSignaledCallback, 09) : IUnknown
{
virtual void Signaled(int priority, bool priorityContainsMeaningfulValue) = 0;
};
AVNCOM(IAvnLoopCancellation, 0a) : IUnknown
{
virtual void Cancel() = 0;
};
AVNCOM(IAvnPlatformThreadingInterface, 0b) : IUnknown
{
virtual bool GetCurrentThreadIsLoopThread() = 0;
virtual void SetSignaledCallback(IAvnSignaledCallback* cb) = 0;
virtual IAvnLoopCancellation* CreateLoopCancellation() = 0;
virtual HRESULT RunLoop(IAvnLoopCancellation* cancel) = 0;
// Can't pass int* to sharpgentools for some reason
virtual void Signal(int priority) = 0;
virtual IUnknown* StartTimer(int priority, int ms, IAvnActionCallback* callback) = 0;
};
AVNCOM(IAvnSystemDialogEvents, 0c) : IUnknown
{
virtual void OnCompleted (int numResults, void* ptrFirstResult) = 0;
};
AVNCOM(IAvnSystemDialogs, 0d) : IUnknown
{
virtual void SelectFolderDialog (IAvnWindow* parentWindowHandle,
IAvnSystemDialogEvents* events,
const char* title,
const char* initialPath) = 0;
virtual void OpenFileDialog (IAvnWindow* parentWindowHandle,
IAvnSystemDialogEvents* events,
bool allowMultiple,
const char* title,
const char* initialDirectory,
const char* initialFile,
const char* filters) = 0;
virtual void SaveFileDialog (IAvnWindow* parentWindowHandle,
IAvnSystemDialogEvents* events,
const char* title,
const char* initialDirectory,
const char* initialFile,
const char* filters) = 0;
};
AVNCOM(IAvnScreens, 0e) : IUnknown
{
virtual HRESULT GetScreenCount (int* ret) = 0;
virtual HRESULT GetScreen (int index, AvnScreen* ret) = 0;
};
AVNCOM(IAvnClipboard, 0f) : IUnknown
{
virtual HRESULT GetText (char* type, IAvnString**ppv) = 0;
virtual HRESULT SetText (char* type, void* utf8Text) = 0;
virtual HRESULT ObtainFormats(IAvnStringArray**ppv) = 0;
virtual HRESULT GetStrings(char* type, IAvnStringArray**ppv) = 0;
virtual HRESULT SetBytes(char* type, void* utf8Text, int len) = 0;
virtual HRESULT GetBytes(char* type, IAvnString**ppv) = 0;
virtual HRESULT Clear() = 0;
};
AVNCOM(IAvnCursor, 10) : IUnknown
{
};
AVNCOM(IAvnCursorFactory, 11) : IUnknown
{
virtual HRESULT GetCursor (AvnStandardCursorType cursorType, IAvnCursor** retOut) = 0;
};
AVNCOM(IAvnGlDisplay, 13) : IUnknown
{
virtual HRESULT CreateContext(IAvnGlContext* share, IAvnGlContext**ppv) = 0;
virtual void LegacyClearCurrentContext() = 0;
virtual HRESULT WrapContext(void* native, IAvnGlContext**ppv) = 0;
virtual void* GetProcAddress(char* proc) = 0;
};
AVNCOM(IAvnGlContext, 14) : IUnknown
{
virtual HRESULT MakeCurrent(IUnknown** ppv) = 0;
virtual HRESULT LegacyMakeCurrent() = 0;
virtual int GetSampleCount() = 0;
virtual int GetStencilSize() = 0;
virtual void* GetNativeHandle() = 0;
};
AVNCOM(IAvnGlSurfaceRenderTarget, 15) : IUnknown
{
virtual HRESULT BeginDrawing(IAvnGlSurfaceRenderingSession** ret) = 0;
};
AVNCOM(IAvnGlSurfaceRenderingSession, 16) : IUnknown
{
virtual HRESULT GetPixelSize(AvnPixelSize* ret) = 0;
virtual HRESULT GetScaling(double* ret) = 0;
};
AVNCOM(IAvnMenu, 17) : IUnknown
{
virtual HRESULT InsertItem (int index, IAvnMenuItem* item) = 0;
virtual HRESULT RemoveItem (IAvnMenuItem* item) = 0;
virtual HRESULT SetTitle (void* utf8String) = 0;
virtual HRESULT Clear () = 0;
};
AVNCOM(IAvnPredicateCallback, 18) : IUnknown
{
virtual bool Evaluate() = 0;
};
AVNCOM(IAvnMenuItem, 19) : IUnknown
{
virtual HRESULT SetSubMenu (IAvnMenu* menu) = 0;
virtual HRESULT SetTitle (void* utf8String) = 0;
virtual HRESULT SetGesture (void* utf8String, AvnInputModifiers modifiers) = 0;
virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) = 0;
virtual HRESULT SetIsChecked (bool isChecked) = 0;
virtual HRESULT SetToggleType (AvnMenuItemToggleType toggleType) = 0;
virtual HRESULT SetIcon (void* data, size_t length) = 0;
};
AVNCOM(IAvnMenuEvents, 1A) : IUnknown
{
/**
* NeedsUpdate
*/
virtual void NeedsUpdate () = 0;
};
AVNCOM(IAvnStringArray, 20) : IUnknown
{
virtual unsigned int GetCount() = 0;
virtual HRESULT Get(unsigned int index, IAvnString**ppv) = 0;
};
AVNCOM(IAvnDndResultCallback, 21) : IUnknown
{
virtual void OnDragAndDropComplete(AvnDragDropEffects effecct) = 0;
};
AVNCOM(IAvnGCHandleDeallocatorCallback, 22) : IUnknown
{
virtual void FreeGCHandle(void* handle) = 0;
};
AVNCOM(IAvnNativeControlHost, 20) : IUnknown
{
virtual HRESULT CreateDefaultChild(void* parent, void** retOut) = 0;
virtual IAvnNativeControlHostTopLevelAttachment* CreateAttachment() = 0;
virtual void DestroyDefaultChild(void* child) = 0;
};
AVNCOM(IAvnNativeControlHostTopLevelAttachment, 21) : IUnknown
{
virtual void* GetParentHandle() = 0;
virtual HRESULT InitializeWithChildHandle(void* child) = 0;
virtual HRESULT AttachTo(IAvnNativeControlHost* host) = 0;
virtual void ShowInBounds(float x, float y, float width, float height) = 0;
virtual void HideWithSize(float width, float height) = 0;
virtual void ReleaseChild() = 0;
};
extern "C" IAvaloniaNativeFactory* CreateAvaloniaNative();

2
native/Avalonia.Native/src/OSX/clipboard.mm

@ -67,7 +67,7 @@ public:
}
}
virtual HRESULT SetText (char* type, void* utf8String) override
virtual HRESULT SetText (char* type, char* utf8String) override
{
Clear();
@autoreleasepool

4
native/Avalonia.Native/src/OSX/main.mm

@ -104,9 +104,9 @@ class MacOptions : public ComSingleObject<IAvnMacOptions, &IID_IAvnMacOptions>
public:
FORWARD_IUNKNOWN()
virtual HRESULT SetApplicationTitle(void* utf8String) override
virtual HRESULT SetApplicationTitle(char* utf8String) override
{
auto appTitle = [NSString stringWithUTF8String:(const char*)utf8String];
auto appTitle = [NSString stringWithUTF8String: utf8String];
[[NSProcessInfo processInfo] setProcessName:appTitle];

6
native/Avalonia.Native/src/OSX/menu.h

@ -43,9 +43,9 @@ public:
virtual HRESULT SetSubMenu (IAvnMenu* menu) override;
virtual HRESULT SetTitle (void* utf8String) override;
virtual HRESULT SetTitle (char* utf8String) override;
virtual HRESULT SetGesture (void* key, AvnInputModifiers modifiers) override;
virtual HRESULT SetGesture (char* key, AvnInputModifiers modifiers) override;
virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) override;
@ -80,7 +80,7 @@ public:
virtual HRESULT RemoveItem (IAvnMenuItem* item) override;
virtual HRESULT SetTitle (void* utf8String) override;
virtual HRESULT SetTitle (char* utf8String) override;
virtual HRESULT Clear () override;
};

6
native/Avalonia.Native/src/OSX/menu.mm

@ -109,7 +109,7 @@ HRESULT AvnAppMenuItem::SetSubMenu (IAvnMenu* menu)
}
}
HRESULT AvnAppMenuItem::SetTitle (void* utf8String)
HRESULT AvnAppMenuItem::SetTitle (char* utf8String)
{
@autoreleasepool
{
@ -122,7 +122,7 @@ HRESULT AvnAppMenuItem::SetTitle (void* utf8String)
}
}
HRESULT AvnAppMenuItem::SetGesture (void* key, AvnInputModifiers modifiers)
HRESULT AvnAppMenuItem::SetGesture (char* key, AvnInputModifiers modifiers)
{
@autoreleasepool
{
@ -296,7 +296,7 @@ HRESULT AvnAppMenu::RemoveItem (IAvnMenuItem* item)
}
}
HRESULT AvnAppMenu::SetTitle (void* utf8String)
HRESULT AvnAppMenu::SetTitle (char* utf8String)
{
@autoreleasepool
{

2
native/Avalonia.Native/src/OSX/window.mm

@ -768,7 +768,7 @@ private:
}
}
virtual HRESULT SetTitle (void* utf8title) override
virtual HRESULT SetTitle (char* utf8title) override
{
@autoreleasepool
{

16
nukebuild/Build.cs

@ -233,6 +233,21 @@ partial class Build : NukeBuild
}
}
Target RunHtmlPreviewerTests => _ => _
.DependsOn(CompileHtmlPreviewer)
.OnlyWhenStatic(() => !(Parameters.SkipPreviewer || Parameters.SkipTests))
.Executes(() =>
{
var webappTestDir = RootDirectory / "tests" / "Avalonia.DesignerSupport.Tests" / "Remote" / "HtmlTransport" / "webapp";
NpmTasks.NpmInstall(c => c
.SetWorkingDirectory(webappTestDir)
.SetArgumentConfigurator(a => a.Add("--silent")));
NpmTasks.NpmRun(c => c
.SetWorkingDirectory(webappTestDir)
.SetCommand("test"));
});
Target RunCoreLibsTests => _ => _
.OnlyWhenStatic(() => !Parameters.SkipTests)
.DependsOn(Compile)
@ -332,6 +347,7 @@ partial class Build : NukeBuild
.DependsOn(RunCoreLibsTests)
.DependsOn(RunRenderTests)
.DependsOn(RunDesignerTests)
.DependsOn(RunHtmlPreviewerTests)
.DependsOn(RunLeakTests);
Target Package => _ => _

2
nukebuild/BuildParameters.cs

@ -62,7 +62,7 @@ public partial class Build
public AbsolutePath ZipTargetControlCatalogDesktopDir { get; }
public BuildParameters(Build b)
public BuildParameters(Build b)
{
// ARGUMENTS
Configuration = b.Configuration ?? "Release";

14
nukebuild/MicroComGen.cs

@ -0,0 +1,14 @@
using System.IO;
using MicroComGenerator;
using Nuke.Common;
partial class Build : NukeBuild
{
Target GenerateCppHeaders => _ => _.Executes(() =>
{
var text = File.ReadAllText(RootDirectory / "src" / "Avalonia.Native" / "avn.idl");
var ast = AstParser.Parse(text);
File.WriteAllText(RootDirectory / "native" / "Avalonia.Native" / "inc" / "avalonia-native.h",
CppGen.GenerateCpp(ast));
});
}

4
nukebuild/_build.csproj

@ -39,4 +39,8 @@
<Compile Include="Numerge/Numerge/**/*.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\src\tools\MicroComGenerator\MicroComGenerator.csproj" />
</ItemGroup>
</Project>

7
packages/Avalonia/Avalonia.csproj

@ -5,9 +5,8 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../../src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj"/>
<ProjectReference Include="../../src/Avalonia.Remote.Protocol/Avalonia.Remote.Protocol.csproj" />
<ProjectReference Include="../../src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj" />
</ItemGroup>
<PropertyGroup>
@ -15,9 +14,7 @@
</PropertyGroup>
<Target Name="AddDesignerHostAppsToPackage" BeforeTargets="GenerateNuspec">
<MSBuild Projects="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj"
Properties="Configuration=$(Configuration);
Platform=$(Platform)" />
<MSBuild Projects="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/Avalonia.Designer.HostApp.csproj" Properties="Configuration=$(Configuration);&#xA; Platform=$(Platform)" />
<ItemGroup>
<_PackageFiles Include="$(DesignerHostAppPath)/Avalonia.Designer.HostApp/bin/$(Configuration)/netcoreapp2.0/Avalonia.Designer.HostApp.dll">

4
packages/Avalonia/AvaloniaBuildTasks.targets

@ -3,6 +3,8 @@
<_AvaloniaUseExternalMSBuild>$(AvaloniaUseExternalMSBuild)</_AvaloniaUseExternalMSBuild>
<_AvaloniaUseExternalMSBuild Condition="'$(_AvaloniaForceInternalMSBuild)' == 'true'">false</_AvaloniaUseExternalMSBuild>
<AvaloniaXamlReportImportance Condition="'$(AvaloniaXamlReportImportance)' == ''">low</AvaloniaXamlReportImportance>
<_AvaloniaPatchComInterop Condition="'$(_AvaloniaPatchComInterop)' == ''">false</_AvaloniaPatchComInterop>
<_AvaloniaSkipXamlCompilation Condition="'$(_AvaloniaSkipXamlCompilation)' == ''">false</_AvaloniaSkipXamlCompilation>
</PropertyGroup>
<!-- Unfortunately we have to update default items in .targets since custom nuget props are improted before Microsoft.NET.Sdk.DefaultItems.props -->
@ -90,6 +92,8 @@
AssemblyOriginatorKeyFile="$(AssemblyOriginatorKeyFile)"
SignAssembly="$(SignAssembly)"
DelaySign="$(DelaySign)"
EnableComInteropPatching="$(_AvaloniaPatchComInterop)"
SkipXamlCompilation="$(_AvaloniaSkipXamlCompilation)"
/>
<Exec
Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'"

130
src/Avalonia.Build.Tasks/ComInteropHelper.cs

@ -0,0 +1,130 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Mono.Cecil;
using Mono.Cecil.Cil;
using XamlX.TypeSystem;
using MethodAttributes = Mono.Cecil.MethodAttributes;
namespace Avalonia.Build.Tasks
{
static class ComInteropHelper
{
public static void PatchAssembly(AssemblyDefinition asm, CecilTypeSystem typeSystem)
{
var classToRemoveList = new List<TypeDefinition>();
var initializers = new List<MethodDefinition>();
foreach (var type in asm.MainModule.Types)
{
var i = type.Methods.FirstOrDefault(m => m.Name == "__MicroComModuleInit");
if (i != null)
initializers.Add(i);
PatchType(type, classToRemoveList);
}
// Remove All Interop classes
foreach (var type in classToRemoveList)
asm.MainModule.Types.Remove(type);
// Patch automatic registrations
if (initializers.Count != 0)
{
var moduleType = asm.MainModule.Types.First(x => x.Name == "<Module>");
// Needed for compatibility with upcoming .NET 5 feature, look for existing initializer first
var staticCtor = moduleType.Methods.FirstOrDefault(m => m.Name == ".cctor");
if (staticCtor == null)
{
// Create a new static ctor if none exists
staticCtor = new MethodDefinition(".cctor",
MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName |
MethodAttributes.Static | MethodAttributes.Private,
asm.MainModule.TypeSystem.Void);
staticCtor.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
moduleType.Methods.Add(staticCtor);
}
foreach (var i in initializers)
staticCtor.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Call, i));
}
}
static void PatchMethod(MethodDefinition method)
{
if (method.HasBody)
{
var ilProcessor = method.Body.GetILProcessor();
var instructions = method.Body.Instructions;
for (int i = 0; i < instructions.Count; i++)
{
Instruction instruction = instructions[i];
if (instruction.OpCode == OpCodes.Call && instruction.Operand is MethodReference)
{
var methodDescription = (MethodReference)instruction.Operand;
if (methodDescription.Name.StartsWith("Calli") && methodDescription.DeclaringType.Name == "LocalInterop")
{
var callSite = new CallSite(methodDescription.ReturnType) { CallingConvention = MethodCallingConvention.StdCall };
if (methodDescription.Name.StartsWith("CalliCdecl"))
{
callSite.CallingConvention = MethodCallingConvention.C;
}
else if(methodDescription.Name.StartsWith("CalliThisCall"))
{
callSite.CallingConvention = MethodCallingConvention.ThisCall;
}
else if(methodDescription.Name.StartsWith("CalliStdCall"))
{
callSite.CallingConvention = MethodCallingConvention.StdCall;
}
else if(methodDescription.Name.StartsWith("CalliFastCall"))
{
callSite.CallingConvention = MethodCallingConvention.FastCall;
}
// Last parameter is the function ptr, so we don't add it as a parameter for calli
// as it is already an implicit parameter for calli
for (int j = 0; j < methodDescription.Parameters.Count - 1; j++)
{
var parameterDefinition = methodDescription.Parameters[j];
callSite.Parameters.Add(parameterDefinition);
}
// Create calli Instruction
var callIInstruction = ilProcessor.Create(OpCodes.Calli, callSite);
// Replace instruction
ilProcessor.Replace(instruction, callIInstruction);
}
}
}
}
}
/// <summary>
/// Patches the type.
/// </summary>
/// <param name="type">The type.</param>
static void PatchType(TypeDefinition type, List<TypeDefinition> classToRemoveList)
{
// Patch methods
foreach (var method in type.Methods)
PatchMethod(method);
if (type.Name == "LocalInterop")
classToRemoveList.Add(type);
// Patch nested types
foreach (var typeDefinition in type.NestedTypes)
PatchType(typeDefinition, classToRemoveList);
}
}
}

7
src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs

@ -40,8 +40,8 @@ namespace Avalonia.Build.Tasks
var res = XamlCompilerTaskExecutor.Compile(BuildEngine, input,
File.ReadAllLines(ReferencesFilePath).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray(),
ProjectDirectory, OutputPath, VerifyIl, outputImportance,
(SignAssembly && !DelaySign) ? AssemblyOriginatorKeyFile : null
);
(SignAssembly && !DelaySign) ? AssemblyOriginatorKeyFile : null,
EnableComInteropPatching, SkipXamlCompilation);
if (!res.Success)
return false;
if (!res.WrittenFile)
@ -76,6 +76,9 @@ namespace Avalonia.Build.Tasks
public bool VerifyIl { get; set; }
public bool EnableComInteropPatching { get; set; }
public bool SkipXamlCompilation { get; set; }
public string AssemblyOriginatorKeyFile { get; set; }
public bool SignAssembly { get; set; }
public bool DelaySign { get; set; }

3
src/Avalonia.Build.Tasks/Program.cs

@ -29,7 +29,8 @@ namespace Avalonia.Build.Tasks
OutputPath = args[2],
BuildEngine = new ConsoleBuildEngine(),
ProjectDirectory = Directory.GetCurrentDirectory(),
VerifyIl = true
VerifyIl = true,
EnableComInteropPatching = true
}.Execute() ?
0 :
2;

53
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@ -40,17 +40,48 @@ namespace Avalonia.Build.Tasks
WrittenFile = writtenFile;
}
}
public static CompileResult Compile(IBuildEngine engine, string input, string[] references,
string projectDirectory,
string output, bool verifyIl, MessageImportance logImportance, string strongNameKey, bool patchCom,
bool skipXamlCompilation)
{
var typeSystem = new CecilTypeSystem(references.Concat(new[] { input }), input);
var asm = typeSystem.TargetAssemblyDefinition;
if (!skipXamlCompilation)
{
var compileRes = CompileCore(engine, typeSystem, projectDirectory, verifyIl, logImportance);
if (compileRes == null && !patchCom)
return new CompileResult(true);
if (compileRes == false)
return new CompileResult(false);
}
if (patchCom)
ComInteropHelper.PatchAssembly(asm, typeSystem);
var writerParameters = new WriterParameters { WriteSymbols = asm.MainModule.HasSymbols };
if (!string.IsNullOrWhiteSpace(strongNameKey))
writerParameters.StrongNameKeyBlob = File.ReadAllBytes(strongNameKey);
asm.Write(output, writerParameters);
return new CompileResult(true, true);
}
public static CompileResult Compile(IBuildEngine engine, string input, string[] references, string projectDirectory,
string output, bool verifyIl, MessageImportance logImportance, string strongNameKey)
static bool? CompileCore(IBuildEngine engine, CecilTypeSystem typeSystem,
string projectDirectory, bool verifyIl,
MessageImportance logImportance)
{
var typeSystem = new CecilTypeSystem(references.Concat(new[] {input}), input);
var asm = typeSystem.TargetAssemblyDefinition;
var emres = new EmbeddedResources(asm);
var avares = new AvaloniaResources(asm, projectDirectory);
if (avares.Resources.Count(CheckXamlName) == 0 && emres.Resources.Count(CheckXamlName) == 0)
// Nothing to do
return new CompileResult(true);
return null;
var clrPropertiesDef = new TypeDefinition("CompiledAvaloniaXaml", "XamlIlHelpers",
TypeAttributes.Class, asm.MainModule.TypeSystem.Object);
@ -364,25 +395,17 @@ namespace Avalonia.Build.Tasks
if (emres.Resources.Count(CheckXamlName) != 0)
if (!CompileGroup(emres))
return new CompileResult(false);
return false;
if (avares.Resources.Count(CheckXamlName) != 0)
{
if (!CompileGroup(avares))
return new CompileResult(false);
return false;
avares.Save();
}
loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull));
loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
var writerParameters = new WriterParameters { WriteSymbols = asm.MainModule.HasSymbols };
if (!string.IsNullOrWhiteSpace(strongNameKey))
writerParameters.StrongNameKeyBlob = File.ReadAllBytes(strongNameKey);
asm.Write(output, writerParameters);
return new CompileResult(true, true);
return true;
}
}

84
src/Avalonia.DesignerSupport/Remote/HtmlTransport/HtmlTransport.cs

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
@ -9,6 +10,7 @@ using System.Threading;
using System.Threading.Tasks;
using Avalonia.Remote.Protocol;
using Avalonia.Remote.Protocol.Viewport;
using InputProtocol = Avalonia.Remote.Protocol.Input;
namespace Avalonia.DesignerSupport.Remote.HtmlTransport
{
@ -115,14 +117,11 @@ namespace Avalonia.DesignerSupport.Remote.HtmlTransport
while (true)
{
var msg = await socket.ReceiveMessage().ConfigureAwait(false);
if(msg == null)
return;
if (msg.IsText)
if(msg != null && msg.IsText)
{
var s = Encoding.UTF8.GetString(msg.Data);
var parts = s.Split(':');
if (parts[0] == "frame-received")
_onMessage?.Invoke(this, new FrameReceivedMessage { SequenceId = long.Parse(parts[1]) });
var message = ParseMessage(msg.AsString());
if (message != null)
_onMessage?.Invoke(this, message);
}
}
}
@ -181,7 +180,6 @@ namespace Avalonia.DesignerSupport.Remote.HtmlTransport
_pendingSocket?.Dispose();
_simpleServer.Dispose();
}
public Task Send(object data)
{
@ -264,5 +262,75 @@ namespace Avalonia.DesignerSupport.Remote.HtmlTransport
_onException?.Invoke(this, ex);
}
#endregion
private static object ParseMessage(string message)
{
var parts = message.Split(':');
var key = parts[0];
if (key.Equals("frame-received", StringComparison.OrdinalIgnoreCase))
{
return new FrameReceivedMessage { SequenceId = long.Parse(parts[1]) };
}
else if (key.Equals("pointer-released", StringComparison.OrdinalIgnoreCase))
{
return new InputProtocol.PointerReleasedEventMessage
{
Modifiers = ParseInputModifiers(parts[1]),
X = ParseDouble(parts[2]),
Y = ParseDouble(parts[3]),
Button = ParseMouseButton(parts[4]),
};
}
else if (key.Equals("pointer-pressed", StringComparison.OrdinalIgnoreCase))
{
return new InputProtocol.PointerPressedEventMessage
{
Modifiers = ParseInputModifiers(parts[1]),
X = ParseDouble(parts[2]),
Y = ParseDouble(parts[3]),
Button = ParseMouseButton(parts[4]),
};
}
else if (key.Equals("pointer-moved", StringComparison.OrdinalIgnoreCase))
{
return new InputProtocol.PointerMovedEventMessage
{
Modifiers = ParseInputModifiers(parts[1]),
X = ParseDouble(parts[2]),
Y = ParseDouble(parts[3]),
};
}
else if (key.Equals("scroll", StringComparison.OrdinalIgnoreCase))
{
return new InputProtocol.ScrollEventMessage
{
Modifiers = ParseInputModifiers(parts[1]),
X = ParseDouble(parts[2]),
Y = ParseDouble(parts[3]),
DeltaX = ParseDouble(parts[4]),
DeltaY = ParseDouble(parts[5]),
};
}
return null;
}
private static InputProtocol.InputModifiers[] ParseInputModifiers(string modifiersText) =>
string.IsNullOrWhiteSpace(modifiersText)
? null
: modifiersText
.Split(',')
.Select(x => (InputProtocol.InputModifiers)Enum.Parse(
typeof(InputProtocol.InputModifiers), x, true))
.ToArray();
private static InputProtocol.MouseButton ParseMouseButton(string buttonText) =>
string.IsNullOrWhiteSpace(buttonText)
? InputProtocol.MouseButton.None
: (InputProtocol.MouseButton)Enum.Parse(
typeof(InputProtocol.MouseButton), buttonText, true);
private static double ParseDouble(string text) =>
double.Parse(text, NumberStyles.Float, CultureInfo.InvariantCulture);
}
}

41
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/FramePresenter.tsx

@ -1,5 +1,9 @@
import {PreviewerFrame, PreviewerServerConnection} from "src/PreviewerServerConnection";
import * as React from "react";
import {PreviewerFrame, PreviewerServerConnection} from "src/PreviewerServerConnection";
import {PointerPressedEventMessage} from "src/Models/Input/PointerPressedEventMessage";
import {PointerReleasedEventMessage} from "src/Models/Input/PointerReleasedEventMessage";
import {PointerMovedEventMessage} from "src/Models/Input/PointerMovedEventMessage";
import {ScrollEventMessage} from "src/Models/Input/ScrollEventMessage";
interface PreviewerPresenterProps {
conn: PreviewerServerConnection;
@ -15,6 +19,11 @@ export class PreviewerPresenter extends React.Component<PreviewerPresenterProps>
this.componentDidUpdate({
conn: null!
}, this.state);
this.handleMouseDown = this.handleMouseDown.bind(this);
this.handleMouseUp = this.handleMouseUp.bind(this);
this.handleMouseMove = this.handleMouseMove.bind(this);
this.handleWheel = this.handleWheel.bind(this);
}
componentDidMount(): void {
@ -51,7 +60,35 @@ export class PreviewerPresenter extends React.Component<PreviewerPresenterProps>
}
}
handleMouseDown(e: React.MouseEvent) {
e.preventDefault();
const pointerPressedEventMessage = new PointerPressedEventMessage(e);
this.props.conn.sendMouseEvent(pointerPressedEventMessage);
}
handleMouseUp(e: React.MouseEvent) {
e.preventDefault();
const pointerReleasedEventMessage = new PointerReleasedEventMessage(e);
this.props.conn.sendMouseEvent(pointerReleasedEventMessage);
}
handleMouseMove(e: React.MouseEvent) {
e.preventDefault();
const pointerMovedEventMessage = new PointerMovedEventMessage(e);
this.props.conn.sendMouseEvent(pointerMovedEventMessage);
}
handleWheel(e: React.WheelEvent) {
e.preventDefault();
const scrollEventMessage = new ScrollEventMessage(e);
this.props.conn.sendMouseEvent(scrollEventMessage);
}
render() {
return <canvas ref={this.canvasRef}/>
return <canvas ref={this.canvasRef}
onMouseDown={this.handleMouseDown}
onMouseUp={this.handleMouseUp}
onMouseMove={this.handleMouseMove}
onWheel={this.handleWheel} />
}
}

11
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/InputEventMessageBase.ts

@ -0,0 +1,11 @@
import * as React from "react";
import {InputModifiers} from "./InputModifiers";
import {getModifiers} from "./MouseEventHelpers";
export abstract class InputEventMessageBase {
public readonly modifiers : Array<InputModifiers>;
protected constructor(e: React.MouseEvent) {
this.modifiers = getModifiers(e);
}
}

9
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/InputModifiers.ts

@ -0,0 +1,9 @@
export enum InputModifiers {
Alt,
Control,
Shift,
Windows,
LeftMouseButton,
RightMouseButton,
MiddleMouseButton,
}

6
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/MouseButton.ts

@ -0,0 +1,6 @@
export enum MouseButton {
None,
Left,
Right,
Middle,
}

39
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/MouseEventHelpers.ts

@ -0,0 +1,39 @@
import * as React from "react";
import {InputModifiers} from "./InputModifiers";
import {MouseButton} from "./MouseButton";
export function getModifiers(e: React.MouseEvent): Array<InputModifiers> {
let modifiers : Array<InputModifiers> = [];
if (e.altKey)
modifiers.push(InputModifiers.Alt);
if (e.ctrlKey)
modifiers.push(InputModifiers.Control);
if (e.shiftKey)
modifiers.push(InputModifiers.Shift);
if (e.metaKey)
modifiers.push(InputModifiers.Windows);
if (e.buttons != 0) {
if ((e.buttons & 1) != 0)
modifiers.push(InputModifiers.LeftMouseButton);
if ((e.buttons & 2) != 0)
modifiers.push(InputModifiers.RightMouseButton);
if ((e.buttons & 4) != 0)
modifiers.push(InputModifiers.MiddleMouseButton);
}
return modifiers;
}
export function getMouseButton(e: React.MouseEvent) : MouseButton {
if (e.button == 0) {
return MouseButton.Left;
} else if (e.button == 1) {
return MouseButton.Middle;
} else if (e.button == 2) {
return MouseButton.Right;
} else {
return MouseButton.None;
}
}

13
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/PointerEventMessageBase.ts

@ -0,0 +1,13 @@
import * as React from "react";
import {InputEventMessageBase} from "./InputEventMessageBase";
export abstract class PointerEventMessageBase extends InputEventMessageBase {
public readonly x: number;
public readonly y: number;
protected constructor(e: React.MouseEvent) {
super(e);
this.x = e.clientX;
this.y = e.clientY;
}
}

12
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/PointerMovedEventMessage.ts

@ -0,0 +1,12 @@
import * as React from "react";
import {PointerEventMessageBase} from "./PointerEventMessageBase";
export class PointerMovedEventMessage extends PointerEventMessageBase {
constructor(e: React.MouseEvent) {
super(e);
}
public toString = () : string => {
return `pointer-moved:${this.modifiers}:${this.x}:${this.y}`;
}
}

17
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/PointerPressedEventMessage.ts

@ -0,0 +1,17 @@
import * as React from "react";
import {PointerEventMessageBase} from "./PointerEventMessageBase";
import {MouseButton} from "./MouseButton";
import {getMouseButton} from "./MouseEventHelpers";
export class PointerPressedEventMessage extends PointerEventMessageBase {
public readonly button: MouseButton
constructor(e: React.MouseEvent) {
super(e);
this.button = getMouseButton(e);
}
public toString = () : string => {
return `pointer-pressed:${this.modifiers}:${this.x}:${this.y}:${this.button}`;
}
}

17
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/PointerReleasedEventMessage.ts

@ -0,0 +1,17 @@
import * as React from "react";
import {PointerEventMessageBase} from "./PointerEventMessageBase";
import {MouseButton} from "./MouseButton";
import {getMouseButton} from "./MouseEventHelpers";
export class PointerReleasedEventMessage extends PointerEventMessageBase {
public readonly button: MouseButton
constructor(e: React.MouseEvent) {
super(e);
this.button = getMouseButton(e);
}
public toString = () : string => {
return `pointer-released:${this.modifiers}:${this.x}:${this.y}:${this.button}`;
}
}

17
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/ScrollEventMessage.ts

@ -0,0 +1,17 @@
import * as React from "react";
import {PointerEventMessageBase} from "./PointerEventMessageBase";
export class ScrollEventMessage extends PointerEventMessageBase {
public readonly deltaX: number;
public readonly deltaY: number;
constructor(e: React.WheelEvent) {
super(e);
this.deltaX = -e.deltaX;
this.deltaY = -e.deltaY;
}
public toString = () : string => {
return `scroll:${this.modifiers}:${this.x}:${this.y}:${this.deltaX}:${this.deltaY}`;
}
}

6
src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/PreviewerServerConnection.ts

@ -1,3 +1,5 @@
import { InputEventMessageBase } from "src/Models/Input/InputEventMessageBase";
export interface PreviewerFrame {
data: ImageData;
dpiX: number;
@ -28,6 +30,10 @@ export class PreviewerServerConnection {
this.handlers.delete(listener);
}
public sendMouseEvent(message: InputEventMessageBase) {
this.conn.send(message.toString());
}
constructor(uri: string) {
this.currentFrame = null;
var conn = this.conn = new WebSocket(uri);

17
src/Avalonia.MicroCom/Avalonia.MicroCom.csproj

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup>
<_AvaloniaPatchComInterop>true</_AvaloniaPatchComInterop>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Avalonia.Build.Tasks\Avalonia.Build.Tasks.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<ExcludeAssets>all</ExcludeAssets>
<SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
</ProjectReference>
</ItemGroup>
<Import Project="..\..\build\BuildTargets.targets" />
</Project>

9
src/Avalonia.MicroCom/IMicroComExceptionCallback.cs

@ -0,0 +1,9 @@
using System;
namespace Avalonia.MicroCom
{
public interface IMicroComExceptionCallback
{
void RaiseException(Exception e);
}
}

9
src/Avalonia.MicroCom/IMicroComShadowContainer.cs

@ -0,0 +1,9 @@
namespace Avalonia.MicroCom
{
public interface IMicroComShadowContainer
{
MicroComShadow Shadow { get; set; }
void OnReferencedFromNative();
void OnUnreferencedFromNative();
}
}

8
src/Avalonia.MicroCom/IUnknown.cs

@ -0,0 +1,8 @@
using System;
namespace Avalonia.MicroCom
{
public interface IUnknown : IDisposable
{
}
}

17
src/Avalonia.MicroCom/LocalInterop.cs

@ -0,0 +1,17 @@
using System;
namespace Avalonia.MicroCom
{
unsafe class LocalInterop
{
public static unsafe void CalliStdCallvoid(void* thisObject, void* methodPtr)
{
throw null;
}
public static unsafe int CalliStdCallint(void* thisObject, Guid* guid, IntPtr* ppv, void* methodPtr)
{
throw null;
}
}
}

110
src/Avalonia.MicroCom/MicroComProxyBase.cs

@ -0,0 +1,110 @@
using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Threading;
namespace Avalonia.MicroCom
{
public unsafe class MicroComProxyBase : CriticalFinalizerObject, IUnknown
{
private IntPtr _nativePointer;
private bool _ownsHandle;
private SynchronizationContext _synchronizationContext;
public IntPtr NativePointer
{
get
{
if (_nativePointer == IntPtr.Zero)
throw new ObjectDisposedException(this.GetType().FullName);
return _nativePointer;
}
}
public void*** PPV => (void***)NativePointer;
public MicroComProxyBase(IntPtr nativePointer, bool ownsHandle)
{
_nativePointer = nativePointer;
_ownsHandle = ownsHandle;
_synchronizationContext = SynchronizationContext.Current;
if(!_ownsHandle)
GC.SuppressFinalize(this);
}
protected virtual int VTableSize => 3;
public void AddRef()
{
LocalInterop.CalliStdCallvoid(PPV, (*PPV)[1]);
}
public void Release()
{
LocalInterop.CalliStdCallvoid(PPV, (*PPV)[2]);
}
public int QueryInterface(Guid guid, out IntPtr ppv)
{
IntPtr r = default;
var rv = LocalInterop.CalliStdCallint(PPV, &guid, &r, (*PPV)[0]);
ppv = r;
return rv;
}
public T QueryInterface<T>() where T : IUnknown
{
var guid = MicroComRuntime.GetGuidFor(typeof(T));
var rv = QueryInterface(guid, out var ppv);
if (rv != 0)
return (T)MicroComRuntime.CreateProxyFor(typeof(T), ppv, true);
throw new COMException("QueryInterface failed", rv);
}
public bool IsDisposed => _nativePointer == IntPtr.Zero;
protected virtual void Dispose(bool disposing)
{
if(_nativePointer == null)
return;
if (_ownsHandle)
{
Release();
_ownsHandle = false;
}
_nativePointer = IntPtr.Zero;
GC.SuppressFinalize(this);
}
public void Dispose() => Dispose(true);
public bool OwnsHandle => _ownsHandle;
public void EnsureOwned()
{
if (!_ownsHandle)
{
GC.ReRegisterForFinalize(true);
AddRef();
_ownsHandle = true;
}
}
private static readonly SendOrPostCallback _disposeDelegate = DisposeOnContext;
private static void DisposeOnContext(object state)
{
(state as MicroComProxyBase)?.Dispose(false);
}
~MicroComProxyBase()
{
if(!_ownsHandle)
return;
if (_synchronizationContext == null)
Dispose();
else
_synchronizationContext.Post(_disposeDelegate, this);
}
}
}

98
src/Avalonia.MicroCom/MicroComRuntime.cs

@ -0,0 +1,98 @@
using System;
using System.Collections.Concurrent;
using System.Runtime.InteropServices;
namespace Avalonia.MicroCom
{
public static unsafe class MicroComRuntime
{
private static ConcurrentDictionary<Type, IntPtr> _vtables = new ConcurrentDictionary<Type, IntPtr>();
private static ConcurrentDictionary<Type, Func<IntPtr, bool, object>> _factories =
new ConcurrentDictionary<Type, Func<IntPtr, bool, object>>();
private static ConcurrentDictionary<Type, Guid> _guids = new ConcurrentDictionary<Type, Guid>();
private static ConcurrentDictionary<Guid, Type> _guidsToTypes = new ConcurrentDictionary<Guid, Type>();
static MicroComRuntime()
{
Register(typeof(IUnknown), new Guid("00000000-0000-0000-C000-000000000046"),
(ppv, owns) => new MicroComProxyBase(ppv, owns));
RegisterVTable(typeof(IUnknown), MicroComVtblBase.Vtable);
}
public static void RegisterVTable(Type t, IntPtr vtable)
{
_vtables[t] = vtable;
}
public static void Register(Type t, Guid guid, Func<IntPtr, bool, object> proxyFactory)
{
_factories[t] = proxyFactory;
_guids[t] = guid;
_guidsToTypes[guid] = t;
}
public static Guid GetGuidFor(Type type) => _guids[type];
public static T CreateProxyFor<T>(void* pObject, bool ownsHandle) => (T)CreateProxyFor(typeof(T), new IntPtr(pObject), ownsHandle);
public static T CreateProxyFor<T>(IntPtr pObject, bool ownsHandle) => (T)CreateProxyFor(typeof(T), pObject, ownsHandle);
public static object CreateProxyFor(Type type, IntPtr pObject, bool ownsHandle) => _factories[type](pObject, ownsHandle);
public static void* GetNativePointer<T>(T obj, bool owned = false) where T : IUnknown
{
if (obj == null)
return null;
if (obj is MicroComProxyBase proxy)
return (void*)proxy.NativePointer;
if (obj is IMicroComShadowContainer container)
{
container.Shadow ??= new MicroComShadow(container);
void* ptr = null;
var res = container.Shadow.GetOrCreateNativePointer(typeof(T), &ptr);
if (res != 0)
throw new COMException(
"Unable to create native callable wrapper for type " + typeof(T) + " for instance of type " +
obj.GetType(),
res);
if (owned)
container.Shadow.AddRef((Ccw*)ptr);
return ptr;
}
throw new ArgumentException("Unable to get a native pointer for " + obj);
}
public static object GetObjectFromCcw(IntPtr ccw)
{
var ptr = (Ccw*)ccw;
var shadow = (MicroComShadow)GCHandle.FromIntPtr(ptr->GcShadowHandle).Target;
return shadow.Target;
}
public static bool TryGetTypeForGuid(Guid guid, out Type t) => _guidsToTypes.TryGetValue(guid, out t);
public static bool GetVtableFor(Type type, out IntPtr ptr) => _vtables.TryGetValue(type, out ptr);
public static void UnhandledException(object target, Exception e)
{
if (target is IMicroComExceptionCallback cb)
{
try
{
cb.RaiseException(e);
}
catch
{
// We've tried
}
}
}
public static T CloneReference<T>(T iface) where T : IUnknown
{
var ownedPointer = GetNativePointer(iface, true);
return CreateProxyFor<T>(ownedPointer, true);
}
}
}

171
src/Avalonia.MicroCom/MicroComShadow.cs

@ -0,0 +1,171 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
namespace Avalonia.MicroCom
{
public unsafe class MicroComShadow : IDisposable
{
private readonly object _lock = new object();
private readonly Dictionary<Type, IntPtr> _shadows = new Dictionary<Type, IntPtr>();
private readonly Dictionary<IntPtr, Type> _backShadows = new Dictionary<IntPtr, Type>();
private GCHandle? _handle;
private volatile int _refCount;
internal IMicroComShadowContainer Target { get; }
internal MicroComShadow(IMicroComShadowContainer target)
{
Target = target;
Target.Shadow = this;
}
internal int QueryInterface(Ccw* ccw, Guid* guid, void** ppv)
{
if (MicroComRuntime.TryGetTypeForGuid(*guid, out var type))
return QueryInterface(type, ppv);
else
return unchecked((int)0x80004002u);
}
internal int QueryInterface(Type type, void** ppv)
{
if (!type.IsInstanceOfType(Target))
return unchecked((int)0x80004002u);
var rv = GetOrCreateNativePointer(type, ppv);
if (rv == 0)
AddRef((Ccw*)*ppv);
return rv;
}
internal int GetOrCreateNativePointer(Type type, void** ppv)
{
if (!MicroComRuntime.GetVtableFor(type, out var vtable))
return unchecked((int)0x80004002u);
lock (_lock)
{
if (_shadows.TryGetValue(type, out var shadow))
{
var targetCcw = (Ccw*)shadow;
AddRef(targetCcw);
*ppv = targetCcw;
return 0;
}
else
{
var intPtr = Marshal.AllocHGlobal(Marshal.SizeOf<Ccw>());
var targetCcw = (Ccw*)intPtr;
*targetCcw = default;
targetCcw->RefCount = 0;
targetCcw->VTable = vtable;
if (_handle == null)
_handle = GCHandle.Alloc(this);
targetCcw->GcShadowHandle = GCHandle.ToIntPtr(_handle.Value);
_shadows[type] = intPtr;
_backShadows[intPtr] = type;
*ppv = targetCcw;
return 0;
}
}
}
internal int AddRef(Ccw* ccw)
{
if (Interlocked.Increment(ref _refCount) == 1)
{
try
{
Target.OnReferencedFromNative();
}
catch (Exception e)
{
MicroComRuntime.UnhandledException(Target, e);
}
}
return Interlocked.Increment(ref ccw->RefCount);
}
internal int Release(Ccw* ccw)
{
Interlocked.Decrement(ref _refCount);
var cnt = Interlocked.Decrement(ref ccw->RefCount);
if (cnt == 0)
return FreeCcw(ccw);
return cnt;
}
int FreeCcw(Ccw* ccw)
{
lock (_lock)
{
// Shadow got resurrected by a call to QueryInterface from another thread
if (ccw->RefCount != 0)
return ccw->RefCount;
var intPtr = new IntPtr(ccw);
var type = _backShadows[intPtr];
_backShadows.Remove(intPtr);
_shadows.Remove(type);
Marshal.FreeHGlobal(intPtr);
if (_shadows.Count == 0)
{
_handle?.Free();
_handle = null;
try
{
Target.OnUnreferencedFromNative();
}
catch(Exception e)
{
MicroComRuntime.UnhandledException(Target, e);
}
}
}
return 0;
}
/*
Needs to be called to support the following scenario:
1) Object created
2) Object passed to native code, shadow is created, CCW is created
3) Native side has never called AddRef
In that case the GC handle to the shadow object is still alive
*/
public void Dispose()
{
lock (_lock)
{
List<IntPtr> toRemove = null;
foreach (var kv in _backShadows)
{
var ccw = (Ccw*)kv.Key;
if (ccw->RefCount == 0)
{
toRemove ??= new List<IntPtr>();
toRemove.Add(kv.Key);
}
}
if(toRemove != null)
foreach (var intPtr in toRemove)
FreeCcw((Ccw*)intPtr);
}
}
}
[StructLayout(LayoutKind.Sequential)]
struct Ccw
{
public IntPtr VTable;
public IntPtr GcShadowHandle;
public volatile int RefCount;
public MicroComShadow GetShadow() => (MicroComShadow)GCHandle.FromIntPtr(GcShadowHandle).Target;
}
}

42
src/Avalonia.MicroCom/MicroComVtblBase.cs

@ -0,0 +1,42 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
namespace Avalonia.MicroCom
{
public unsafe class MicroComVtblBase
{
private List<IntPtr> _methods = new List<IntPtr>();
[UnmanagedFunctionPointerAttribute(CallingConvention.ThisCall)]
private delegate int AddRefDelegate(Ccw* ccw);
[UnmanagedFunctionPointerAttribute(CallingConvention.ThisCall)]
private delegate int QueryInterfaceDelegate(Ccw* ccw, Guid* guid, void** ppv);
public static IntPtr Vtable { get; } = new MicroComVtblBase().CreateVTable();
public MicroComVtblBase()
{
AddMethod((QueryInterfaceDelegate)QueryInterface);
AddMethod((AddRefDelegate)AddRef);
AddMethod((AddRefDelegate)Release);
}
protected void AddMethod(Delegate d)
{
GCHandle.Alloc(d);
_methods.Add(Marshal.GetFunctionPointerForDelegate(d));
}
protected unsafe IntPtr CreateVTable()
{
var ptr = (IntPtr*)Marshal.AllocHGlobal((IntPtr.Size + 1) * _methods.Count);
for (var c = 0; c < _methods.Count; c++)
ptr[c] = _methods[c];
return new IntPtr(ptr);
}
static int QueryInterface(Ccw* ccw, Guid* guid, void** ppv) => ccw->GetShadow().QueryInterface(ccw, guid, ppv);
static int AddRef(Ccw* ccw) => ccw->GetShadow().AddRef(ccw);
static int Release(Ccw* ccw) => ccw->GetShadow().Release(ccw);
}
}

1
src/Avalonia.Native/.gitignore

@ -1 +1,2 @@
Generated/*.cs
*.Generated.cs

40
src/Avalonia.Native/Avalonia.Native.csproj

@ -5,10 +5,7 @@
<IsPackable>$(PackAvaloniaNative)</IsPackable>
<IsPackable Condition="'$([MSBuild]::IsOSPlatform(OSX))' == 'True'">true</IsPackable>
<TargetFramework>netstandard2.0</TargetFramework>
<CastXmlPath Condition="Exists('/usr/bin/castxml')">/usr/bin/castxml</CastXmlPath>
<CastXmlPath Condition="Exists('/usr/local/bin/castxml')">/usr/local/bin/castxml</CastXmlPath>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<SharpGenGenerateConsumerBindMapping>false</SharpGenGenerateConsumerBindMapping>
</PropertyGroup>
<ItemGroup Condition="'$(PackAvaloniaNative)' == 'true'">
@ -21,11 +18,38 @@
</ItemGroup>
<ItemGroup>
<!--<SharpGenMapping Include="Mappings.xml" />-->
<PackageReference Include="SharpGenTools.Sdk" Version="1.2.1" PrivateAssets="all" />
<PackageReference Include="SharpGen.Runtime" Version="1.2.1" />
<PackageReference Include="SharpGen.Runtime.COM" Version="1.2.0" />
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\Avalonia.Dialogs\Avalonia.Dialogs.csproj" />
</ItemGroup>
</Project>
<!-- COM Interop generation -->
<ItemGroup>
<ProjectReference Include="..\tools\MicroComGenerator\MicroComGenerator.csproj">
<ReferenceOutputAssembly>false</ReferenceOutputAssembly>
<ExcludeAssets>all</ExcludeAssets>
<SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
</ProjectReference>
</ItemGroup>
<Target Name="GenerateAvaloniaNativeComInterop"
BeforeTargets="CoreCompile"
DependsOnTargets="ResolveReferences"
Inputs="avn.idl;$(MSBuildThisFileDirectory)/../tools/MicroComGenerator/**/*.cs"
Outputs="Interop.Generated.cs">
<Message Importance="high" Text="Generating Interop.Generated.cs" />
<Exec Command="dotnet ../tools/MicroComGenerator/bin/$(Configuration)/netcoreapp3.1/MicroComGenerator.dll -i avn.idl --cs Interop.Generated.cs" LogStandardErrorAsError="true" />
<ItemGroup>
<!-- Remove and re-add generated file, this is needed for the clean build -->
<Compile Remove="Interop.Generated.cs"/>
<Compile Include="Interop.Generated.cs"/>
</ItemGroup>
</Target>
<ItemGroup>
<UpToDateCheckInput Include="avn.idl"/>
<UpToDateCheckInput Include="$(MSBuildThisFileDirectory)/../tools/MicroComGenerator/**/*.cs"/>
</ItemGroup>
<PropertyGroup>
<_AvaloniaPatchComInterop>true</_AvaloniaPatchComInterop>
</PropertyGroup>
<Import Project="..\..\build\BuildTargets.targets" />
</Project>

7
src/Avalonia.Native/AvaloniaNativeMenuExporter.cs

@ -4,6 +4,7 @@ using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Controls.Platform;
using Avalonia.Dialogs;
using Avalonia.Native.Interop;
using Avalonia.Native.Interop.Impl;
using Avalonia.Threading;
namespace Avalonia.Native
@ -15,7 +16,7 @@ namespace Avalonia.Native
private bool _exported = false;
private IAvnWindow _nativeWindow;
private NativeMenu _menu;
private IAvnMenu _nativeMenu;
private __MicroComIAvnMenuProxy _nativeMenu;
public AvaloniaNativeMenuExporter(IAvnWindow nativeWindow, IAvaloniaNativeFactory factory)
{
@ -135,7 +136,7 @@ namespace Avalonia.Native
if (_nativeMenu is null)
{
_nativeMenu = IAvnMenu.Create(_factory);
_nativeMenu = (__MicroComIAvnMenuProxy)__MicroComIAvnMenuProxy.Create(_factory);
_nativeMenu.Initialise(this, appMenuHolder, "");
@ -156,7 +157,7 @@ namespace Avalonia.Native
if (_nativeMenu is null)
{
_nativeMenu = IAvnMenu.Create(_factory);
_nativeMenu = __MicroComIAvnMenuProxy.Create(_factory);
_nativeMenu.Initialise(this, menu, "");

12
src/Avalonia.Native/AvaloniaNativePlatform.cs

@ -4,6 +4,7 @@ using System.Security.Cryptography;
using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Input.Platform;
using Avalonia.MicroCom;
using Avalonia.Native.Interop;
using Avalonia.OpenGL;
using Avalonia.Platform;
@ -29,7 +30,7 @@ namespace Avalonia.Native
public static AvaloniaNativePlatform Initialize(IntPtr factory, AvaloniaNativePlatformOptions options)
{
var result = new AvaloniaNativePlatform(new IAvaloniaNativeFactory(factory));
var result = new AvaloniaNativePlatform(MicroComRuntime.CreateProxyFor<IAvaloniaNativeFactory>(factory, true));
result.DoInitialize(options);
return result;
@ -65,10 +66,7 @@ namespace Avalonia.Native
{
if(!string.IsNullOrWhiteSpace(Application.Current.Name))
{
using (var buffer = new Utf8Buffer(Application.Current.Name))
{
_factory.MacOptions.SetApplicationTitle(buffer.DangerousGetHandle());
}
_factory.MacOptions.SetApplicationTitle(Application.Current.Name);
}
}
@ -93,7 +91,7 @@ namespace Avalonia.Native
{
var macOpts = AvaloniaLocator.Current.GetService<MacOSPlatformOptions>();
_factory.MacOptions.ShowInDock = macOpts?.ShowInDock != false ? 1 : 0;
_factory.MacOptions.SetShowInDock(macOpts?.ShowInDock != false ? 1 : 0);
}
AvaloniaLocator.CurrentMutable
@ -153,7 +151,7 @@ namespace Avalonia.Native
set
{
_showInDock = value;
_opts.ShowInDock = value ? 1 : 0;
_opts.SetShowInDock(value ? 1 : 0);
}
}
}

4
src/Avalonia.Native/AvaloniaNativePlatformOpenGlInterface.cs

@ -150,12 +150,12 @@ namespace Avalonia.Native
{
get
{
var s = _session.GetPixelSize();
var s = _session.PixelSize;
return new PixelSize(s.Width, s.Height);
}
}
public double Scaling => _session.GetScaling();
public double Scaling => _session.Scaling;
public bool IsYFlipped => true;

22
src/Avalonia.Native/AvnString.cs

@ -1,8 +1,22 @@
using System;
using System.Runtime.InteropServices;
namespace Avalonia.Native.Interop
{
unsafe partial class IAvnString
partial interface IAvnString
{
public string String { get; }
public byte[] Bytes { get; }
}
partial interface IAvnStringArray
{
string[] ToStringArray();
}
}
namespace Avalonia.Native.Interop.Impl
{
unsafe partial class __MicroComIAvnStringProxy
{
private string _managed;
private byte[] _bytes;
@ -16,7 +30,7 @@ namespace Avalonia.Native.Interop
var ptr = Pointer();
if (ptr == null)
return null;
_managed = System.Text.Encoding.UTF8.GetString((byte*)ptr.ToPointer(), Length());
_managed = System.Text.Encoding.UTF8.GetString((byte*)ptr, Length());
}
return _managed;
@ -30,7 +44,7 @@ namespace Avalonia.Native.Interop
if (_bytes == null)
{
_bytes = new byte[Length()];
Marshal.Copy(Pointer(), _bytes, 0, _bytes.Length);
Marshal.Copy(new IntPtr(Pointer()), _bytes, 0, _bytes.Length);
}
return _bytes;
@ -40,7 +54,7 @@ namespace Avalonia.Native.Interop
public override string ToString() => String;
}
partial class IAvnStringArray
partial class __MicroComIAvnStringArrayProxy
{
public string[] ToStringArray()
{

78
src/Avalonia.Native/CallbackBase.cs

@ -1,44 +1,30 @@
using System;
using System.Runtime.ExceptionServices;
using SharpGen.Runtime;
using Avalonia.MicroCom;
using Avalonia.Platform;
namespace Avalonia.Native
{
public class CallbackBase : SharpGen.Runtime.IUnknown, IExceptionCallback
public class CallbackBase : IUnknown, IMicroComShadowContainer, IMicroComExceptionCallback
{
private uint _refCount;
private bool _disposed;
private readonly object _lock = new object();
private ShadowContainer _shadow;
private bool _referencedFromManaged = true;
private bool _referencedFromNative = false;
private bool _destroyed;
public CallbackBase()
{
_refCount = 1;
}
public ShadowContainer Shadow
protected virtual void Destroyed()
{
get => _shadow;
set
{
lock (_lock)
{
if (_disposed && value != null)
{
throw new ObjectDisposedException("CallbackBase");
}
_shadow = value;
}
}
}
public uint AddRef()
public void RaiseException(Exception e)
{
lock (_lock)
if (AvaloniaLocator.Current.GetService<IPlatformThreadingInterface>() is PlatformThreadingInterface threadingInterface)
{
return ++_refCount;
threadingInterface.TerminateNativeApp();
threadingInterface.DispatchException(ExceptionDispatchInfo.Capture(e));
}
}
@ -46,43 +32,35 @@ namespace Avalonia.Native
{
lock (_lock)
{
if (!_disposed)
{
_disposed = true;
Release();
}
_referencedFromManaged = false;
DestroyIfNeeded();
}
}
public uint Release()
void DestroyIfNeeded()
{
lock (_lock)
if(_destroyed)
return;
if (_referencedFromManaged == false && _referencedFromNative == false)
{
_refCount--;
if (_refCount == 0)
{
Shadow?.Dispose();
Shadow = null;
Destroyed();
}
return _refCount;
_destroyed = true;
Destroyed();
}
}
protected virtual void Destroyed()
public MicroComShadow Shadow { get; set; }
public void OnReferencedFromNative()
{
lock (_lock)
_referencedFromNative = true;
}
public void RaiseException(Exception e)
public void OnUnreferencedFromNative()
{
if (AvaloniaLocator.Current.GetService<IPlatformThreadingInterface>() is PlatformThreadingInterface threadingInterface)
lock (_lock)
{
threadingInterface.TerminateNativeApp();
threadingInterface.DispatchException(ExceptionDispatchInfo.Capture(e));
_referencedFromNative = false;
DestroyIfNeeded();
}
}
}

16
src/Avalonia.Native/ClipboardImpl.cs

@ -35,17 +35,12 @@ namespace Avalonia.Native
return Task.FromResult(text.String);
}
public Task SetTextAsync(string text)
public unsafe Task SetTextAsync(string text)
{
_native.Clear();
if (text != null)
{
using (var buffer = new Utf8Buffer(text))
{
_native.SetText(NSPasteboardTypeString, buffer.DangerousGetHandle());
}
}
if (text != null)
_native.SetText(NSPasteboardTypeString, text);
return Task.CompletedTask;
}
@ -90,11 +85,10 @@ namespace Avalonia.Native
{
var o = data.Get(fmt);
if(o is string s)
using (var b = new Utf8Buffer(s))
_native.SetText(fmt, b.DangerousGetHandle());
_native.SetText(fmt, s);
else if(o is byte[] bytes)
fixed (byte* pbytes = bytes)
_native.SetBytes(fmt, new IntPtr(pbytes), bytes.Length);
_native.SetBytes(fmt, pbytes, bytes.Length);
}
return Task.CompletedTask;
}

7
src/Avalonia.Native/DeferredFramebuffer.cs

@ -2,11 +2,10 @@
using System.Runtime.InteropServices;
using Avalonia.Native.Interop;
using Avalonia.Platform;
using SharpGen.Runtime;
namespace Avalonia.Native
{
public class DeferredFramebuffer : ILockedFramebuffer
internal unsafe class DeferredFramebuffer : ILockedFramebuffer
{
private readonly Func<Action<IAvnWindowBase>, bool> _lockWindow;
@ -56,7 +55,7 @@ namespace Avalonia.Native
{
var fb = new AvnFramebuffer
{
Data = Address,
Data = Address.ToPointer(),
Dpi = new AvnVector
{
X = Dpi.X,
@ -70,7 +69,7 @@ namespace Avalonia.Native
using (var d = new Disposer(Address))
{
win.ThreadSafeSetSwRenderedFrame(ref fb, d);
win.ThreadSafeSetSwRenderedFrame(&fb, d);
}
}))
{

628
src/Avalonia.Native/Generated/Enumerations.cs

@ -1,628 +0,0 @@
// <auto-generated/>
namespace Avalonia.Native.Interop
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnDragDropEffects</unmanaged>
/// <unmanaged-short>AvnDragDropEffects</unmanaged-short>
public enum AvnDragDropEffects : System.Int32
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>None</unmanaged>
/// <unmanaged-short>None</unmanaged-short>
None = unchecked ((System.Int32)(0)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Copy</unmanaged>
/// <unmanaged-short>Copy</unmanaged-short>
Copy = unchecked ((System.Int32)(1)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Move</unmanaged>
/// <unmanaged-short>Move</unmanaged-short>
Move = unchecked ((System.Int32)(2)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Link</unmanaged>
/// <unmanaged-short>Link</unmanaged-short>
Link = unchecked ((System.Int32)(4))}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnDragEventType</unmanaged>
/// <unmanaged-short>AvnDragEventType</unmanaged-short>
public enum AvnDragEventType : System.Int32
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Enter</unmanaged>
/// <unmanaged-short>Enter</unmanaged-short>
Enter = unchecked ((System.Int32)(0)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Over</unmanaged>
/// <unmanaged-short>Over</unmanaged-short>
Over = unchecked ((System.Int32)(1)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Leave</unmanaged>
/// <unmanaged-short>Leave</unmanaged-short>
Leave = unchecked ((System.Int32)(2)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Drop</unmanaged>
/// <unmanaged-short>Drop</unmanaged-short>
Drop = unchecked ((System.Int32)(3))}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnExtendClientAreaChromeHints</unmanaged>
/// <unmanaged-short>AvnExtendClientAreaChromeHints</unmanaged-short>
public enum AvnExtendClientAreaChromeHints : System.Int32
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnNoChrome</unmanaged>
/// <unmanaged-short>AvnNoChrome</unmanaged-short>
AvnNoChrome = unchecked ((System.Int32)(0)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnSystemChrome</unmanaged>
/// <unmanaged-short>AvnSystemChrome</unmanaged-short>
AvnSystemChrome = unchecked ((System.Int32)(1)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnPreferSystemChrome</unmanaged>
/// <unmanaged-short>AvnPreferSystemChrome</unmanaged-short>
AvnPreferSystemChrome = unchecked ((System.Int32)(2)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnOSXThickTitleBar</unmanaged>
/// <unmanaged-short>AvnOSXThickTitleBar</unmanaged-short>
AvnOSXThickTitleBar = unchecked ((System.Int32)(8)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnDefaultChrome</unmanaged>
/// <unmanaged-short>AvnDefaultChrome</unmanaged-short>
AvnDefaultChrome = unchecked ((System.Int32)(1))}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnInputModifiers</unmanaged>
/// <unmanaged-short>AvnInputModifiers</unmanaged-short>
public enum AvnInputModifiers : System.Int32
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnInputModifiersNone</unmanaged>
/// <unmanaged-short>AvnInputModifiersNone</unmanaged-short>
AvnInputModifiersNone = unchecked ((System.Int32)(0)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Alt</unmanaged>
/// <unmanaged-short>Alt</unmanaged-short>
Alt = unchecked ((System.Int32)(1)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Control</unmanaged>
/// <unmanaged-short>Control</unmanaged-short>
Control = unchecked ((System.Int32)(2)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Shift</unmanaged>
/// <unmanaged-short>Shift</unmanaged-short>
Shift = unchecked ((System.Int32)(4)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Windows</unmanaged>
/// <unmanaged-short>Windows</unmanaged-short>
Windows = unchecked ((System.Int32)(8)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>LeftMouseButton</unmanaged>
/// <unmanaged-short>LeftMouseButton</unmanaged-short>
LeftMouseButton = unchecked ((System.Int32)(16)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>RightMouseButton</unmanaged>
/// <unmanaged-short>RightMouseButton</unmanaged-short>
RightMouseButton = unchecked ((System.Int32)(32)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>MiddleMouseButton</unmanaged>
/// <unmanaged-short>MiddleMouseButton</unmanaged-short>
MiddleMouseButton = unchecked ((System.Int32)(64)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>XButton1MouseButton</unmanaged>
/// <unmanaged-short>XButton1MouseButton</unmanaged-short>
XButton1MouseButton = unchecked ((System.Int32)(128)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>XButton2MouseButton</unmanaged>
/// <unmanaged-short>XButton2MouseButton</unmanaged-short>
XButton2MouseButton = unchecked ((System.Int32)(256))}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnMenuItemToggleType</unmanaged>
/// <unmanaged-short>AvnMenuItemToggleType</unmanaged-short>
public enum AvnMenuItemToggleType : System.Int32
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>None</unmanaged>
/// <unmanaged-short>None</unmanaged-short>
None = unchecked ((System.Int32)(0)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CheckMark</unmanaged>
/// <unmanaged-short>CheckMark</unmanaged-short>
CheckMark = unchecked ((System.Int32)(1)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Radio</unmanaged>
/// <unmanaged-short>Radio</unmanaged-short>
Radio = unchecked ((System.Int32)(2))}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnPixelFormat</unmanaged>
/// <unmanaged-short>AvnPixelFormat</unmanaged-short>
public enum AvnPixelFormat : System.Int32
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>kAvnRgb565</unmanaged>
/// <unmanaged-short>kAvnRgb565</unmanaged-short>
KAvnRgb565 = unchecked ((System.Int32)(0)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>kAvnRgba8888</unmanaged>
/// <unmanaged-short>kAvnRgba8888</unmanaged-short>
KAvnRgba8888 = unchecked ((System.Int32)(1)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>kAvnBgra8888</unmanaged>
/// <unmanaged-short>kAvnBgra8888</unmanaged-short>
KAvnBgra8888 = unchecked ((System.Int32)(2))}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnRawKeyEventType</unmanaged>
/// <unmanaged-short>AvnRawKeyEventType</unmanaged-short>
public enum AvnRawKeyEventType : System.Int32
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>KeyDown</unmanaged>
/// <unmanaged-short>KeyDown</unmanaged-short>
KeyDown = unchecked ((System.Int32)(0)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>KeyUp</unmanaged>
/// <unmanaged-short>KeyUp</unmanaged-short>
KeyUp = unchecked ((System.Int32)(1))}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnRawMouseEventType</unmanaged>
/// <unmanaged-short>AvnRawMouseEventType</unmanaged-short>
public enum AvnRawMouseEventType : System.Int32
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>LeaveWindow</unmanaged>
/// <unmanaged-short>LeaveWindow</unmanaged-short>
LeaveWindow = unchecked ((System.Int32)(0)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>LeftButtonDown</unmanaged>
/// <unmanaged-short>LeftButtonDown</unmanaged-short>
LeftButtonDown = unchecked ((System.Int32)(1)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>LeftButtonUp</unmanaged>
/// <unmanaged-short>LeftButtonUp</unmanaged-short>
LeftButtonUp = unchecked ((System.Int32)(2)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>RightButtonDown</unmanaged>
/// <unmanaged-short>RightButtonDown</unmanaged-short>
RightButtonDown = unchecked ((System.Int32)(3)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>RightButtonUp</unmanaged>
/// <unmanaged-short>RightButtonUp</unmanaged-short>
RightButtonUp = unchecked ((System.Int32)(4)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>MiddleButtonDown</unmanaged>
/// <unmanaged-short>MiddleButtonDown</unmanaged-short>
MiddleButtonDown = unchecked ((System.Int32)(5)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>MiddleButtonUp</unmanaged>
/// <unmanaged-short>MiddleButtonUp</unmanaged-short>
MiddleButtonUp = unchecked ((System.Int32)(6)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>XButton1Down</unmanaged>
/// <unmanaged-short>XButton1Down</unmanaged-short>
XButton1Down = unchecked ((System.Int32)(7)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>XButton1Up</unmanaged>
/// <unmanaged-short>XButton1Up</unmanaged-short>
XButton1Up = unchecked ((System.Int32)(8)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>XButton2Down</unmanaged>
/// <unmanaged-short>XButton2Down</unmanaged-short>
XButton2Down = unchecked ((System.Int32)(9)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>XButton2Up</unmanaged>
/// <unmanaged-short>XButton2Up</unmanaged-short>
XButton2Up = unchecked ((System.Int32)(10)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Move</unmanaged>
/// <unmanaged-short>Move</unmanaged-short>
Move = unchecked ((System.Int32)(11)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Wheel</unmanaged>
/// <unmanaged-short>Wheel</unmanaged-short>
Wheel = unchecked ((System.Int32)(12)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>NonClientLeftButtonDown</unmanaged>
/// <unmanaged-short>NonClientLeftButtonDown</unmanaged-short>
NonClientLeftButtonDown = unchecked ((System.Int32)(13)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>TouchBegin</unmanaged>
/// <unmanaged-short>TouchBegin</unmanaged-short>
TouchBegin = unchecked ((System.Int32)(14)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>TouchUpdate</unmanaged>
/// <unmanaged-short>TouchUpdate</unmanaged-short>
TouchUpdate = unchecked ((System.Int32)(15)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>TouchEnd</unmanaged>
/// <unmanaged-short>TouchEnd</unmanaged-short>
TouchEnd = unchecked ((System.Int32)(16)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>TouchCancel</unmanaged>
/// <unmanaged-short>TouchCancel</unmanaged-short>
TouchCancel = unchecked ((System.Int32)(17))}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnStandardCursorType</unmanaged>
/// <unmanaged-short>AvnStandardCursorType</unmanaged-short>
public enum AvnStandardCursorType : System.Int32
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorArrow</unmanaged>
/// <unmanaged-short>CursorArrow</unmanaged-short>
CursorArrow = unchecked ((System.Int32)(0)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorIbeam</unmanaged>
/// <unmanaged-short>CursorIbeam</unmanaged-short>
CursorIbeam = unchecked ((System.Int32)(1)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorWait</unmanaged>
/// <unmanaged-short>CursorWait</unmanaged-short>
CursorWait = unchecked ((System.Int32)(2)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorCross</unmanaged>
/// <unmanaged-short>CursorCross</unmanaged-short>
CursorCross = unchecked ((System.Int32)(3)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorUpArrow</unmanaged>
/// <unmanaged-short>CursorUpArrow</unmanaged-short>
CursorUpArrow = unchecked ((System.Int32)(4)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorSizeWestEast</unmanaged>
/// <unmanaged-short>CursorSizeWestEast</unmanaged-short>
CursorSizeWestEast = unchecked ((System.Int32)(5)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorSizeNorthSouth</unmanaged>
/// <unmanaged-short>CursorSizeNorthSouth</unmanaged-short>
CursorSizeNorthSouth = unchecked ((System.Int32)(6)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorSizeAll</unmanaged>
/// <unmanaged-short>CursorSizeAll</unmanaged-short>
CursorSizeAll = unchecked ((System.Int32)(7)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorNo</unmanaged>
/// <unmanaged-short>CursorNo</unmanaged-short>
CursorNo = unchecked ((System.Int32)(8)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorHand</unmanaged>
/// <unmanaged-short>CursorHand</unmanaged-short>
CursorHand = unchecked ((System.Int32)(9)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorAppStarting</unmanaged>
/// <unmanaged-short>CursorAppStarting</unmanaged-short>
CursorAppStarting = unchecked ((System.Int32)(10)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorHelp</unmanaged>
/// <unmanaged-short>CursorHelp</unmanaged-short>
CursorHelp = unchecked ((System.Int32)(11)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorTopSide</unmanaged>
/// <unmanaged-short>CursorTopSide</unmanaged-short>
CursorTopSide = unchecked ((System.Int32)(12)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorBottomSize</unmanaged>
/// <unmanaged-short>CursorBottomSize</unmanaged-short>
CursorBottomSize = unchecked ((System.Int32)(13)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorLeftSide</unmanaged>
/// <unmanaged-short>CursorLeftSide</unmanaged-short>
CursorLeftSide = unchecked ((System.Int32)(14)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorRightSide</unmanaged>
/// <unmanaged-short>CursorRightSide</unmanaged-short>
CursorRightSide = unchecked ((System.Int32)(15)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorTopLeftCorner</unmanaged>
/// <unmanaged-short>CursorTopLeftCorner</unmanaged-short>
CursorTopLeftCorner = unchecked ((System.Int32)(16)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorTopRightCorner</unmanaged>
/// <unmanaged-short>CursorTopRightCorner</unmanaged-short>
CursorTopRightCorner = unchecked ((System.Int32)(17)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorBottomLeftCorner</unmanaged>
/// <unmanaged-short>CursorBottomLeftCorner</unmanaged-short>
CursorBottomLeftCorner = unchecked ((System.Int32)(18)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorBottomRightCorner</unmanaged>
/// <unmanaged-short>CursorBottomRightCorner</unmanaged-short>
CursorBottomRightCorner = unchecked ((System.Int32)(19)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorDragMove</unmanaged>
/// <unmanaged-short>CursorDragMove</unmanaged-short>
CursorDragMove = unchecked ((System.Int32)(20)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorDragCopy</unmanaged>
/// <unmanaged-short>CursorDragCopy</unmanaged-short>
CursorDragCopy = unchecked ((System.Int32)(21)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorDragLink</unmanaged>
/// <unmanaged-short>CursorDragLink</unmanaged-short>
CursorDragLink = unchecked ((System.Int32)(22)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>CursorNone</unmanaged>
/// <unmanaged-short>CursorNone</unmanaged-short>
CursorNone = unchecked ((System.Int32)(23))}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnWindowEdge</unmanaged>
/// <unmanaged-short>AvnWindowEdge</unmanaged-short>
public enum AvnWindowEdge : System.Int32
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>WindowEdgeNorthWest</unmanaged>
/// <unmanaged-short>WindowEdgeNorthWest</unmanaged-short>
WindowEdgeNorthWest = unchecked ((System.Int32)(0)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>WindowEdgeNorth</unmanaged>
/// <unmanaged-short>WindowEdgeNorth</unmanaged-short>
WindowEdgeNorth = unchecked ((System.Int32)(1)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>WindowEdgeNorthEast</unmanaged>
/// <unmanaged-short>WindowEdgeNorthEast</unmanaged-short>
WindowEdgeNorthEast = unchecked ((System.Int32)(2)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>WindowEdgeWest</unmanaged>
/// <unmanaged-short>WindowEdgeWest</unmanaged-short>
WindowEdgeWest = unchecked ((System.Int32)(3)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>WindowEdgeEast</unmanaged>
/// <unmanaged-short>WindowEdgeEast</unmanaged-short>
WindowEdgeEast = unchecked ((System.Int32)(4)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>WindowEdgeSouthWest</unmanaged>
/// <unmanaged-short>WindowEdgeSouthWest</unmanaged-short>
WindowEdgeSouthWest = unchecked ((System.Int32)(5)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>WindowEdgeSouth</unmanaged>
/// <unmanaged-short>WindowEdgeSouth</unmanaged-short>
WindowEdgeSouth = unchecked ((System.Int32)(6)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>WindowEdgeSouthEast</unmanaged>
/// <unmanaged-short>WindowEdgeSouthEast</unmanaged-short>
WindowEdgeSouthEast = unchecked ((System.Int32)(7))}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnWindowState</unmanaged>
/// <unmanaged-short>AvnWindowState</unmanaged-short>
public enum AvnWindowState : System.Int32
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Normal</unmanaged>
/// <unmanaged-short>Normal</unmanaged-short>
Normal = unchecked ((System.Int32)(0)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Minimized</unmanaged>
/// <unmanaged-short>Minimized</unmanaged-short>
Minimized = unchecked ((System.Int32)(1)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Maximized</unmanaged>
/// <unmanaged-short>Maximized</unmanaged-short>
Maximized = unchecked ((System.Int32)(2)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>FullScreen</unmanaged>
/// <unmanaged-short>FullScreen</unmanaged-short>
FullScreen = unchecked ((System.Int32)(3))}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>SystemDecorations</unmanaged>
/// <unmanaged-short>SystemDecorations</unmanaged-short>
public enum SystemDecorations : System.Int32
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>SystemDecorationsNone</unmanaged>
/// <unmanaged-short>SystemDecorationsNone</unmanaged-short>
SystemDecorationsNone = unchecked ((System.Int32)(0)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>SystemDecorationsBorderOnly</unmanaged>
/// <unmanaged-short>SystemDecorationsBorderOnly</unmanaged-short>
SystemDecorationsBorderOnly = unchecked ((System.Int32)(1)),
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>SystemDecorationsFull</unmanaged>
/// <unmanaged-short>SystemDecorationsFull</unmanaged-short>
SystemDecorationsFull = unchecked ((System.Int32)(2))}
}

5
src/Avalonia.Native/Generated/Functions.cs

@ -1,5 +0,0 @@
// <auto-generated/>
namespace Avalonia.Native.Interop
{
}

3092
src/Avalonia.Native/Generated/Interfaces.cs

File diff suppressed because it is too large

202
src/Avalonia.Native/Generated/LocalInterop.cs

@ -1,202 +0,0 @@
// <auto-generated/>
namespace Avalonia.Native
{
internal static partial class LocalInterop
{
public static unsafe int CalliThisCallint(void *thisObject, void *methodPtr)
{
throw null;
}
public static unsafe void CalliThisCallvoid(void *thisObject, void *methodPtr)
{
throw null;
}
public static unsafe void CalliThisCallvoid(void *thisObject, void *param0, void *methodPtr)
{
throw null;
}
public static unsafe void CalliThisCallvoid0(void *thisObject, Avalonia.Native.Interop.AvnPoint param0, void *methodPtr)
{
throw null;
}
public static unsafe void CalliThisCallvoid0(void *thisObject, int param0, System.UInt32 param1, int param2, Avalonia.Native.Interop.AvnPoint param3, Avalonia.Native.Interop.AvnVector param4, void *methodPtr)
{
throw null;
}
public static unsafe System.Byte CalliThisCallSystemByte(void *thisObject, int param0, System.UInt32 param1, int param2, System.UInt32 param3, void *methodPtr)
{
throw null;
}
public static unsafe System.Byte CalliThisCallSystemByte(void *thisObject, System.UInt32 param0, void *param1, void *methodPtr)
{
throw null;
}
public static unsafe void CalliThisCallvoid(void *thisObject, double param0, void *methodPtr)
{
throw null;
}
public static unsafe Avalonia.Native.Interop.AvnDragDropEffects CalliThisCallAvaloniaNativeInteropAvnDragDropEffects0(void *thisObject, int param0, Avalonia.Native.Interop.AvnPoint param1, int param2, int param3, void *param4, void *param5, void *methodPtr)
{
throw null;
}
public static unsafe System.Byte CalliThisCallSystemByte(void *thisObject, void *methodPtr)
{
throw null;
}
public static unsafe void CalliThisCallvoid(void *thisObject, int param0, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint(void *thisObject, void *param0, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint0(void *thisObject, Avalonia.Native.Interop.AvnSize param0, Avalonia.Native.Interop.AvnSize param1, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint(void *thisObject, double param0, double param1, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint0(void *thisObject, Avalonia.Native.Interop.AvnRect param0, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint(void *thisObject, int param0, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint0(void *thisObject, Avalonia.Native.Interop.AvnPoint param0, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint0(void *thisObject, Avalonia.Native.Interop.AvnPoint param0, void *param1, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint(void *thisObject, void *param0, void *param1, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint(void *thisObject, System.Byte param0, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint0(void *thisObject, int param0, Avalonia.Native.Interop.AvnPoint param1, void *param2, void *param3, void *param4, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint0(void *thisObject, Avalonia.Native.Interop.AvnColor param0, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint(void *thisObject, double param0, void *methodPtr)
{
throw null;
}
public static unsafe System.IntPtr CalliThisCallSystemIntPtr(void *thisObject, void *methodPtr)
{
throw null;
}
public static unsafe System.IntPtr CalliThisCallSystemIntPtr(void *thisObject, int param0, int param1, void *param2, void *methodPtr)
{
throw null;
}
public static unsafe void CalliThisCallvoid(void *thisObject, int param0, void *param1, void *methodPtr)
{
throw null;
}
public static unsafe void CalliThisCallvoid(void *thisObject, void *param0, void *param1, void *param2, void *param3, void *methodPtr)
{
throw null;
}
public static unsafe void CalliThisCallvoid(void *thisObject, void *param0, void *param1, System.Byte param2, void *param3, void *param4, void *param5, void *param6, void *methodPtr)
{
throw null;
}
public static unsafe void CalliThisCallvoid(void *thisObject, void *param0, void *param1, void *param2, void *param3, void *param4, void *param5, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint(void *thisObject, int param0, void *param1, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint(void *thisObject, void *param0, void *param1, int param2, void *methodPtr)
{
throw null;
}
public static unsafe System.IntPtr CalliThisCallSystemIntPtr(void *thisObject, void *param0, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint(void *thisObject, void *param0, int param1, void *methodPtr)
{
throw null;
}
public static unsafe System.UInt32 CalliThisCallSystemUInt32(void *thisObject, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint(void *thisObject, System.UInt32 param0, void *param1, void *methodPtr)
{
throw null;
}
public static unsafe void CalliThisCallvoid(void *thisObject, float param0, float param1, float param2, float param3, void *methodPtr)
{
throw null;
}
public static unsafe void CalliThisCallvoid(void *thisObject, float param0, float param1, void *methodPtr)
{
throw null;
}
public static unsafe int CalliThisCallint(void *thisObject, void *param0, void *param1, void *param2, void *methodPtr)
{
throw null;
}
public static unsafe void CalliThisCallvoid(void *thisObject, int param0, System.Byte param1, void *methodPtr)
{
throw null;
}
}
}

246
src/Avalonia.Native/Generated/Structures.cs

@ -1,246 +0,0 @@
// <auto-generated/>
namespace Avalonia.Native.Interop
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnColor</unmanaged>
/// <unmanaged-short>AvnColor</unmanaged-short>
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
public partial struct AvnColor
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Alpha</unmanaged>
/// <unmanaged-short>Alpha</unmanaged-short>
public System.Byte Alpha;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Red</unmanaged>
/// <unmanaged-short>Red</unmanaged-short>
public System.Byte Red;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Green</unmanaged>
/// <unmanaged-short>Green</unmanaged-short>
public System.Byte Green;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Blue</unmanaged>
/// <unmanaged-short>Blue</unmanaged-short>
public System.Byte Blue;
}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnFramebuffer</unmanaged>
/// <unmanaged-short>AvnFramebuffer</unmanaged-short>
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
public partial struct AvnFramebuffer
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Data</unmanaged>
/// <unmanaged-short>Data</unmanaged-short>
public System.IntPtr Data;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Width</unmanaged>
/// <unmanaged-short>Width</unmanaged-short>
public System.Int32 Width;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Height</unmanaged>
/// <unmanaged-short>Height</unmanaged-short>
public System.Int32 Height;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Stride</unmanaged>
/// <unmanaged-short>Stride</unmanaged-short>
public System.Int32 Stride;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Dpi</unmanaged>
/// <unmanaged-short>Dpi</unmanaged-short>
public Avalonia.Native.Interop.AvnVector Dpi;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>PixelFormat</unmanaged>
/// <unmanaged-short>PixelFormat</unmanaged-short>
public Avalonia.Native.Interop.AvnPixelFormat PixelFormat;
}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnPixelSize</unmanaged>
/// <unmanaged-short>AvnPixelSize</unmanaged-short>
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
public partial struct AvnPixelSize
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Width</unmanaged>
/// <unmanaged-short>Width</unmanaged-short>
public System.Int32 Width;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Height</unmanaged>
/// <unmanaged-short>Height</unmanaged-short>
public System.Int32 Height;
}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnPoint</unmanaged>
/// <unmanaged-short>AvnPoint</unmanaged-short>
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
public partial struct AvnPoint
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>X</unmanaged>
/// <unmanaged-short>X</unmanaged-short>
public System.Double X;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Y</unmanaged>
/// <unmanaged-short>Y</unmanaged-short>
public System.Double Y;
}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnRect</unmanaged>
/// <unmanaged-short>AvnRect</unmanaged-short>
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
public partial struct AvnRect
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>X</unmanaged>
/// <unmanaged-short>X</unmanaged-short>
public System.Double X;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Y</unmanaged>
/// <unmanaged-short>Y</unmanaged-short>
public System.Double Y;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Width</unmanaged>
/// <unmanaged-short>Width</unmanaged-short>
public System.Double Width;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Height</unmanaged>
/// <unmanaged-short>Height</unmanaged-short>
public System.Double Height;
}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnScreen</unmanaged>
/// <unmanaged-short>AvnScreen</unmanaged-short>
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
public partial struct AvnScreen
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Bounds</unmanaged>
/// <unmanaged-short>Bounds</unmanaged-short>
public Avalonia.Native.Interop.AvnRect Bounds;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>WorkingArea</unmanaged>
/// <unmanaged-short>WorkingArea</unmanaged-short>
public Avalonia.Native.Interop.AvnRect WorkingArea;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>PixelDensity</unmanaged>
/// <unmanaged-short>PixelDensity</unmanaged-short>
public System.Single PixelDensity;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Primary</unmanaged>
/// <unmanaged-short>Primary</unmanaged-short>
public bool Primary
{
get => 0 != _Primary;
set => _Primary = (System.Byte)(value ? 1 : 0);
}
internal System.Byte _Primary;
}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnSize</unmanaged>
/// <unmanaged-short>AvnSize</unmanaged-short>
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
public partial struct AvnSize
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Width</unmanaged>
/// <unmanaged-short>Width</unmanaged-short>
public System.Double Width;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Height</unmanaged>
/// <unmanaged-short>Height</unmanaged-short>
public System.Double Height;
}
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>AvnVector</unmanaged>
/// <unmanaged-short>AvnVector</unmanaged-short>
[System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential, Pack = 0, CharSet = System.Runtime.InteropServices.CharSet.Unicode)]
public partial struct AvnVector
{
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>X</unmanaged>
/// <unmanaged-short>X</unmanaged-short>
public System.Double X;
/// <summary>
/// No documentation.
/// </summary>
/// <unmanaged>Y</unmanaged>
/// <unmanaged-short>Y</unmanaged-short>
public System.Double Y;
}
}

2
src/Avalonia.Native/Helpers.cs

@ -2,7 +2,7 @@
namespace Avalonia.Native
{
public static class Helpers
internal static class Helpers
{
public static Point ToAvaloniaPoint (this AvnPoint pt)
{

45
src/Avalonia.Native/IAvnMenu.cs

@ -22,15 +22,23 @@ namespace Avalonia.Native.Interop
}
}
public partial class IAvnMenu
partial interface IAvnMenu
{
void RaiseNeedsUpdate();
void Deinitialise();
}
}
namespace Avalonia.Native.Interop.Impl
{
partial class __MicroComIAvnMenuProxy
{
private MenuEvents _events;
private AvaloniaNativeMenuExporter _exporter;
private List<IAvnMenuItem> _menuItems = new List<IAvnMenuItem>();
private Dictionary<NativeMenuItemBase, IAvnMenuItem> _menuItemLookup = new Dictionary<NativeMenuItemBase, IAvnMenuItem>();
private List<__MicroComIAvnMenuItemProxy> _menuItems = new List<__MicroComIAvnMenuItemProxy>();
private Dictionary<NativeMenuItemBase, __MicroComIAvnMenuItemProxy> _menuItemLookup = new Dictionary<NativeMenuItemBase, __MicroComIAvnMenuItemProxy>();
private CompositeDisposable _propertyDisposables = new CompositeDisposable();
internal void RaiseNeedsUpdate()
public void RaiseNeedsUpdate()
{
(ManagedMenu as INativeMenuExporterEventsImplBridge).RaiseNeedsUpdate();
@ -39,11 +47,11 @@ namespace Avalonia.Native.Interop
internal NativeMenu ManagedMenu { get; private set; }
public static IAvnMenu Create(IAvaloniaNativeFactory factory)
public static __MicroComIAvnMenuProxy Create(IAvaloniaNativeFactory factory)
{
var events = new MenuEvents();
var menu = factory.CreateMenu(events);
var menu = (__MicroComIAvnMenuProxy)factory.CreateMenu(events);
events.Initialise(menu);
@ -60,7 +68,7 @@ namespace Avalonia.Native.Interop
}
}
private void RemoveAndDispose(IAvnMenuItem item)
private void RemoveAndDispose(__MicroComIAvnMenuItemProxy item)
{
_menuItemLookup.Remove(item.ManagedMenuItem);
_menuItems.Remove(item);
@ -70,7 +78,7 @@ namespace Avalonia.Native.Interop
item.Dispose();
}
private void MoveExistingTo(int index, IAvnMenuItem item)
private void MoveExistingTo(int index, __MicroComIAvnMenuItemProxy item)
{
_menuItems.Remove(item);
_menuItems.Insert(index, item);
@ -79,7 +87,7 @@ namespace Avalonia.Native.Interop
InsertItem(index, item);
}
private IAvnMenuItem CreateNewAt(IAvaloniaNativeFactory factory, int index, NativeMenuItemBase item)
private __MicroComIAvnMenuItemProxy CreateNewAt(IAvaloniaNativeFactory factory, int index, NativeMenuItemBase item)
{
var result = CreateNew(factory, item);
@ -93,9 +101,11 @@ namespace Avalonia.Native.Interop
return result;
}
private IAvnMenuItem CreateNew(IAvaloniaNativeFactory factory, NativeMenuItemBase item)
private __MicroComIAvnMenuItemProxy CreateNew(IAvaloniaNativeFactory factory, NativeMenuItemBase item)
{
var nativeItem = item is NativeMenuItemSeperator ? factory.CreateMenuItemSeperator() : factory.CreateMenuItem();
var nativeItem = (__MicroComIAvnMenuItemProxy)(item is NativeMenuItemSeperator ?
factory.CreateMenuItemSeperator() :
factory.CreateMenuItem());
nativeItem.ManagedMenuItem = item;
return nativeItem;
@ -108,16 +118,11 @@ namespace Avalonia.Native.Interop
((INotifyCollectionChanged)ManagedMenu.Items).CollectionChanged += OnMenuItemsChanged;
if (!string.IsNullOrWhiteSpace(title))
{
using (var buffer = new Utf8Buffer(title))
{
Title = buffer.DangerousGetHandle();
}
}
if (!string.IsNullOrWhiteSpace(title))
SetTitle(title);
}
internal void Deinitialise()
public void Deinitialise()
{
((INotifyCollectionChanged)ManagedMenu.Items).CollectionChanged -= OnMenuItemsChanged;
@ -137,7 +142,7 @@ namespace Avalonia.Native.Interop
for (int i = 0; i < menu.Items.Count; i++)
{
IAvnMenuItem nativeItem;
__MicroComIAvnMenuItemProxy nativeItem;
if (i >= _menuItems.Count)
{

41
src/Avalonia.Native/IAvnMenuItem.cs

@ -7,37 +7,35 @@ using Avalonia.Platform.Interop;
namespace Avalonia.Native.Interop
{
public partial class IAvnMenuItem
partial interface IAvnMenuItem
{
private IAvnMenu _subMenu;
}
}
namespace Avalonia.Native.Interop.Impl
{
partial class __MicroComIAvnMenuItemProxy
{
private __MicroComIAvnMenuProxy _subMenu;
private CompositeDisposable _propertyDisposables = new CompositeDisposable();
private IDisposable _currentActionDisposable;
public NativeMenuItemBase ManagedMenuItem { get; set; }
private void UpdateTitle(string title)
{
using (var buffer = new Utf8Buffer(string.IsNullOrWhiteSpace(title) ? "" : title))
{
Title = buffer.DangerousGetHandle();
}
}
private void UpdateTitle(string title) => SetTitle(title ?? "");
private void UpdateIsChecked(bool isChecked)
{
IsChecked = isChecked;
}
private void UpdateIsChecked(bool isChecked) => SetIsChecked(isChecked);
private void UpdateToggleType(NativeMenuItemToggleType toggleType)
{
ToggleType = (AvnMenuItemToggleType)toggleType;
SetToggleType((AvnMenuItemToggleType)toggleType);
}
private unsafe void UpdateIcon (IBitmap icon)
{
if(icon is null)
{
SetIcon(IntPtr.Zero, 0);
SetIcon(null, IntPtr.Zero);
}
else
{
@ -49,7 +47,7 @@ namespace Avalonia.Native.Interop
fixed(void* ptr = imageData)
{
SetIcon(new IntPtr(ptr), imageData.Length);
SetIcon(ptr, new IntPtr(imageData.Length));
}
}
}
@ -57,12 +55,9 @@ namespace Avalonia.Native.Interop
private void UpdateGesture(Input.KeyGesture gesture)
{
// todo ensure backend can cope with setting null gesture.
using (var buffer = new Utf8Buffer(gesture == null ? "" : OsxUnicodeKeys.ConvertOSXSpecialKeyCodes(gesture.Key)))
{
var modifiers = gesture == null ? AvnInputModifiers.AvnInputModifiersNone : (AvnInputModifiers)gesture.KeyModifiers;
SetGesture(buffer.DangerousGetHandle(), modifiers);
}
var text = gesture == null ? "" : OsxUnicodeKeys.ConvertOSXSpecialKeyCodes(gesture.Key);
var modifiers = gesture == null ? AvnInputModifiers.AvnInputModifiersNone : (AvnInputModifiers)gesture.KeyModifiers;
SetGesture(text, modifiers);
}
private void UpdateAction(NativeMenuItem item)
@ -153,7 +148,7 @@ namespace Avalonia.Native.Interop
{
if (_subMenu == null)
{
_subMenu = IAvnMenu.Create(factory);
_subMenu = __MicroComIAvnMenuProxy.Create(factory);
_subMenu.Initialise(exporter, item.Menu, item.Header);

4
src/Avalonia.Native/NativeControlHostImpl.cs

@ -1,5 +1,6 @@
using System;
using Avalonia.Controls.Platform;
using Avalonia.MicroCom;
using Avalonia.Native.Interop;
using Avalonia.Platform;
using Avalonia.VisualTree;
@ -28,8 +29,7 @@ namespace Avalonia.Native
public DestroyableNSView(IAvnNativeControlHost impl)
{
_impl = new IAvnNativeControlHost(impl.NativePointer);
_impl.AddRef();
_impl = MicroComRuntime.CloneReference(impl);
_nsView = _impl.CreateDefaultChild(IntPtr.Zero);
}

5
src/Avalonia.Native/PlatformThreadingInterface.cs

@ -4,11 +4,10 @@ using System.Threading;
using Avalonia.Native.Interop;
using Avalonia.Platform;
using Avalonia.Threading;
using SharpGen.Runtime;
namespace Avalonia.Native
{
public class PlatformThreadingInterface : IPlatformThreadingInterface
internal class PlatformThreadingInterface : IPlatformThreadingInterface
{
class TimerCallback : CallbackBase, IAvnActionCallback
{
@ -48,7 +47,7 @@ namespace Avalonia.Native
{
_native = native;
using (var cb = new SignaledCallback(this))
_native.SignaledCallback = cb;
_native.SetSignaledCallback(cb);
}
public bool CurrentThreadIsLoopThread => _native.CurrentThreadIsLoopThread;

2
src/Avalonia.Native/ScreenImpl.cs

@ -14,7 +14,7 @@ namespace Avalonia.Native
_native = native;
}
public int ScreenCount => _native.GetScreenCount();
public int ScreenCount => _native.ScreenCount;
public IReadOnlyList<Screen> AllScreens
{

8
src/Avalonia.Native/SystemDialogs.cs

@ -8,7 +8,7 @@ using Avalonia.Native.Interop;
namespace Avalonia.Native
{
public class SystemDialogs : ISystemDialogImpl
internal class SystemDialogs : ISystemDialogImpl
{
IAvnSystemDialogs _native;
@ -62,7 +62,7 @@ namespace Avalonia.Native
}
}
public class SystemDialogEvents : CallbackBase, IAvnSystemDialogEvents
internal unsafe class SystemDialogEvents : CallbackBase, IAvnSystemDialogEvents
{
private TaskCompletionSource<string[]> _tcs;
@ -73,13 +73,13 @@ namespace Avalonia.Native
public Task<string[]> Task => _tcs.Task;
public void OnCompleted(int numResults, IntPtr trFirstResultRef)
public void OnCompleted(int numResults, void* trFirstResultRef)
{
string[] results = new string[numResults];
unsafe
{
var ptr = (IntPtr*)trFirstResultRef.ToPointer();
var ptr = (IntPtr*)trFirstResultRef;
for (int i = 0; i < numResults; i++)
{

28
src/Avalonia.Native/WindowImpl.cs

@ -10,7 +10,7 @@ using Avalonia.Platform.Interop;
namespace Avalonia.Native
{
public class WindowImpl : WindowBaseImpl, IWindowImpl, ITopLevelImplWithNativeMenuExporter
internal class WindowImpl : WindowBaseImpl, IWindowImpl, ITopLevelImplWithNativeMenuExporter
{
private readonly IAvaloniaNativeFactory _factory;
private readonly AvaloniaNativePlatformOptions _opts;
@ -69,12 +69,12 @@ namespace Avalonia.Native
public void CanResize(bool value)
{
_native.CanResize = value;
_native.SetCanResize(value);
}
public void SetSystemDecorations(Controls.SystemDecorations enabled)
{
_native.Decorations = (Interop.SystemDecorations)enabled;
_native.SetDecorations((Interop.SystemDecorations)enabled);
}
public void SetTitleBarColor(Avalonia.Media.Color color)
@ -82,24 +82,12 @@ namespace Avalonia.Native
_native.SetTitleBarColor(new AvnColor { Alpha = color.A, Red = color.R, Green = color.G, Blue = color.B });
}
public void SetTitle(string title)
{
using (var buffer = new Utf8Buffer(title))
{
_native.SetTitle(buffer.DangerousGetHandle());
}
}
public void SetTitle(string title) => _native.SetTitle(title);
public WindowState WindowState
{
get
{
return (WindowState)_native.GetWindowState();
}
set
{
_native.SetWindowState((AvnWindowState)value);
}
get => (WindowState)_native.WindowState;
set => _native.SetWindowState((AvnWindowState)value);
}
public Action<WindowState> WindowStateChanged { get; set; }
@ -146,7 +134,7 @@ namespace Avalonia.Native
}
else
{
ExtendedMargins = _isExtended ? new Thickness(0, _extendTitleBarHeight == -1 ? _native.GetExtendTitleBarHeight() : _extendTitleBarHeight, 0, 0) : new Thickness();
ExtendedMargins = _isExtended ? new Thickness(0, _extendTitleBarHeight == -1 ? _native.ExtendTitleBarHeight : _extendTitleBarHeight, 0, 0) : new Thickness();
}
ExtendClientAreaToDecorationsChanged?.Invoke(_isExtended);
@ -174,7 +162,7 @@ namespace Avalonia.Native
_extendTitleBarHeight = titleBarHeight;
_native.SetExtendTitleBarHeight(titleBarHeight);
ExtendedMargins = _isExtended ? new Thickness(0, titleBarHeight == -1 ? _native.GetExtendTitleBarHeight() : titleBarHeight, 0, 0) : new Thickness();
ExtendedMargins = _isExtended ? new Thickness(0, titleBarHeight == -1 ? _native.ExtendTitleBarHeight : titleBarHeight, 0, 0) : new Thickness();
ExtendClientAreaToDecorationsChanged?.Invoke(_isExtended);
}

18
src/Avalonia.Native/WindowImplBase.cs

@ -15,7 +15,7 @@ using Avalonia.Threading;
namespace Avalonia.Native
{
public class MacOSTopLevelWindowHandle : IPlatformHandle, IMacOSTopLevelPlatformHandle
internal class MacOSTopLevelWindowHandle : IPlatformHandle, IMacOSTopLevelPlatformHandle
{
IAvnWindowBase _native;
@ -43,7 +43,7 @@ namespace Avalonia.Native
}
}
public abstract class WindowBaseImpl : IWindowBaseImpl,
internal abstract class WindowBaseImpl : IWindowBaseImpl,
IFramebufferPlatformSurface, ITopLevelImplWithNativeControlHost
{
protected IInputRoot _inputRoot;
@ -96,7 +96,7 @@ namespace Avalonia.Native
{
if (_native != null)
{
var s = _native.GetClientSize();
var s = _native.ClientSize;
return new Size(s.Width, s.Height);
}
@ -137,7 +137,7 @@ namespace Avalonia.Native
public IMouseDevice MouseDevice => _mouse;
public abstract IPopupImpl CreatePopup();
protected class WindowBaseEvents : CallbackBase, IAvnWindowBaseEvents
protected unsafe class WindowBaseEvents : CallbackBase, IAvnWindowBaseEvents
{
private readonly WindowBaseImpl _parent;
@ -172,11 +172,11 @@ namespace Avalonia.Native
_parent.Paint?.Invoke(new Rect(0, 0, s.Width, s.Height));
}
void IAvnWindowBaseEvents.Resized(AvnSize size)
void IAvnWindowBaseEvents.Resized(AvnSize* size)
{
if (_parent._native != null)
{
var s = new Size(size.Width, size.Height);
var s = new Size(size->Width, size->Height);
_parent._savedLogicalSize = s;
_parent.Resized?.Invoke(s);
}
@ -358,7 +358,7 @@ namespace Avalonia.Native
public PixelPoint Position
{
get => _native.GetPosition().ToAvaloniaPixelPoint();
get => _native.Position.ToAvaloniaPixelPoint();
set => _native.SetPosition(value.ToAvnPoint());
}
@ -390,7 +390,7 @@ namespace Avalonia.Native
_native.SetTopMost(value);
}
public double RenderScaling => _native?.GetScaling() ?? 1;
public double RenderScaling => _native?.Scaling ?? 1;
public double DesktopScaling => 1;
@ -406,7 +406,7 @@ namespace Avalonia.Native
var newCursor = cursor as AvaloniaNativeCursor;
newCursor = newCursor ?? (_cursorFactory.GetCursor(StandardCursorType.Arrow) as AvaloniaNativeCursor);
_native.Cursor = newCursor.Cursor;
_native.SetCursor(newCursor.Cursor);
}
public Action<PixelPoint> PositionChanged { get; set; }

522
src/Avalonia.Native/avn.idl

@ -0,0 +1,522 @@
@clr-namespace Avalonia.Native.Interop
@clr-access internal
@cpp-preamble @@
#include "com.h"
#include "key.h"
#include "stddef.h"
@@
enum SystemDecorations {
SystemDecorationsNone = 0,
SystemDecorationsBorderOnly = 1,
SystemDecorationsFull = 2,
}
struct AvnSize
{
double Width, Height;
}
struct AvnPixelSize
{
int Width, Height;
}
struct AvnRect
{
double X, Y, Width, Height;
}
struct AvnVector
{
double X, Y;
}
struct AvnPoint
{
double X, Y;
}
struct AvnScreen
{
AvnRect Bounds;
AvnRect WorkingArea;
float PixelDensity;
bool Primary;
}
enum AvnPixelFormat
{
kAvnRgb565,
kAvnRgba8888,
kAvnBgra8888
}
struct AvnFramebuffer
{
void* Data;
int Width;
int Height;
int Stride;
AvnVector Dpi;
AvnPixelFormat PixelFormat;
}
struct AvnColor
{
byte Alpha;
byte Red;
byte Green;
byte Blue;
}
enum AvnRawMouseEventType
{
LeaveWindow,
LeftButtonDown,
LeftButtonUp,
RightButtonDown,
RightButtonUp,
MiddleButtonDown,
MiddleButtonUp,
XButton1Down,
XButton1Up,
XButton2Down,
XButton2Up,
Move,
Wheel,
NonClientLeftButtonDown,
TouchBegin,
TouchUpdate,
TouchEnd,
TouchCancel
}
enum AvnRawKeyEventType
{
KeyDown,
KeyUp
}
enum AvnInputModifiers
{
AvnInputModifiersNone = 0,
Alt = 1,
Control = 2,
Shift = 4,
Windows = 8,
LeftMouseButton = 16,
RightMouseButton = 32,
MiddleMouseButton = 64,
XButton1MouseButton = 128,
XButton2MouseButton = 256
}
[class-enum]
enum AvnDragDropEffects
{
None = 0,
Copy = 1,
Move = 2,
Link = 4,
}
[class-enum]
enum AvnDragEventType
{
Enter,
Over,
Leave,
Drop
}
enum AvnWindowState
{
Normal,
Minimized,
Maximized,
FullScreen,
}
enum AvnStandardCursorType
{
CursorArrow,
CursorIbeam,
CursorWait,
CursorCross,
CursorUpArrow,
CursorSizeWestEast,
CursorSizeNorthSouth,
CursorSizeAll,
CursorNo,
CursorHand,
CursorAppStarting,
CursorHelp,
CursorTopSide,
CursorBottomSize,
CursorLeftSide,
CursorRightSide,
CursorTopLeftCorner,
CursorTopRightCorner,
CursorBottomLeftCorner,
CursorBottomRightCorner,
CursorDragMove,
CursorDragCopy,
CursorDragLink,
CursorNone
}
enum AvnWindowEdge
{
WindowEdgeNorthWest,
WindowEdgeNorth,
WindowEdgeNorthEast,
WindowEdgeWest,
WindowEdgeEast,
WindowEdgeSouthWest,
WindowEdgeSouth,
WindowEdgeSouthEast
}
enum AvnMenuItemToggleType
{
None,
CheckMark,
Radio
}
enum AvnExtendClientAreaChromeHints
{
AvnNoChrome = 0,
AvnSystemChrome = 0x01,
AvnPreferSystemChrome = 0x02,
AvnOSXThickTitleBar = 0x08,
AvnDefaultChrome = AvnSystemChrome,
}
[uuid(809c652e-7396-11d2-9771-00a0c9b4d50c)]
interface IAvaloniaNativeFactory : IUnknown
{
HRESULT Initialize(IAvnGCHandleDeallocatorCallback* deallocator);
IAvnMacOptions* GetMacOptions();
HRESULT CreateWindow(IAvnWindowEvents* cb, IAvnGlContext* gl, IAvnWindow** ppv);
HRESULT CreatePopup(IAvnWindowEvents* cb, IAvnGlContext* gl, IAvnPopup** ppv);
HRESULT CreatePlatformThreadingInterface(IAvnPlatformThreadingInterface** ppv);
HRESULT CreateSystemDialogs(IAvnSystemDialogs** ppv);
HRESULT CreateScreens(IAvnScreens** ppv);
HRESULT CreateClipboard(IAvnClipboard** ppv);
HRESULT CreateDndClipboard(IAvnClipboard** ppv);
HRESULT CreateCursorFactory(IAvnCursorFactory** ppv);
HRESULT ObtainGlDisplay(IAvnGlDisplay** ppv);
HRESULT SetAppMenu(IAvnMenu* menu);
HRESULT CreateMenu(IAvnMenuEvents* cb, IAvnMenu** ppv);
HRESULT CreateMenuItem(IAvnMenuItem** ppv);
HRESULT CreateMenuItemSeperator(IAvnMenuItem** ppv);
}
[uuid(233e094f-9b9f-44a3-9a6e-6948bbdd9fb1)]
interface IAvnString : IUnknown
{
HRESULT Pointer(void**retOut);
HRESULT Length(int*ret);
}
[uuid(e5aca675-02b7-4129-aa79-d6e417210bda)]
interface IAvnWindowBase : IUnknown
{
HRESULT Show();
HRESULT Hide();
HRESULT Close();
HRESULT Activate();
HRESULT GetClientSize(AvnSize*ret);
HRESULT GetScaling(double*ret);
HRESULT SetMinMaxSize(AvnSize minSize, AvnSize maxSize);
HRESULT Resize(double width, double height);
HRESULT Invalidate(AvnRect rect);
HRESULT BeginMoveDrag();
HRESULT BeginResizeDrag(AvnWindowEdge edge);
HRESULT GetPosition(AvnPoint*ret);
HRESULT SetPosition(AvnPoint point);
HRESULT PointToClient(AvnPoint point, AvnPoint*ret);
HRESULT PointToScreen(AvnPoint point, AvnPoint*ret);
HRESULT ThreadSafeSetSwRenderedFrame(AvnFramebuffer* fb, IUnknown* dispose);
HRESULT SetTopMost(bool value);
HRESULT SetCursor(IAvnCursor* cursor);
HRESULT CreateGlRenderTarget(IAvnGlSurfaceRenderTarget** ret);
HRESULT SetMainMenu(IAvnMenu* menu);
HRESULT ObtainNSWindowHandle([intptr]void** retOut);
HRESULT ObtainNSWindowHandleRetained([intptr]void** retOut);
HRESULT ObtainNSViewHandle([intptr]void** retOut);
HRESULT ObtainNSViewHandleRetained([intptr]void** retOut);
HRESULT CreateNativeControlHost(IAvnNativeControlHost** retOut);
HRESULT BeginDragAndDropOperation(AvnDragDropEffects effects, AvnPoint point,
IAvnClipboard* clipboard, IAvnDndResultCallback* cb, [intptr]void* sourceHandle);
HRESULT SetBlurEnabled(bool enable);
}
[uuid(83e588f3-6981-4e48-9ea0-e1e569f79a91), cpp-virtual-inherits]
interface IAvnPopup : IAvnWindowBase
{
}
[uuid(cab661de-49d6-4ead-b59c-eac9b2b6c28d), cpp-virtual-inherits]
interface IAvnWindow : IAvnWindowBase
{
HRESULT SetEnabled(bool enable);
HRESULT SetParent(IAvnWindow* parent);
HRESULT SetCanResize(bool value);
HRESULT SetDecorations(SystemDecorations value);
HRESULT SetTitle(char* utf8Title);
HRESULT SetTitleBarColor(AvnColor color);
HRESULT SetWindowState(AvnWindowState state);
HRESULT GetWindowState(AvnWindowState*ret);
HRESULT TakeFocusFromChildren();
HRESULT SetExtendClientArea(bool enable);
HRESULT SetExtendClientAreaHints(AvnExtendClientAreaChromeHints hints);
HRESULT GetExtendTitleBarHeight(double*ret);
HRESULT SetExtendTitleBarHeight(double value);
}
[uuid(939b6599-40a8-4710-a4c8-5d72d8f174fb)]
interface IAvnWindowBaseEvents : IUnknown
{
HRESULT Paint();
void Closed();
void Activated();
void Deactivated();
void Resized([const] AvnSize& size);
void PositionChanged(AvnPoint position);
void RawMouseEvent(AvnRawMouseEventType type,
uint timeStamp,
AvnInputModifiers modifiers,
AvnPoint point,
AvnVector delta);
bool RawKeyEvent(AvnRawKeyEventType type, uint timeStamp, AvnInputModifiers modifiers, uint key);
bool RawTextInputEvent(uint timeStamp, [const] char* text);
void ScalingChanged(double scaling);
void RunRenderPriorityJobs();
void LostFocus();
AvnDragDropEffects DragEvent(AvnDragEventType type, AvnPoint position,
AvnInputModifiers modifiers, AvnDragDropEffects effects,
IAvnClipboard* clipboard, [intptr]void* dataObjectHandle);
}
[uuid(1ae178ee-1fcc-447f-b6dd-b7bb727f934c)]
interface IAvnWindowEvents : IAvnWindowBaseEvents
{
/**
* Closing Event
* Called when the user presses the OS window close button.
* return true to allow the close, return false to prevent close.
*/
bool Closing();
void WindowStateChanged(AvnWindowState state);
void GotInputWhenDisabled();
}
[uuid(e34ae0f8-18b4-48a3-b09d-2e6b19a3cf5e)]
interface IAvnMacOptions : IUnknown
{
HRESULT SetShowInDock(int show);
HRESULT SetApplicationTitle(char* utf8string);
}
[uuid(04c1b049-1f43-418a-9159-cae627ec1367)]
interface IAvnActionCallback : IUnknown
{
void Run();
}
[uuid(6df4d2db-0b80-4f59-ad88-0baa5e21eb14)]
interface IAvnSignaledCallback : IUnknown
{
void Signaled(int priority, bool priorityContainsMeaningfulValue);
}
[uuid(97330f88-c22b-4a8e-a130-201520091b01)]
interface IAvnLoopCancellation : IUnknown
{
void Cancel();
}
[uuid(fbc06f3d-7860-42df-83fd-53c4b02dd9c3)]
interface IAvnPlatformThreadingInterface : IUnknown
{
bool GetCurrentThreadIsLoopThread();
void SetSignaledCallback(IAvnSignaledCallback* cb);
IAvnLoopCancellation* CreateLoopCancellation();
HRESULT RunLoop(IAvnLoopCancellation* cancel);
// Can't pass int* to sharpgentools for some reason
void Signal(int priority);
IUnknown* StartTimer(int priority, int ms, IAvnActionCallback* callback);
}
[uuid(6c621a6e-e4c1-4ae3-9749-83eeeffa09b6)]
interface IAvnSystemDialogEvents : IUnknown
{
void OnCompleted(int numResults, void* ptrFirstResult);
}
[uuid(4d7a47db-a944-4061-abe7-62cb6aa0ffd5)]
interface IAvnSystemDialogs : IUnknown
{
void SelectFolderDialog(IAvnWindow* parentWindowHandle,
IAvnSystemDialogEvents* events,
[const] char* title,
[const] char* initialPath);
void OpenFileDialog(IAvnWindow* parentWindowHandle,
IAvnSystemDialogEvents* events,
bool allowMultiple,
[const] char* title,
[const] char* initialDirectory,
[const] char* initialFile,
[const] char* filters);
void SaveFileDialog(IAvnWindow* parentWindowHandle,
IAvnSystemDialogEvents* events,
[const] char* title,
[const] char* initialDirectory,
[const] char* initialFile,
[const] char* filters);
}
[uuid(9a52bc7a-d8c7-4230-8d34-704a0b70a933)]
interface IAvnScreens : IUnknown
{
HRESULT GetScreenCount(int* ret);
HRESULT GetScreen(int index, AvnScreen* ret);
}
[uuid(792b1bd4-76cc-46ea-bfd0-9d642154b1b3)]
interface IAvnClipboard : IUnknown
{
HRESULT GetText(char* type, IAvnString**ppv);
HRESULT SetText(char* type, char* utf8Text);
HRESULT ObtainFormats(IAvnStringArray**ppv);
HRESULT GetStrings(char* type, IAvnStringArray**ppv);
HRESULT SetBytes(char* type, void* utf8Text, int len);
HRESULT GetBytes(char* type, IAvnString**ppv);
HRESULT Clear();
}
[uuid(3f998545-f027-4d4d-bd2a-1a80926d984e)]
interface IAvnCursor : IUnknown
{
}
[uuid(51ecfb12-c427-4757-a2c9-1596bfce53ef)]
interface IAvnCursorFactory : IUnknown
{
HRESULT GetCursor(AvnStandardCursorType cursorType, IAvnCursor** retOut);
}
[uuid(60452465-8616-40af-bc00-042e69828ce7)]
interface IAvnGlDisplay : IUnknown
{
HRESULT CreateContext(IAvnGlContext* share, IAvnGlContext**ppv);
void LegacyClearCurrentContext();
HRESULT WrapContext([intptr]void* native, IAvnGlContext**ppv);
[intptr]void* GetProcAddress(char* proc);
}
[uuid(78c5711e-2a98-40d2-bac4-0cc9a49dc4f3)]
interface IAvnGlContext : IUnknown
{
HRESULT MakeCurrent(IUnknown** ppv);
HRESULT LegacyMakeCurrent();
int GetSampleCount();
int GetStencilSize();
[intptr]void* GetNativeHandle();
}
[uuid(931062d2-5bc8-4062-8588-83dd8deb99c2)]
interface IAvnGlSurfaceRenderTarget : IUnknown
{
HRESULT BeginDrawing(IAvnGlSurfaceRenderingSession** ret);
}
[uuid(e625b406-f04c-484e-946a-4abd2c6015ad)]
interface IAvnGlSurfaceRenderingSession : IUnknown
{
HRESULT GetPixelSize(AvnPixelSize* ret);
HRESULT GetScaling(double* ret);
}
[uuid(a7724dc1-cf6b-4fa8-9d23-228bf2593edc)]
interface IAvnMenu : IUnknown
{
HRESULT InsertItem(int index, IAvnMenuItem* item);
HRESULT RemoveItem(IAvnMenuItem* item);
HRESULT SetTitle(char* utf8String);
HRESULT Clear();
}
[uuid(59e0586d-bd1c-4b85-9882-80d448b0fed9)]
interface IAvnPredicateCallback : IUnknown
{
bool Evaluate();
}
[uuid(f890219a-1720-4cd5-9a26-cd95fccbf53c)]
interface IAvnMenuItem : IUnknown
{
HRESULT SetSubMenu(IAvnMenu* menu);
HRESULT SetTitle(char* utf8String);
HRESULT SetGesture(char* utf8String, AvnInputModifiers modifiers);
HRESULT SetAction(IAvnPredicateCallback* predicate, IAvnActionCallback* callback);
HRESULT SetIsChecked(bool isChecked);
HRESULT SetToggleType(AvnMenuItemToggleType toggleType);
HRESULT SetIcon(void* data, size_t length);
}
[uuid(0af7df53-7632-42f4-a650-0992c361b477)]
interface IAvnMenuEvents : IUnknown
{
/**
* NeedsUpdate
*/
void NeedsUpdate();
}
[uuid(5142bb41-66ab-49e7-bb37-cd079c000f27)]
interface IAvnStringArray : IUnknown
{
uint GetCount();
HRESULT Get(uint index, IAvnString**ppv);
}
[uuid(a13d2382-3b3a-4d1c-9b27-8f34653d3f01)]
interface IAvnDndResultCallback : IUnknown
{
void OnDragAndDropComplete(AvnDragDropEffects effecct);
}
[uuid(f07c608e-52e9-422d-836e-c70f6e9b80f5)]
interface IAvnGCHandleDeallocatorCallback : IUnknown
{
void FreeGCHandle([intptr]void* handle);
}
[uuid(91c7f677-f26b-4ff3-93cc-cf15aa966ffa)]
interface IAvnNativeControlHost : IUnknown
{
HRESULT CreateDefaultChild([intptr]void* parent, [intptr]void** retOut);
IAvnNativeControlHostTopLevelAttachment* CreateAttachment();
void DestroyDefaultChild([intptr]void* child);
}
[uuid(14a9e164-1aae-4271-bb78-7b5230999b52)]
interface IAvnNativeControlHostTopLevelAttachment : IUnknown
{
[intptr]void* GetParentHandle();
HRESULT InitializeWithChildHandle([intptr]void* child);
HRESULT AttachTo(IAvnNativeControlHost* host);
void ShowInBounds(float x, float y, float width, float height);
void HideWithSize(float width, float height);
void ReleaseChild();
}

23
src/Avalonia.ReactiveUI/ReactiveUserControl.cs

@ -28,11 +28,7 @@ namespace Avalonia.ReactiveUI
// This WhenActivated block calls ViewModel's WhenActivated
// block if the ViewModel implements IActivatableViewModel.
this.WhenActivated(disposables => { });
this.ObservableForProperty(x => x.ViewModel, false, true)
.Subscribe(args => DataContext = args.Value);
this.ObservableForProperty(x => x.DataContext, false, true)
.Subscribe(args => ViewModel = args.Value as TViewModel);
this.GetObservable(ViewModelProperty).Subscribe(OnViewModelChanged);
}
/// <summary>
@ -49,5 +45,22 @@ namespace Avalonia.ReactiveUI
get => ViewModel;
set => ViewModel = (TViewModel)value;
}
protected override void OnDataContextChanged(EventArgs e)
{
ViewModel = DataContext as TViewModel;
}
private void OnViewModelChanged(object value)
{
if (value == null)
{
ClearValue(DataContextProperty);
}
else if (DataContext != value)
{
DataContext = value;
}
}
}
}

31
src/Avalonia.ReactiveUI/ReactiveWindow.cs

@ -28,11 +28,8 @@ namespace Avalonia.ReactiveUI
// This WhenActivated block calls ViewModel's WhenActivated
// block if the ViewModel implements IActivatableViewModel.
this.WhenActivated(disposables => { });
this.ObservableForProperty(x => x.ViewModel, false, true)
.Subscribe(args => DataContext = args.Value);
this.ObservableForProperty(x => x.DataContext, false, true)
.Subscribe(args => ViewModel = args.Value as TViewModel);
this.GetObservable(DataContextProperty).Subscribe(OnDataContextChanged);
this.GetObservable(ViewModelProperty).Subscribe(OnViewModelChanged);
}
/// <summary>
@ -49,5 +46,29 @@ namespace Avalonia.ReactiveUI
get => ViewModel;
set => ViewModel = (TViewModel)value;
}
private void OnDataContextChanged(object value)
{
if (value is TViewModel viewModel)
{
ViewModel = viewModel;
}
else
{
ViewModel = null;
}
}
private void OnViewModelChanged(object value)
{
if (value == null)
{
ClearValue(DataContextProperty);
}
else if (DataContext != value)
{
DataContext = value;
}
}
}
}

55
src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs

@ -26,6 +26,7 @@ namespace Avalonia.Markup.Xaml.XamlIl
{
#if !RUNTIME_XAML_CECIL
private static SreTypeSystem _sreTypeSystem;
private static Type _ignoresAccessChecksFromAttribute;
private static ModuleBuilder _sreBuilder;
private static IXamlType _sreContextType;
private static XamlLanguageTypeMappings _sreMappings;
@ -94,8 +95,60 @@ namespace Avalonia.Markup.Xaml.XamlIl
_sreTypeSystem.CreateTypeBuilder(
_sreBuilder.DefineType("XamlIlContext")), _sreTypeSystem, _sreMappings,
_sreEmitMappings);
if (_ignoresAccessChecksFromAttribute == null)
_ignoresAccessChecksFromAttribute = EmitIgnoresAccessCheckAttributeDefinition(_sreBuilder);
}
static Type EmitIgnoresAccessCheckAttributeDefinition(ModuleBuilder builder)
{
var tb = builder.DefineType("System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute",
TypeAttributes.Class | TypeAttributes.Public, typeof(Attribute));
var field = tb.DefineField("_name", typeof(string), FieldAttributes.Private);
var propGet = tb.DefineMethod("get_AssemblyName", MethodAttributes.Public, typeof(string),
Array.Empty<Type>());
var propGetIl = propGet.GetILGenerator();
propGetIl.Emit(OpCodes.Ldarg_0);
propGetIl.Emit(OpCodes.Ldfld, field);
propGetIl.Emit(OpCodes.Ret);
var prop = tb.DefineProperty("AssemblyName", PropertyAttributes.None, typeof(string), Array.Empty<Type>());
prop.SetGetMethod(propGet);
var ctor = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard,
new[] { typeof(string) });
var ctorIl = ctor.GetILGenerator();
ctorIl.Emit(OpCodes.Ldarg_0);
ctorIl.Emit(OpCodes.Ldarg_1);
ctorIl.Emit(OpCodes.Stfld, field);
ctorIl.Emit(OpCodes.Ldarg_0);
ctorIl.Emit(OpCodes.Call, typeof(Attribute)
.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.First(x => x.GetParameters().Length == 0));
ctorIl.Emit(OpCodes.Ret);
tb.SetCustomAttribute(new CustomAttributeBuilder(
typeof(AttributeUsageAttribute).GetConstructor(new[] { typeof(AttributeTargets) }),
new object[] { AttributeTargets.Assembly },
new[] { typeof(AttributeUsageAttribute).GetProperty("AllowMultiple") },
new object[] { true }));
return tb.CreateTypeInfo();
}
static void EmitIgnoresAccessCheckToAttribute(AssemblyName assemblyName)
{
var name = assemblyName.Name;
if(string.IsNullOrWhiteSpace(name))
return;
var key = assemblyName.GetPublicKey();
if (key != null && key.Length != 0)
name += ", PublicKey=" + BitConverter.ToString(key).Replace("-", "").ToUpperInvariant();
_sreAsm.SetCustomAttribute(new CustomAttributeBuilder(
_ignoresAccessChecksFromAttribute.GetConstructors()[0],
new object[] { name }));
}
static object LoadSre(string xaml, Assembly localAssembly, object rootInstance, Uri uri, bool isDesignMode)
{
@ -118,6 +171,8 @@ namespace Avalonia.Markup.Xaml.XamlIl
{
InitializeSre();
if (localAssembly?.GetName() != null)
EmitIgnoresAccessCheckToAttribute(localAssembly.GetName());
var asm = localAssembly == null ? null : _sreTypeSystem.GetAssembly(localAssembly);
var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + uri);
var clrPropertyBuilder = tb.DefineNestedType("ClrProperties_" + Guid.NewGuid().ToString("N"));

241
src/tools/MicroComGenerator/Ast.cs

@ -0,0 +1,241 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace MicroComGenerator.Ast
{
public class AstAttributeNode
{
public string Name { get; set; }
public string Value { get; set; }
public AstAttributeNode(string name, string value)
{
Name = name;
Value = value;
}
public override string ToString() => $"{Name} = {Value}";
public AstAttributeNode Clone() => new AstAttributeNode(Name, Value);
}
public class AstAttributes : List<AstAttributeNode>
{
public bool HasAttribute(string a) => this.Any(x => x.Name == a);
public AstAttributes Clone()
{
var rv= new AstAttributes();
rv.AddRange(this.Select(x => x.Clone()));
return rv;
}
}
public interface IAstNodeWithAttributes
{
public AstAttributes Attributes { get; set; }
}
public class AstEnumNode : List<AstEnumMemberNode>, IAstNodeWithAttributes
{
public AstAttributes Attributes { get; set; } = new AstAttributes();
public string Name { get; set; }
public override string ToString() => "Enum " + Name;
public AstEnumNode Clone()
{
var rv = new AstEnumNode { Name = Name, Attributes = Attributes.Clone() };
rv.AddRange(this.Select(x => x.Clone()));
return rv;
}
}
public class AstEnumMemberNode
{
public string Name { get; set; }
public string Value { get; set; }
public AstEnumMemberNode(string name, string value)
{
Name = name;
Value = value;
}
public override string ToString() => $"Enum member {Name} = {Value}";
public AstEnumMemberNode Clone() => new AstEnumMemberNode(Name, Value);
}
public class AstStructNode : List<AstStructMemberNode>, IAstNodeWithAttributes
{
public AstAttributes Attributes { get; set; } = new AstAttributes();
public string Name { get; set; }
public override string ToString() => "Struct " + Name;
public AstStructNode Clone()
{
var rv = new AstStructNode { Name = Name, Attributes = Attributes.Clone() };
rv.AddRange(this.Select(x => x.Clone()));
return rv;
}
}
public class AstTypeNode
{
public string Name { get; set; }
public int PointerLevel { get; set; }
public bool IsLink { get; set; }
public string Format() => Name + new string('*', PointerLevel)
+ (IsLink ? "&" : "");
public override string ToString() => Format();
public AstTypeNode Clone() => new AstTypeNode() {
Name = Name,
PointerLevel = PointerLevel,
IsLink = IsLink
};
}
public class AstStructMemberNode : IAstNodeWithAttributes
{
public string Name { get; set; }
public AstTypeNode Type { get; set; }
public override string ToString() => $"Struct member {Type.Format()} {Name}";
public AstStructMemberNode Clone() => new AstStructMemberNode() { Name = Name, Type = Type.Clone() };
public AstAttributes Attributes { get; set; } = new AstAttributes();
}
public class AstInterfaceNode : List<AstInterfaceMemberNode>, IAstNodeWithAttributes
{
public AstAttributes Attributes { get; set; } = new AstAttributes();
public string Name { get; set; }
public string Inherits { get; set; }
public override string ToString()
{
if (Inherits == null)
return Name;
return $"Interface {Name} : {Inherits}";
}
public AstInterfaceNode Clone()
{
var rv = new AstInterfaceNode { Name = Name, Inherits = Inherits, Attributes = Attributes.Clone() };
rv.AddRange(this.Select(x => x.Clone()));
return rv;
}
}
public class AstInterfaceMemberNode : List<AstInterfaceMemberArgumentNode>, IAstNodeWithAttributes
{
public string Name { get; set; }
public AstTypeNode ReturnType { get; set; }
public AstAttributes Attributes { get; set; } = new AstAttributes();
public AstInterfaceMemberNode Clone()
{
var rv = new AstInterfaceMemberNode()
{
Name = Name, Attributes = Attributes.Clone(), ReturnType = ReturnType
};
rv.AddRange(this.Select(x => x.Clone()));
return rv;
}
public override string ToString() =>
$"Interface member {ReturnType.Format()} {Name} ({string.Join(", ", this.Select(x => x.Format()))})";
}
public class AstInterfaceMemberArgumentNode : IAstNodeWithAttributes
{
public string Name { get; set; }
public AstTypeNode Type { get; set; }
public AstAttributes Attributes { get; set; } = new AstAttributes();
public string Format() => $"{Type.Format()} {Name}";
public override string ToString() => "Argument " + Format();
public AstInterfaceMemberArgumentNode Clone() => new AstInterfaceMemberArgumentNode
{
Name = Name, Type = Type.Clone(), Attributes = Attributes.Clone()
};
}
public static class AstExtensions
{
public static bool HasAttribute(this IAstNodeWithAttributes node, string s) => node.Attributes.HasAttribute(s);
public static string GetAttribute(this IAstNodeWithAttributes node, string s)
{
var value = node.Attributes.FirstOrDefault(a => a.Name == s)?.Value;
if (value == null)
throw new CodeGenException("Expected attribute " + s + " for node " + node);
return value;
}
public static string GetAttributeOrDefault(this IAstNodeWithAttributes node, string s)
=> node.Attributes.FirstOrDefault(a => a.Name == s)?.Value;
}
class AstVisitor
{
protected virtual void VisitType(AstTypeNode type)
{
}
protected virtual void VisitArgument(AstInterfaceMemberArgumentNode argument)
{
VisitType(argument.Type);
}
protected virtual void VisitInterfaceMember(AstInterfaceMemberNode member)
{
foreach(var a in member)
VisitArgument(a);
VisitType(member.ReturnType);
}
protected virtual void VisitInterface(AstInterfaceNode iface)
{
foreach(var m in iface)
VisitInterfaceMember(m);
}
protected virtual void VisitStructMember(AstStructMemberNode member)
{
VisitType(member.Type);
}
protected virtual void VisitStruct(AstStructNode node)
{
foreach(var m in node)
VisitStructMember(m);
}
public virtual void VisitAst(AstIdlNode ast)
{
foreach(var iface in ast.Interfaces)
VisitInterface(iface);
foreach (var s in ast.Structs)
VisitStruct(s);
}
}
public class AstIdlNode : IAstNodeWithAttributes
{
public AstAttributes Attributes { get; set; } = new AstAttributes();
public List<AstEnumNode> Enums { get; set; } = new List<AstEnumNode>();
public List<AstStructNode> Structs { get; set; } = new List<AstStructNode>();
public List<AstInterfaceNode> Interfaces { get; set; } = new List<AstInterfaceNode>();
public AstIdlNode Clone() => new AstIdlNode()
{
Attributes = Attributes.Clone(),
Enums = Enums.Select(x => x.Clone()).ToList(),
Structs = Structs.Select(x => x.Clone()).ToList(),
Interfaces = Interfaces.Select(x => x.Clone()).ToList()
};
}
}

231
src/tools/MicroComGenerator/AstParser.cs

@ -0,0 +1,231 @@
using System.Collections.Generic;
using MicroComGenerator.Ast;
namespace MicroComGenerator
{
public class AstParser
{
public static AstIdlNode Parse(string source)
{
var parser = new TokenParser(source);
var idl = new AstIdlNode { Attributes = ParseGlobalAttributes(ref parser) };
while (!parser.Eof)
{
var attrs = ParseLocalAttributes(ref parser);
if (parser.TryParseKeyword("enum"))
idl.Enums.Add(ParseEnum(attrs, ref parser));
else if (parser.TryParseKeyword("struct"))
idl.Structs.Add(ParseStruct(attrs, ref parser));
else if (parser.TryParseKeyword("interface"))
idl.Interfaces.Add(ParseInterface(attrs, ref parser));
else
throw new ParseException("Unexpected character", ref parser);
}
return idl;
}
static AstAttributes ParseGlobalAttributes(ref TokenParser parser)
{
var rv = new AstAttributes();
while (!parser.Eof)
{
parser.SkipWhitespace();
if (parser.TryConsume('@'))
{
var ident = parser.ParseIdentifier("-");
var value = parser.ReadToEol().Trim();
if (value == "@@")
{
parser.Advance(1);
value = "";
while (true)
{
var l = parser.ReadToEol();
if (l == "@@")
break;
else
value = value.Length == 0 ? l : (value + "\n" + l);
parser.Advance(1);
}
}
rv.Add(new AstAttributeNode(ident, value));
}
else
return rv;
}
return rv;
}
static AstAttributes ParseLocalAttributes(ref TokenParser parser)
{
var rv = new AstAttributes();
if (parser.TryConsume("["))
{
while (!parser.TryConsume("]") && !parser.Eof)
{
if (parser.TryConsume(','))
continue;
// Get identifier
var ident = parser.ParseIdentifier("-");
// No value, end of attribute list
if (parser.TryConsume(']'))
{
rv.Add(new AstAttributeNode(ident, null));
return rv;
}
// No value, next attribute
else if (parser.TryConsume(','))
rv.Add(new AstAttributeNode(ident, null));
// Has value
else if (parser.TryConsume('('))
{
var value = parser.ReadTo(')');
parser.Consume(')');
rv.Add(new AstAttributeNode(ident, value));
}
else
throw new ParseException("Unexpected character", ref parser);
}
if (parser.Eof)
throw new ParseException("Unexpected EOF", ref parser);
}
return rv;
}
static void EnsureOpenBracket(ref TokenParser parser)
{
if (!parser.TryConsume('{'))
throw new ParseException("{ expected", ref parser);
}
static AstEnumNode ParseEnum(AstAttributes attrs, ref TokenParser parser)
{
var name = parser.ParseIdentifier();
EnsureOpenBracket(ref parser);
var rv = new AstEnumNode { Name = name, Attributes = attrs };
while (!parser.TryConsume('}') && !parser.Eof)
{
if (parser.TryConsume(','))
continue;
var ident = parser.ParseIdentifier();
// Automatic value
if (parser.TryConsume(',') || parser.Peek == '}')
{
rv.Add(new AstEnumMemberNode(ident, null));
continue;
}
if (!parser.TryConsume('='))
throw new ParseException("Unexpected character", ref parser);
var value = parser.ReadToAny(",}").Trim();
rv.Add(new AstEnumMemberNode(ident, value));
if (parser.Eof)
throw new ParseException("Unexpected EOF", ref parser);
}
return rv;
}
static AstTypeNode ParseType(ref TokenParser parser)
{
var ident = parser.ParseIdentifier();
var t = new AstTypeNode { Name = ident };
while (parser.TryConsume('*'))
t.PointerLevel++;
if (parser.TryConsume("&"))
t.IsLink = true;
return t;
}
static AstStructNode ParseStruct(AstAttributes attrs, ref TokenParser parser)
{
var name = parser.ParseIdentifier();
EnsureOpenBracket(ref parser);
var rv = new AstStructNode { Name = name, Attributes = attrs };
while (!parser.TryConsume('}') && !parser.Eof)
{
var memberAttrs = ParseLocalAttributes(ref parser);
var t = ParseType(ref parser);
bool parsedAtLeastOneMember = false;
while (!parser.TryConsume(';'))
{
// Skip any ,
while (parser.TryConsume(',')) { }
var ident = parser.ParseIdentifier();
parsedAtLeastOneMember = true;
rv.Add(new AstStructMemberNode { Name = ident, Type = t, Attributes = memberAttrs});
}
if (!parsedAtLeastOneMember)
throw new ParseException("Expected at least one enum member with declared type " + t, ref parser);
}
return rv;
}
static AstInterfaceNode ParseInterface(AstAttributes interfaceAttrs, ref TokenParser parser)
{
var interfaceName = parser.ParseIdentifier();
string inheritsFrom = null;
if (parser.TryConsume(":"))
inheritsFrom = parser.ParseIdentifier();
EnsureOpenBracket(ref parser);
var rv = new AstInterfaceNode
{
Name = interfaceName, Attributes = interfaceAttrs, Inherits = inheritsFrom
};
while (!parser.TryConsume('}') && !parser.Eof)
{
var memberAttrs = ParseLocalAttributes(ref parser);
var returnType = ParseType(ref parser);
var name = parser.ParseIdentifier();
var member = new AstInterfaceMemberNode
{
Name = name, ReturnType = returnType, Attributes = memberAttrs
};
rv.Add(member);
parser.Consume('(');
while (true)
{
if (parser.TryConsume(')'))
break;
var argumentAttrs = ParseLocalAttributes(ref parser);
var type = ParseType(ref parser);
var argName = parser.ParseIdentifier();
member.Add(new AstInterfaceMemberArgumentNode
{
Name = argName, Type = type, Attributes = argumentAttrs
});
if (parser.TryConsume(')'))
break;
if (parser.TryConsume(','))
continue;
throw new ParseException("Unexpected character", ref parser);
}
parser.Consume(';');
}
return rv;
}
}
}

459
src/tools/MicroComGenerator/CSharpGen.InterfaceGen.cs

@ -0,0 +1,459 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using MicroComGenerator.Ast;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
// ReSharper disable CoVariantArrayConversion
// HERE BE DRAGONS
namespace MicroComGenerator
{
public partial class CSharpGen
{
abstract class Arg
{
public string Name;
public string NativeType;
public virtual StatementSyntax CreateFixed(StatementSyntax inner) => inner;
public virtual void PreMarshal(List<StatementSyntax> body)
{
}
public virtual void PreMarshalForReturn(List<StatementSyntax> body) =>
throw new InvalidOperationException("Don't know how to use " + NativeType + " as HRESULT-return");
public virtual ExpressionSyntax Value(bool isHresultReturn) => ParseExpression(Name);
public abstract string ManagedType { get; }
public virtual string ReturnManagedType => ManagedType;
public virtual StatementSyntax[] ReturnMarshalResult() => new[] { ParseStatement("return " + Name + ";") };
public virtual void BackPreMarshal(List<StatementSyntax> body)
{
}
public virtual ExpressionSyntax BackMarshalValue() => ParseExpression(Name);
public virtual ExpressionSyntax BackMarshalReturn(string resultVar) => ParseExpression(resultVar);
}
class InterfaceReturnArg : Arg
{
public string InterfaceType;
public override ExpressionSyntax Value(bool isHresultReturn) => ParseExpression("&" + PName);
public override string ManagedType => InterfaceType;
private string PName => "__marshal_" + Name;
public override void PreMarshalForReturn(List<StatementSyntax> body)
{
body.Add(ParseStatement("void* " + PName + " = null;"));
}
public override StatementSyntax[] ReturnMarshalResult() => new[]
{
ParseStatement("return Avalonia.MicroCom.MicroComRuntime.CreateProxyFor<" + InterfaceType + ">(" +
PName + ", true);")
};
public override ExpressionSyntax BackMarshalValue()
{
return ParseExpression("INVALID");
}
public override ExpressionSyntax BackMarshalReturn(string resultVar)
{
return ParseExpression($"Avalonia.MicroCom.MicroComRuntime.GetNativePointer({resultVar}, true)");
}
}
class InterfaceArg : Arg
{
public string InterfaceType;
public override ExpressionSyntax Value(bool isHresultReturn) =>
ParseExpression("Avalonia.MicroCom.MicroComRuntime.GetNativePointer(" + Name + ")");
public override string ManagedType => InterfaceType;
public override StatementSyntax[] ReturnMarshalResult() => new[]
{
ParseStatement("return Avalonia.MicroCom.MicroComRuntime.CreateProxyFor<" + InterfaceType + ">(" +
Name + ", true);")
};
public override ExpressionSyntax BackMarshalValue()
{
return ParseExpression("Avalonia.MicroCom.MicroComRuntime.CreateProxyFor<" + InterfaceType + ">(" +
Name + ", false)");
}
public override ExpressionSyntax BackMarshalReturn(string resultVar)
{
return ParseExpression($"Avalonia.MicroCom.MicroComRuntime.GetNativePointer({resultVar}, true)");
}
}
class BypassArg : Arg
{
public string Type { get; set; }
public int PointerLevel;
public override string ManagedType => Type + new string('*', PointerLevel);
public override string ReturnManagedType => Type + new string('*', PointerLevel - 1);
public override ExpressionSyntax Value(bool isHresultReturn)
{
if (isHresultReturn)
return ParseExpression("&" + Name);
return base.Value(false);
}
public override void PreMarshalForReturn(List<StatementSyntax> body)
{
if (PointerLevel == 0)
base.PreMarshalForReturn(body);
else
body.Add(ParseStatement(Type + new string('*', PointerLevel - 1) + " " + Name + "=default;"));
}
}
class StringArg : Arg
{
private string BName => "__bytemarshal_" + Name;
private string FName => "__fixedmarshal_" + Name;
public override void PreMarshal(List<StatementSyntax> body)
{
body.Add(ParseStatement($"var {BName} = new byte[System.Text.Encoding.UTF8.GetByteCount({Name})+1];"));
body.Add(ParseStatement($"System.Text.Encoding.UTF8.GetBytes({Name}, 0, {Name}.Length, {BName}, 0);"));
}
public override StatementSyntax CreateFixed(StatementSyntax inner)
{
return FixedStatement(DeclareVar("byte*", FName, ParseExpression(BName)), inner);
}
public override ExpressionSyntax Value(bool isHresultReturn) => ParseExpression(FName);
public override string ManagedType => "string";
public override ExpressionSyntax BackMarshalValue()
{
return ParseExpression(
$"({Name} == null ? null : System.Runtime.InteropServices.Marshal.PtrToStringAnsi(new IntPtr(" + Name + ")))");
}
}
string ConvertNativeType(string type)
{
if (type == "size_t")
return "System.IntPtr";
if (type == "HRESULT")
return "int";
return type;
}
Arg ConvertArg(string name, AstTypeNode type)
{
type = new AstTypeNode { Name = ConvertNativeType(type.Name), PointerLevel = type.PointerLevel };
if (type.PointerLevel == 2)
{
if (IsInterface(type))
return new InterfaceReturnArg { Name = name, InterfaceType = type.Name, NativeType = "void**" };
}
else if (type.PointerLevel == 1)
{
if (IsInterface(type))
return new InterfaceArg { Name = name, InterfaceType = type.Name, NativeType = "void*" };
if (type.Name == "char")
return new StringArg { Name = name, NativeType = "byte*" };
}
return new BypassArg
{
Name = name, Type = type.Name, PointerLevel = type.PointerLevel, NativeType = type.ToString()
};
}
void GenerateInterfaceMember(AstInterfaceMemberNode member, ref InterfaceDeclarationSyntax iface,
ref ClassDeclarationSyntax proxy, ref ClassDeclarationSyntax vtbl,
List<StatementSyntax> vtblCtor, int num)
{
// Prepare method information
var args = member.Select(a => ConvertArg(a.Name, a.Type)).ToList();
var returnArg = ConvertArg("__result", member.ReturnType);
bool isHresult = member.ReturnType.Name == "HRESULT";
bool isHresultLastArgumentReturn = isHresult
&& args.Count > 0
&& (args.Last().Name == "ppv" || args.Last().Name == "retOut" || args.Last().Name == "ret")
&& ((member.Last().Type.PointerLevel > 0
&& !IsInterface(member.Last().Type))
|| member.Last().Type.PointerLevel == 2);
bool isVoidReturn = member.ReturnType.Name == "void" && member.ReturnType.PointerLevel == 0;
// Generate method signature
MethodDeclarationSyntax GenerateManagedSig(string returnType, string name,
IEnumerable<(string n, string t)> args)
=> MethodDeclaration(ParseTypeName(returnType), name).WithParameterList(
ParameterList(
SeparatedList(args.Select(x => Parameter(Identifier(x.n)).WithType(ParseTypeName(x.t))))));
var managedSig =
isHresult ?
GenerateManagedSig(isHresultLastArgumentReturn ? args.Last().ReturnManagedType : "void",
member.Name,
(isHresultLastArgumentReturn ? args.SkipLast(1) : args).Select(a => (a.Name, a.ManagedType))) :
GenerateManagedSig(returnArg.ManagedType, member.Name, args.Select(a => (a.Name, a.ManagedType)));
iface = iface.AddMembers(managedSig.WithSemicolonToken(Semicolon()));
// Prepare args for marshaling
var preMarshal = new List<StatementSyntax>();
if (!isVoidReturn)
preMarshal.Add(ParseStatement(returnArg.NativeType + " __result;"));
for (var idx = 0; idx < args.Count; idx++)
{
if (isHresultLastArgumentReturn && idx == args.Count - 1)
args[idx].PreMarshalForReturn(preMarshal);
else
args[idx].PreMarshal(preMarshal);
}
// Generate call expression
ExpressionSyntax callExpr = InvocationExpression(_localInterop.GetCaller(returnArg.NativeType,
args.Select(x => x.NativeType).ToList()))
.AddArgumentListArguments(Argument(ParseExpression("PPV")))
.AddArgumentListArguments(args
.Select((a, i) => Argument(a.Value(isHresultLastArgumentReturn && i == args.Count - 1))).ToArray())
.AddArgumentListArguments(Argument(ParseExpression("(*PPV)[base.VTableSize + " + num + "]")));
if (!isVoidReturn)
callExpr = CastExpression(ParseTypeName(returnArg.NativeType), callExpr);
// Save call result if needed
if (!isVoidReturn)
callExpr = AssignmentExpression(SyntaxKind.SimpleAssignmentExpression, ParseExpression("__result"),
callExpr);
// Wrap call into fixed() blocks
StatementSyntax callStatement = ExpressionStatement(callExpr);
foreach (var arg in args)
callStatement = arg.CreateFixed(callStatement);
// Build proxy body
var proxyBody = Block()
.AddStatements(preMarshal.ToArray())
.AddStatements(callStatement);
// Process return value
if (!isVoidReturn)
{
if (isHresult)
{
proxyBody = proxyBody.AddStatements(
ParseStatement(
$"if(__result != 0) throw new System.Runtime.InteropServices.COMException(\"{member.Name} failed\", __result);"));
if (isHresultLastArgumentReturn)
proxyBody = proxyBody.AddStatements(args.Last().ReturnMarshalResult());
}
else
proxyBody = proxyBody.AddStatements(returnArg.ReturnMarshalResult());
}
// Add the proxy method
proxy = proxy.AddMembers(managedSig.AddModifiers(SyntaxKind.PublicKeyword)
.WithBody(proxyBody));
// Generate VTable method
var shadowDelegate = DelegateDeclaration(ParseTypeName(returnArg.NativeType), member.Name + "Delegate")
.AddParameterListParameters(Parameter(Identifier("@this")).WithType(ParseTypeName("IntPtr")))
.AddParameterListParameters(args.Select(x =>
Parameter(Identifier(x.Name)).WithType(ParseTypeName(x.NativeType))).ToArray())
.AddAttribute("System.Runtime.InteropServices.UnmanagedFunctionPointer",
"System.Runtime.InteropServices.CallingConvention.StdCall");
var shadowMethod = MethodDeclaration(shadowDelegate.ReturnType, member.Name)
.WithParameterList(shadowDelegate.ParameterList)
.AddModifiers(Token(SyntaxKind.StaticKeyword));
var backPreMarshal = new List<StatementSyntax>();
foreach (var arg in args)
arg.BackPreMarshal(backPreMarshal);
backPreMarshal.Add(
ParseStatement($"__target = ({iface.Identifier.Text})Avalonia.MicroCom.MicroComRuntime.GetObjectFromCcw(@this);"));
var isBackVoidReturn = isVoidReturn || (isHresult && !isHresultLastArgumentReturn);
StatementSyntax backCallStatement;
var backCallExpr =
IsPropertyRewriteCandidate(managedSig) ?
ParseExpression("__target." + member.Name.Substring(3)) :
InvocationExpression(ParseExpression("__target." + member.Name))
.WithArgumentList(ArgumentList(SeparatedList(
(isHresultLastArgumentReturn ? args.SkipLast(1) : args)
.Select(a =>
Argument(a.BackMarshalValue())))));
if (isBackVoidReturn)
backCallStatement = ExpressionStatement(backCallExpr);
else
{
backCallStatement = LocalDeclarationStatement(DeclareVar("var", "__result", backCallExpr));
if (isHresultLastArgumentReturn)
{
backCallStatement = Block(backCallStatement,
ExpressionStatement(AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
ParseExpression("*" + args.Last().Name),
args.Last().BackMarshalReturn("__result")
)));
}
else
backCallStatement = Block(backCallStatement,
ReturnStatement(returnArg.BackMarshalReturn("__result")));
}
BlockSyntax backBodyBlock = Block().AddStatements(backPreMarshal.ToArray()).AddStatements(backCallStatement);
backBodyBlock = Block(
TryStatement(
SingletonList(CatchClause(
CatchDeclaration(ParseTypeName("System.Exception"), Identifier("__exception__")), null,
Block(
ParseStatement(
"Avalonia.MicroCom.MicroComRuntime.UnhandledException(__target, __exception__);"),
isHresult ? ParseStatement("return unchecked((int)0x80004005u);")
: isVoidReturn ? EmptyStatement() : ParseStatement("return default;")
))))
.WithBlock(Block(backBodyBlock))
);
if (isHresult)
backBodyBlock = backBodyBlock.AddStatements(ParseStatement("return 0;"));
backBodyBlock = Block()
.AddStatements(ParseStatement($"{iface.Identifier.Text} __target = null;"))
.AddStatements(backBodyBlock.Statements.ToArray());
shadowMethod = shadowMethod.WithBody(backBodyBlock);
vtbl = vtbl.AddMembers(shadowDelegate).AddMembers(shadowMethod);
vtblCtor.Add(ParseStatement("base.AddMethod((" + shadowDelegate.Identifier.Text + ")" +
shadowMethod.Identifier.Text + ");"));
}
class LocalInteropHelper
{
public ClassDeclarationSyntax Class { get; private set; } = ClassDeclaration("LocalInterop");
private HashSet<string> _existing = new HashSet<string>();
public ExpressionSyntax GetCaller(string returnType, List<string> args)
{
string ConvertType(string t) => t.EndsWith("*") ? "void*" : t;
returnType = ConvertType(returnType);
args = args.Select(ConvertType).ToList();
var name = "CalliStdCall" + returnType.Replace("*", "_ptr");
var signature = returnType + "::" + name + "::" + string.Join("::", args);
if (_existing.Add(signature))
{
Class = Class.AddMembers(MethodDeclaration(ParseTypeName(returnType), name)
.AddModifiers(SyntaxKind.StaticKeyword, SyntaxKind.UnsafeKeyword, SyntaxKind.PublicKeyword)
.AddParameterListParameters(Parameter(Identifier("thisObj")).WithType(ParseTypeName("void*")))
.AddParameterListParameters(args.Select((x, i) =>
Parameter(Identifier("arg" + i)).WithType(ParseTypeName(x))).ToArray())
.AddParameterListParameters(Parameter(Identifier("methodPtr")).WithType(ParseTypeName("void*")))
.WithBody(Block(ExpressionStatement(ThrowExpression(ParseExpression("null"))))));
}
return ParseExpression("LocalInterop." + name);
}
}
void GenerateInterface(ref NamespaceDeclarationSyntax ns, ref NamespaceDeclarationSyntax implNs,
AstInterfaceNode iface)
{
var guidString = iface.GetAttribute("uuid");
var inheritsUnknown = iface.Inherits == null || iface.Inherits == "IUnknown";
var ifaceDec = InterfaceDeclaration(iface.Name)
.WithBaseType(inheritsUnknown ? "Avalonia.MicroCom.IUnknown" : iface.Inherits)
.AddModifiers(Token(_visibility), Token(SyntaxKind.UnsafeKeyword), Token(SyntaxKind.PartialKeyword));
var proxyClassName = "__MicroCom" + iface.Name + "Proxy";
var proxy = ClassDeclaration(proxyClassName)
.AddModifiers(Token(SyntaxKind.UnsafeKeyword), Token(_visibility), Token(SyntaxKind.PartialKeyword))
.WithBaseType(inheritsUnknown ?
"Avalonia.MicroCom.MicroComProxyBase" :
("__MicroCom" + iface.Inherits + "Proxy"))
.AddBaseListTypes(SimpleBaseType(ParseTypeName(iface.Name)));
// Generate vtable
var vtbl = ClassDeclaration("__MicroCom" + iface.Name + "VTable")
.AddModifiers(Token(SyntaxKind.UnsafeKeyword));
vtbl = vtbl.WithBaseType(inheritsUnknown ?
"Avalonia.MicroCom.MicroComVtblBase" :
"__MicroCom" + iface.Inherits + "VTable");
var vtblCtor = new List<StatementSyntax>();
for (var idx = 0; idx < iface.Count; idx++)
GenerateInterfaceMember(iface[idx], ref ifaceDec, ref proxy, ref vtbl, vtblCtor, idx);
vtbl = vtbl.AddMembers(
ConstructorDeclaration(vtbl.Identifier.Text)
.AddModifiers(Token(SyntaxKind.PublicKeyword))
.WithBody(Block(vtblCtor))
)
.AddMembers(MethodDeclaration(ParseTypeName("void"), "__MicroComModuleInit")
.AddModifiers(Token(SyntaxKind.StaticKeyword), Token(SyntaxKind.InternalKeyword))
.WithExpressionBody(ArrowExpressionClause(
ParseExpression("Avalonia.MicroCom.MicroComRuntime.RegisterVTable(typeof(" +
iface.Name + "), new " + vtbl.Identifier.Text + "().CreateVTable())")))
.WithSemicolonToken(Semicolon()));
// Finalize proxy code
proxy = proxy.AddMembers(
MethodDeclaration(ParseTypeName("void"), "__MicroComModuleInit")
.AddModifiers(Token(SyntaxKind.StaticKeyword), Token(SyntaxKind.InternalKeyword))
.WithBody(Block(
ParseStatement("Avalonia.MicroCom.MicroComRuntime.Register(typeof(" +
iface.Name + "), new Guid(\"" + guidString + "\"), (p, owns) => new " +
proxyClassName + "(p, owns));")
)))
.AddMembers(ParseMemberDeclaration("public " + proxyClassName +
"(IntPtr nativePointer, bool ownsHandle) : base(nativePointer, ownsHandle) {}"))
.AddMembers(ParseMemberDeclaration("protected override int VTableSize => base.VTableSize + " +
iface.Count + ";"));
ns = ns.AddMembers(RewriteMethodsToProperties(ifaceDec));
implNs = implNs.AddMembers(RewriteMethodsToProperties(proxy), RewriteMethodsToProperties(vtbl));
}
}
}

110
src/tools/MicroComGenerator/CSharpGen.Utils.cs

@ -0,0 +1,110 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using MicroComGenerator.Ast;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Formatting;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace MicroComGenerator
{
public partial class CSharpGen
{
CompilationUnitSyntax Unit()
=> CompilationUnit().WithUsings(List(new[]
{
"System", "System.Text", "System.Collections", "System.Collections.Generic", "Avalonia.MicroCom"
}
.Concat(_extraUsings).Select(u => UsingDirective(IdentifierName(u)))));
string Format(CompilationUnitSyntax unit)
{
var cw = new AdhocWorkspace();
return
"#pragma warning disable 108\n" +
Microsoft.CodeAnalysis.Formatting.Formatter.Format(unit.NormalizeWhitespace(), cw, cw.Options
.WithChangedOption(CSharpFormattingOptions.NewLineForMembersInObjectInit, true)
.WithChangedOption(CSharpFormattingOptions.NewLinesForBracesInObjectCollectionArrayInitializers,
true)
.WithChangedOption(CSharpFormattingOptions.NewLineForMembersInAnonymousTypes, true)
.WithChangedOption(CSharpFormattingOptions.NewLinesForBracesInMethods, true)
).ToFullString();
}
SyntaxToken Semicolon() => Token(SyntaxKind.SemicolonToken);
static VariableDeclarationSyntax DeclareVar(string type, string name,
ExpressionSyntax? initializer = null)
=> VariableDeclaration(ParseTypeName(type),
SingletonSeparatedList(VariableDeclarator(name)
.WithInitializer(initializer == null ? null : EqualsValueClause(initializer))));
FieldDeclarationSyntax DeclareConstant(string type, string name, LiteralExpressionSyntax value)
=> FieldDeclaration(
VariableDeclaration(ParseTypeName(type),
SingletonSeparatedList(
VariableDeclarator(name).WithInitializer(EqualsValueClause(value))
))
).WithSemicolonToken(Semicolon())
.WithModifiers(TokenList(Token(SyntaxKind.PublicKeyword), Token(SyntaxKind.ConstKeyword)));
FieldDeclarationSyntax DeclareField(string type, string name, params SyntaxKind[] modifiers) =>
DeclareField(type, name, null, modifiers);
FieldDeclarationSyntax DeclareField(string type, string name, EqualsValueClauseSyntax initializer,
params SyntaxKind[] modifiers) =>
FieldDeclaration(
VariableDeclaration(ParseTypeName(type),
SingletonSeparatedList(
VariableDeclarator(name).WithInitializer(initializer))))
.WithSemicolonToken(Semicolon())
.WithModifiers(TokenList(modifiers.Select(x => Token(x))));
bool IsPropertyRewriteCandidate(MethodDeclarationSyntax method)
{
if(method.Identifier.Text.Contains("GetScaling"))
Console.WriteLine();
return (method.Identifier.Text.StartsWith("Get") &&
method.ParameterList.Parameters.Count == 0);
}
TypeDeclarationSyntax RewriteMethodsToProperties<T>(T decl) where T : TypeDeclarationSyntax
{
var replace = new Dictionary<MethodDeclarationSyntax, PropertyDeclarationSyntax>();
foreach (var method in decl.Members.OfType<MethodDeclarationSyntax>().ToList())
{
if (IsPropertyRewriteCandidate(method))
{
var getter = AccessorDeclaration(SyntaxKind.GetAccessorDeclaration);
if (method.Body != null)
getter = getter.WithBody(method.Body);
else
getter = getter.WithSemicolonToken(Semicolon());
replace[method] = PropertyDeclaration(method.ReturnType,
method.Identifier.Text.Substring(3))
.WithModifiers(method.Modifiers).AddAccessorListAccessors(getter);
}
}
return decl.ReplaceNodes(replace.Keys, (m, m2) => replace[m]);
}
bool IsInterface(string name)
{
if (name == "IUnknown")
return true;
return _idl.Interfaces.Any(i => i.Name == name);
}
private bool IsInterface(AstTypeNode type) => IsInterface(type.Name);
}
}

133
src/tools/MicroComGenerator/CSharpGen.cs

@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using MicroComGenerator.Ast;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
// ReSharper disable CoVariantArrayConversion
namespace MicroComGenerator
{
public partial class CSharpGen
{
private readonly AstIdlNode _idl;
private List<string> _extraUsings;
private string _namespace;
private SyntaxKind _visibility;
private LocalInteropHelper _localInterop = new LocalInteropHelper();
public CSharpGen(AstIdlNode idl)
{
_idl = idl.Clone();
new AstRewriter().VisitAst(_idl);
_extraUsings = _idl.Attributes.Where(u => u.Name == "clr-using").Select(u => u.Value).ToList();
_namespace = _idl.GetAttribute("clr-namespace");
var visibilityString = _idl.GetAttribute("clr-access");
if (visibilityString == "internal")
_visibility = SyntaxKind.InternalKeyword;
else if (visibilityString == "public")
_visibility = SyntaxKind.PublicKeyword;
else
throw new CodeGenException("Invalid clr-access attribute");
}
class AstRewriter : AstVisitor
{
void ConvertIntPtr(AstTypeNode type)
{
if (type.Name == "void" && type.PointerLevel > 0)
{
type.Name = "IntPtr";
type.PointerLevel--;
}
}
protected override void VisitStructMember(AstStructMemberNode member)
{
if (member.HasAttribute("intptr"))
ConvertIntPtr(member.Type);
base.VisitStructMember(member);
}
protected override void VisitType(AstTypeNode type)
{
if (type.IsLink)
{
type.PointerLevel++;
type.IsLink = false;
}
base.VisitType(type);
}
protected override void VisitArgument(AstInterfaceMemberArgumentNode argument)
{
if (argument.HasAttribute("intptr"))
{
if(argument.Name == "retOut")
Console.WriteLine();
ConvertIntPtr(argument.Type);
}
base.VisitArgument(argument);
}
protected override void VisitInterfaceMember(AstInterfaceMemberNode member)
{
if (member.HasAttribute("intptr"))
ConvertIntPtr(member.ReturnType);
base.VisitInterfaceMember(member);
}
}
public string Generate()
{
var ns = NamespaceDeclaration(ParseName(_namespace));
var implNs = NamespaceDeclaration(ParseName(_namespace + ".Impl"));
ns = GenerateEnums(ns);
ns = GenerateStructs(ns);
foreach (var i in _idl.Interfaces)
GenerateInterface(ref ns, ref implNs, i);
implNs = implNs.AddMembers(_localInterop.Class);
var unit = Unit().AddMembers(ns, implNs);
return Format(unit);
}
NamespaceDeclarationSyntax GenerateEnums(NamespaceDeclarationSyntax ns)
{
return ns.AddMembers(_idl.Enums.Select(e =>
EnumDeclaration(e.Name)
.WithModifiers(TokenList(Token(_visibility)))
.WithMembers(SeparatedList(e.Select(m =>
{
var member = EnumMemberDeclaration(m.Name);
if (m.Value != null)
return member.WithEqualsValue(EqualsValueClause(ParseExpression(m.Value)));
return member;
})))
).ToArray());
}
NamespaceDeclarationSyntax GenerateStructs(NamespaceDeclarationSyntax ns)
{
return ns.AddMembers(_idl.Structs.Select(e =>
StructDeclaration(e.Name)
.WithModifiers(TokenList(Token(_visibility)))
.AddAttribute("System.Runtime.InteropServices.StructLayout", "System.Runtime.InteropServices.LayoutKind.Sequential")
.AddModifiers(Token(SyntaxKind.UnsafeKeyword))
.WithMembers(new SyntaxList<MemberDeclarationSyntax>(SeparatedList(e.Select(m =>
DeclareField(m.Type.ToString(), m.Name, SyntaxKind.PublicKeyword)))))
).ToArray());
}
}
}

116
src/tools/MicroComGenerator/CppGen.cs

@ -0,0 +1,116 @@
using System;
using System.Linq;
using System.Text;
using MicroComGenerator.Ast;
namespace MicroComGenerator
{
public class CppGen
{
static string ConvertType(AstTypeNode type)
{
var name = type.Name;
if (name == "byte")
name = "unsigned char";
else if(name == "uint")
name = "unsigned int";
return name + new string('*', type.PointerLevel);
}
public static string GenerateCpp(AstIdlNode idl)
{
var sb = new StringBuilder();
var preamble = idl.GetAttributeOrDefault("cpp-preamble");
if (preamble != null)
sb.AppendLine(preamble);
foreach (var s in idl.Structs)
sb.AppendLine("struct " + s.Name + ";");
foreach (var s in idl.Interfaces)
sb.AppendLine("struct " + s.Name + ";");
foreach (var en in idl.Enums)
{
sb.Append("enum ");
if (en.Attributes.Any(a => a.Name == "class-enum"))
sb.Append("class ");
sb.AppendLine(en.Name).AppendLine("{");
foreach (var m in en)
{
sb.Append(" ").Append(m.Name);
if (m.Value != null)
sb.Append(" = ").Append(m.Value);
sb.AppendLine(",");
}
sb.AppendLine("};");
}
foreach (var s in idl.Structs)
{
sb.Append("struct ").AppendLine(s.Name).AppendLine("{");
foreach (var m in s)
sb.Append(" ").Append(ConvertType(m.Type)).Append(" ").Append(m.Name).AppendLine(";");
sb.AppendLine("};");
}
foreach (var i in idl.Interfaces)
{
var guidString = i.GetAttribute("uuid");
var guid = Guid.Parse(guidString).ToString().Replace("-", "");
sb.Append("COMINTERFACE(").Append(i.Name).Append(", ")
.Append(guid.Substring(0, 8)).Append(", ")
.Append(guid.Substring(8, 4)).Append(", ")
.Append(guid.Substring(12, 4));
for (var c = 0; c < 8; c++)
{
sb.Append(", ").Append(guid.Substring(16 + c * 2, 2));
}
sb.Append(") : ");
if (i.HasAttribute("cpp-virtual-inherits"))
sb.Append("virtual ");
sb.AppendLine(i.Inherits ?? "IUnknown")
.AppendLine("{");
foreach (var m in i)
{
sb.Append(" ")
.Append("virtual ")
.Append(ConvertType(m.ReturnType))
.Append(" ").Append(m.Name).Append(" (");
if (m.Count == 0)
sb.AppendLine(") = 0;");
else
{
sb.AppendLine();
for (var c = 0; c < m.Count; c++)
{
var arg = m[c];
sb.Append(" ");
if (arg.Attributes.Any(a => a.Name == "const"))
sb.Append("const ");
sb.Append(ConvertType(arg.Type))
.Append(" ")
.Append(arg.Name);
if (c != m.Count - 1)
sb.Append(", ");
sb.AppendLine();
}
sb.AppendLine(" ) = 0;");
}
}
sb.AppendLine("};");
}
return sb.ToString();
}
}
}

97
src/tools/MicroComGenerator/Extensions.cs

@ -0,0 +1,97 @@
using System;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
namespace MicroComGenerator
{
public static class Extensions
{
public static ClassDeclarationSyntax AddModifiers(this ClassDeclarationSyntax cl, params SyntaxKind[] modifiers)
{
if (modifiers == null)
return cl;
return cl.AddModifiers(modifiers.Select(x => SyntaxFactory.Token(x)).ToArray());
}
public static MethodDeclarationSyntax AddModifiers(this MethodDeclarationSyntax cl, params SyntaxKind[] modifiers)
{
if (modifiers == null)
return cl;
return cl.AddModifiers(modifiers.Select(x => SyntaxFactory.Token(x)).ToArray());
}
public static PropertyDeclarationSyntax AddModifiers(this PropertyDeclarationSyntax cl, params SyntaxKind[] modifiers)
{
if (modifiers == null)
return cl;
return cl.AddModifiers(modifiers.Select(x => SyntaxFactory.Token(x)).ToArray());
}
public static ConstructorDeclarationSyntax AddModifiers(this ConstructorDeclarationSyntax cl, params SyntaxKind[] modifiers)
{
if (modifiers == null)
return cl;
return cl.AddModifiers(modifiers.Select(x => SyntaxFactory.Token(x)).ToArray());
}
public static AccessorDeclarationSyntax AddModifiers(this AccessorDeclarationSyntax cl, params SyntaxKind[] modifiers)
{
if (modifiers == null)
return cl;
return cl.AddModifiers(modifiers.Select(x => SyntaxFactory.Token(x)).ToArray());
}
public static string WithLowerFirst(this string s)
{
if (string.IsNullOrEmpty(s))
return s;
return char.ToLowerInvariant(s[0]) + s.Substring(1);
}
public static ExpressionSyntax MemberAccess(params string[] identifiers)
{
if (identifiers == null || identifiers.Length == 0)
throw new ArgumentException();
var expr = (ExpressionSyntax)IdentifierName(identifiers[0]);
for (var c = 1; c < identifiers.Length; c++)
expr = MemberAccess(expr, identifiers[c]);
return expr;
}
public static ExpressionSyntax MemberAccess(ExpressionSyntax expr, params string[] identifiers)
{
foreach (var i in identifiers)
expr = MemberAccess(expr, i);
return expr;
}
public static MemberAccessExpressionSyntax MemberAccess(ExpressionSyntax expr, string identifier) =>
MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, expr, IdentifierName(identifier));
public static ClassDeclarationSyntax WithBaseType(this ClassDeclarationSyntax cl, string bt)
{
return cl.AddBaseListTypes(SimpleBaseType(SyntaxFactory.ParseTypeName(bt)));
}
public static InterfaceDeclarationSyntax WithBaseType(this InterfaceDeclarationSyntax cl, string bt)
{
return cl.AddBaseListTypes(SimpleBaseType(SyntaxFactory.ParseTypeName(bt)));
}
public static T AddAttribute<T>(this T member, string attribute, params string[] args) where T : MemberDeclarationSyntax
{
return (T)member.AddAttributeLists(AttributeList(SingletonSeparatedList(
Attribute(ParseName(attribute), AttributeArgumentList(
SeparatedList(args.Select(a => AttributeArgument(ParseExpression(a)))))))));
}
public static string StripPrefix(this string s, string prefix) => string.IsNullOrEmpty(s)
? s
: s.StartsWith(prefix)
? s.Substring(prefix.Length)
: s;
}
}

10
src/tools/MicroComGenerator/MicroComGenerator.csproj

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.8.0" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="3.7.0" />
</ItemGroup>
</Project>

27
src/tools/MicroComGenerator/ParseException.cs

@ -0,0 +1,27 @@
using System;
namespace MicroComGenerator
{
class ParseException : Exception
{
public int Line { get; }
public int Position { get; }
public ParseException(string message, int line, int position) : base(message)
{
Line = line;
Position = position;
}
public ParseException(string message, ref TokenParser parser) : this(message, parser.Line, parser.Position)
{
}
}
class CodeGenException : Exception
{
public CodeGenException(string message) : base(message)
{
}
}
}

44
src/tools/MicroComGenerator/Program.cs

@ -0,0 +1,44 @@
using System;
using System.IO;
using System.Linq;
using CommandLine;
namespace MicroComGenerator
{
class Program
{
public class Options
{
[Option('i', "input", Required = true, HelpText = "Input IDL file")]
public string Input { get; set; }
[Option("cpp", Required = false, HelpText = "C++ output file")]
public string CppOutput { get; set; }
[Option("cs", Required = false, HelpText = "C# output file")]
public string CSharpOutput { get; set; }
}
static int Main(string[] args)
{
var p = Parser.Default.ParseArguments<Options>(args);
if (p is NotParsed<Options>)
{
return 1;
}
var opts = ((Parsed<Options>)p).Value;
var text = File.ReadAllText(opts.Input);
var ast = AstParser.Parse(text);
if (opts.CppOutput != null)
File.WriteAllText(opts.CppOutput, CppGen.GenerateCpp(ast));
if (opts.CSharpOutput != null)
File.WriteAllText(opts.CSharpOutput, new CSharpGen(ast).Generate());
return 0;
}
}
}

417
src/tools/MicroComGenerator/TokenParser.cs

@ -0,0 +1,417 @@
using System;
using System.Globalization;
using System.IO;
namespace MicroComGenerator
{
internal ref struct TokenParser
{
private ReadOnlySpan<char> _s;
public int Position { get; private set; }
public int Line { get; private set; }
public TokenParser(ReadOnlySpan<char> s)
{
_s = s;
Position = 0;
Line = 0;
}
public void SkipWhitespace()
{
while (true)
{
if(_s.Length == 0)
return;
if (char.IsWhiteSpace(_s[0]))
Advance(1);
else if (_s[0] == '/' && _s.Length>1)
{
if (_s[1] == '/')
SkipOneLineComment();
else if (_s[1] == '*')
SkipMultiLineComment();
else
return;
}
else
return;
}
}
void SkipOneLineComment()
{
while (true)
{
if (_s.Length > 0 && _s[0] != '\n' && _s[0] != '\r')
Advance(1);
else
return;
}
}
void SkipMultiLineComment()
{
var l = Line;
var p = Position;
while (true)
{
if (_s.Length == 0)
throw new ParseException("No matched */ found for /*", l, p);
if (_s[0] == '*' && _s.Length > 1 && _s[1] == '/')
{
Advance(2);
return;
}
Advance(1);
}
}
static bool IsAlphaNumeric(char ch) => (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z');
public void Consume(char c)
{
if (!TryConsume(c))
throw new ParseException("Expected " + c, Line, Position);
}
public bool TryConsume(char c)
{
SkipWhitespace();
if (_s.Length == 0 || _s[0] != c)
return false;
Advance(1);
return true;
}
public bool TryConsume(string s)
{
SkipWhitespace();
if (_s.Length < s.Length)
return false;
for (var c = 0; c < s.Length; c++)
{
if (_s[c] != s[c])
return false;
}
Advance(s.Length);
return true;
}
public bool TryConsumeAny(ReadOnlySpan<char> chars, out char token)
{
SkipWhitespace();
token = default;
if (_s.Length == 0)
return false;
foreach (var c in chars)
{
if (c == _s[0])
{
token = c;
Advance(1);
return true;
}
}
return false;
}
public bool TryParseKeyword(string keyword)
{
SkipWhitespace();
if (keyword.Length > _s.Length)
return false;
for(var c=0; c<keyword.Length;c++)
if (keyword[c] != _s[c])
return false;
if (_s.Length > keyword.Length && IsAlphaNumeric(_s[keyword.Length]))
return false;
Advance(keyword.Length);
return true;
}
public bool TryParseKeywordLowerCase(string keywordInLowerCase)
{
SkipWhitespace();
if (keywordInLowerCase.Length > _s.Length)
return false;
for(var c=0; c<keywordInLowerCase.Length;c++)
if (keywordInLowerCase[c] != char.ToLowerInvariant(_s[c]))
return false;
if (_s.Length > keywordInLowerCase.Length && IsAlphaNumeric(_s[keywordInLowerCase.Length]))
return false;
Advance(keywordInLowerCase.Length);
return true;
}
public void Advance(int c)
{
while (c > 0)
{
if (_s[0] == '\n')
{
Line++;
Position = 0;
}
else
Position++;
_s = _s.Slice(1);
c--;
}
}
public int Length => _s.Length;
public bool Eof
{
get
{
SkipWhitespace();
return Length == 0;
}
}
public char Peek
{
get
{
if (_s.Length == 0)
throw new ParseException("Unexpected EOF", Line, Position);
return _s[0];
}
}
public string ParseIdentifier(ReadOnlySpan<char> extraValidChars)
{
if (!TryParseIdentifier(extraValidChars, out var ident))
throw new ParseException("Identifier expected", Line, Position);
return ident.ToString();
}
public string ParseIdentifier()
{
if (!TryParseIdentifier(out var ident))
throw new ParseException("Identifier expected", Line, Position);
return ident.ToString();
}
public bool TryParseIdentifier(ReadOnlySpan<char> extraValidChars, out ReadOnlySpan<char> res)
{
res = ReadOnlySpan<char>.Empty;
SkipWhitespace();
if (_s.Length == 0)
return false;
var first = _s[0];
if (!((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z') || first == '_'))
return false;
int len = 1;
for (var c = 1; c < _s.Length; c++)
{
var ch = _s[c];
if (IsAlphaNumeric(ch) || ch == '_')
len++;
else
{
var found = false;
foreach(var vc in extraValidChars)
if (vc == ch)
{
found = true;
break;
}
if (found)
len++;
else
break;
}
}
res = _s.Slice(0, len);
Advance(len);
return true;
}
public bool TryParseIdentifier(out ReadOnlySpan<char> res)
{
res = ReadOnlySpan<char>.Empty;
SkipWhitespace();
if (_s.Length == 0)
return false;
var first = _s[0];
if (!((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z') || first == '_'))
return false;
int len = 1;
for (var c = 1; c < _s.Length; c++)
{
var ch = _s[c];
if (IsAlphaNumeric(ch) || ch == '_')
len++;
else
break;
}
res = _s.Slice(0, len);
Advance(len);
return true;
}
public string ReadToEol()
{
var initial = _s;
var len = 0;
while (true)
{
if (_s.Length > 0 && _s[0] != '\n' && _s[0] != '\r')
{
len++;
Advance(1);
}
else
return initial.Slice(0, len).ToString();
}
}
public string ReadTo(char c)
{
var initial = _s;
var len = 0;
var l = Line;
var p = Position;
while (true)
{
if (_s.Length == 0)
throw new ParseException("Expected " + c + " before EOF", l, p);
if (_s[0] != c)
{
len++;
Advance(1);
}
else
return initial.Slice(0, len).ToString();
}
}
public string ReadToAny(ReadOnlySpan<char> chars)
{
var initial = _s;
var len = 0;
var l = Line;
var p = Position;
while (true)
{
if (_s.Length == 0)
throw new ParseException("Expected any of '" + chars.ToString() + "' before EOF", l, p);
var foundTerminator = false;
foreach (var term in chars)
{
if (_s[0] == term)
{
foundTerminator = true;
break;
}
}
if (!foundTerminator)
{
len++;
Advance(1);
}
else
return initial.Slice(0, len).ToString();
}
}
public bool TryParseCall(out ReadOnlySpan<char> res)
{
res = ReadOnlySpan<char>.Empty;
SkipWhitespace();
if (_s.Length == 0)
return false;
var first = _s[0];
if (!((first >= 'a' && first <= 'z') || (first >= 'A' && first <= 'Z')))
return false;
int len = 1;
for (var c = 1; c < _s.Length; c++)
{
var ch = _s[c];
if ((ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch<= 'Z') || ch == '.')
len++;
else
break;
}
res = _s.Slice(0, len);
// Find '('
for (var c = len; c < _s.Length; c++)
{
if(char.IsWhiteSpace(_s[c]))
continue;
if(_s[c]=='(')
{
Advance(c + 1);
return true;
}
return false;
}
return false;
}
public bool TryParseFloat(out float res)
{
res = 0;
SkipWhitespace();
if (_s.Length == 0)
return false;
var len = 0;
var dotCount = 0;
for (var c = 0; c < _s.Length; c++)
{
var ch = _s[c];
if (ch >= '0' && ch <= '9')
len = c + 1;
else if (ch == '.' && dotCount == 0)
{
len = c + 1;
dotCount++;
}
else
break;
}
var span = _s.Slice(0, len);
#if NETSTANDARD2_0
if (!float.TryParse(span.ToString(), NumberStyles.Number, CultureInfo.InvariantCulture, out res))
return false;
#else
if (!float.TryParse(span, NumberStyles.Number, CultureInfo.InvariantCulture, out res))
return false;
#endif
Advance(len);
return true;
}
public override string ToString() => _s.ToString();
}
}

61
tests/Avalonia.DesignerSupport.Tests/DesignerSupportTests.cs

@ -11,6 +11,7 @@ using System.Threading;
using System.Threading.Tasks;
using Avalonia.Remote.Protocol;
using Avalonia.Remote.Protocol.Designer;
using Avalonia.Remote.Protocol.Viewport;
using Xunit;
using Xunit.Extensions;
@ -31,19 +32,38 @@ namespace Avalonia.DesignerSupport.Tests
@"..\..\..\..\..\tests/Avalonia.DesignerSupport.TestApp/bin/$BUILD/netcoreapp3.1/",
"Avalonia.DesignerSupport.TestApp",
"Avalonia.DesignerSupport.TestApp.dll",
@"..\..\..\..\..\tests\Avalonia.DesignerSupport.TestApp\MainWindow.xaml"),
@"..\..\..\..\..\tests\Avalonia.DesignerSupport.TestApp\MainWindow.xaml",
"win32"),
InlineData(
@"..\..\..\..\..\samples\ControlCatalog.NetCore\bin\$BUILD\netcoreapp3.1\",
"ControlCatalog.NetCore",
"ControlCatalog.dll",
@"..\..\..\..\..\samples\ControlCatalog\MainWindow.xaml")]
@"..\..\..\..\..\samples\ControlCatalog\MainWindow.xaml",
"win32"),
InlineData(
@"..\..\..\..\..\tests/Avalonia.DesignerSupport.TestApp/bin/$BUILD/netcoreapp3.1/",
"Avalonia.DesignerSupport.TestApp",
"Avalonia.DesignerSupport.TestApp.dll",
@"..\..\..\..\..\tests\Avalonia.DesignerSupport.TestApp\MainWindow.xaml",
"avalonia-remote"),
InlineData(
@"..\..\..\..\..\samples\ControlCatalog.NetCore\bin\$BUILD\netcoreapp3.1\",
"ControlCatalog.NetCore",
"ControlCatalog.dll",
@"..\..\..\..\..\samples\ControlCatalog\MainWindow.xaml",
"avalonia-remote")]
public async Task Designer_In_Win32_Mode_Should_Provide_Valid_Hwnd(
string outputDir,
string executableName,
string assemblyName,
string xamlFile)
string xamlFile,
string method)
{
Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
outputDir = Path.GetFullPath(outputDir.Replace('\\', Path.DirectorySeparatorChar));
xamlFile = Path.GetFullPath(xamlFile.Replace('\\', Path.DirectorySeparatorChar));
if (method == "win32")
Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows));
var xaml = File.ReadAllText(xamlFile);
string buildType;
@ -56,6 +76,8 @@ namespace Avalonia.DesignerSupport.Tests
var sessionId = Guid.NewGuid();
long handle = 0;
bool success = false;
string error = null;
var resultMessageReceivedToken = new CancellationTokenSource();
@ -71,6 +93,18 @@ namespace Avalonia.DesignerSupport.Tests
if (msg is StartDesignerSessionMessage start)
{
Assert.Equal(sessionId, Guid.Parse(start.SessionId));
if (method == "avalonia-remote")
{
await conn.Send(new ClientSupportedPixelFormatsMessage
{
Formats = new[] { PixelFormat.Rgba8888 }
});
await conn.Send(new ClientViewportAllocatedMessage
{
DpiX = 96, DpiY = 96, Width = 1024, Height = 768
});
}
await conn.Send(new UpdateXamlMessage
{
AssemblyPath = Path.Combine(outputDir, assemblyName),
@ -80,8 +114,14 @@ namespace Avalonia.DesignerSupport.Tests
else if (msg is UpdateXamlResultMessage result)
{
if (result.Error != null)
{
error = result.Error;
outputHelper.WriteLine(result.Error);
handle = result.Handle != null ? long.Parse(result.Handle) : 0;
}
else
success = true;
if (method == "win32")
handle = result.Handle != null ? long.Parse(result.Handle) : 0;
resultMessageReceivedToken.Cancel();
conn.Dispose();
}
@ -91,7 +131,7 @@ namespace Avalonia.DesignerSupport.Tests
var cmdline =
$"exec --runtimeconfig \"{outputDir}{executableName}.runtimeconfig.json\" --depsfile \"{outputDir}{executableName}.deps.json\" "
+ $" \"{DesignerAppPath.Replace("$BUILD", buildType)}\" "
+ $"--transport tcp-bson://127.0.0.1:{port}/ --session-id {sessionId} --method win32 \"{outputDir}{executableName}.dll\"";
+ $"--transport tcp-bson://127.0.0.1:{port}/ --session-id {sessionId} --method {method} \"{outputDir}{executableName}.dll\"";
using (var proc = new Process
{
@ -128,10 +168,15 @@ namespace Avalonia.DesignerSupport.Tests
}
proc.WaitForExit();
var stdout = proc.StandardOutput.ReadToEnd();
var stderr = proc.StandardError.ReadToEnd();
Assert.True(cancelled,
$"Message Not Received.\n" + proc.StandardOutput.ReadToEnd() + "\n" +
proc.StandardError.ReadToEnd());
Assert.NotEqual(0, handle);
stderr + "\n" + stdout);
Assert.True(success, error);
if (method == "win32")
Assert.NotEqual(0, handle);
}
}

3
tests/Avalonia.DesignerSupport.Tests/Remote/HtmlTransport/webapp/.gitignore

@ -0,0 +1,3 @@
build
node_modules
.nyc_output

94
tests/Avalonia.DesignerSupport.Tests/Remote/HtmlTransport/webapp/Models/InputEventTests.ts

@ -0,0 +1,94 @@
import { describe } from 'mocha';
import { expect } from 'chai';
import { Mock } from "moq.ts";
import { MouseEvent, WheelEvent } from "react";
import { InputModifiers } from "../../../../../../src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/InputModifiers";
import { MouseButton } from "../../../../../../src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/MouseButton";
import { PointerMovedEventMessage } from "../../../../../../src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/PointerMovedEventMessage";
import { PointerPressedEventMessage } from "../../../../../../src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/PointerPressedEventMessage";
import { PointerReleasedEventMessage } from "../../../../../../src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/PointerReleasedEventMessage";
import { ScrollEventMessage } from "../../../../../../src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/ScrollEventMessage";
import { getModifiers, getMouseButton } from '../../../../../../src/Avalonia.DesignerSupport/Remote/HtmlTransport/webapp/src/Models/Input/MouseEventHelpers';
describe("Input event tests", () => {
describe("Helpers", () => {
it("getModifiers", () => {
const event = new Mock<MouseEvent>()
.setup(x => x.altKey).returns(false)
.setup(x => x.ctrlKey).returns(true)
.setup(x => x.shiftKey).returns(false)
.setup(x => x.metaKey).returns(false)
.setup(x => x.buttons).returns(1)
.object()
var actual = getModifiers(event)
expect(actual)
.eql([InputModifiers.Control, InputModifiers.LeftMouseButton])
})
it("getMouseButton", () => {
const event = new Mock<MouseEvent>()
.setup(x => x.button).returns(1)
.object()
var actual = getMouseButton(event)
expect(actual)
.equal(MouseButton.Middle)
})
})
describe("Messages", () => {
const x = .3
const y = .42
const modifiers = "0,1,2,3,4,5,6"
const button = "1"
const deltaX = -3.
const deltaY = -3.
const mouseEvent = new Mock<MouseEvent>()
.setup(x => x.altKey).returns(true)
.setup(x => x.ctrlKey).returns(true)
.setup(x => x.shiftKey).returns(true)
.setup(x => x.metaKey).returns(true)
.setup(x => x.buttons).returns(7)
.setup(x => x.button).returns(0)
.setup(x => x.clientX).returns(x)
.setup(x => x.clientY).returns(y)
.object()
it("PointerMovedEventMessage", () => {
const message = new PointerMovedEventMessage(mouseEvent)
expect(message.toString())
.equal(`pointer-moved:${modifiers}:${x}:${y}`)
})
it("PointerPressedEventMessage", () => {
const message = new PointerPressedEventMessage(mouseEvent)
expect(message.toString())
.equal(`pointer-pressed:${modifiers}:${x}:${y}:${button}`)
})
it("PointerReleasedEventMessage", () => {
const message = new PointerReleasedEventMessage(mouseEvent)
expect(message.toString())
.equal(`pointer-released:${modifiers}:${x}:${y}:${button}`)
})
it("ScrollEventMessage", () => {
const wheelEvent = new Mock<WheelEvent>()
.setup(x => x.altKey).returns(true)
.setup(x => x.ctrlKey).returns(true)
.setup(x => x.shiftKey).returns(true)
.setup(x => x.metaKey).returns(true)
.setup(x => x.buttons).returns(7)
.setup(x => x.clientX).returns(x)
.setup(x => x.clientY).returns(y)
.setup(x => x.deltaX).returns(-deltaX)
.setup(x => x.deltaY).returns(-deltaY)
.object()
const message = new ScrollEventMessage(wheelEvent)
expect(message.toString())
.equal(`scroll:${modifiers}:${x}:${y}:${deltaX}:${deltaY}`)
})
})
})

2414
tests/Avalonia.DesignerSupport.Tests/Remote/HtmlTransport/webapp/package-lock.json

File diff suppressed because it is too large

26
tests/Avalonia.DesignerSupport.Tests/Remote/HtmlTransport/webapp/package.json

@ -0,0 +1,26 @@
{
"name": "simple-test",
"version": "1.0.0",
"main": "index.js",
"scripts": {
"test": "mocha -r ts-node/register ./**/*Tests.ts",
"coverage": "nyc -r text -e .ts -x \"./*Tests.ts\" npm run test"
},
"type": "module",
"keywords": [],
"author": "",
"license": "MIT",
"dependencies": {},
"devDependencies": {
"@types/chai": "4.2.12",
"@types/mocha": "8.0.3",
"@types/react": "^16.3.14",
"chai": "^4.2.0",
"mocha": "^8.1.3",
"moq.ts": "^6.4.0",
"nyc": "^15.1.0",
"react": "^16.3.2",
"ts-node": "^9.0.0",
"typescript": "^4.0.2"
}
}

12
tests/Avalonia.DesignerSupport.Tests/Remote/HtmlTransport/webapp/tsconfig.json

@ -0,0 +1,12 @@
{
"compilerOptions": {
"module": "commonjs",
"target": "es5",
"sourceMap": true,
"strict": true,
"esModuleInterop": true
},
"exclude": [
"node_modules"
]
}

71
tests/Avalonia.ReactiveUI.UnitTests/ReactiveUserControlTest.cs

@ -1,4 +1,5 @@
using System.Reactive.Disposables;
using Avalonia.Controls;
using Avalonia.UnitTests;
using ReactiveUI;
using Splat;
@ -100,5 +101,75 @@ namespace Avalonia.ReactiveUI.UnitTests
Assert.NotNull(view.DataContext);
Assert.False(view.ViewModel.IsActive);
}
[Fact]
public void Should_Inherit_DataContext()
{
var vm1 = new ExampleViewModel();
var vm2 = new ExampleViewModel();
var view = new ExampleView();
var root = new TestRoot(view);
Assert.Null(view.DataContext);
Assert.Null(view.ViewModel);
root.DataContext = vm1;
Assert.Same(vm1, view.DataContext);
Assert.Same(vm1, view.ViewModel);
root.DataContext = null;
Assert.Null(view.DataContext);
Assert.Null(view.ViewModel);
root.DataContext = vm2;
Assert.Same(vm2, view.DataContext);
Assert.Same(vm2, view.ViewModel);
}
[Fact]
public void Should_Not_Overlap_Change_Notifications()
{
var vm1 = new ExampleViewModel();
var vm2 = new ExampleViewModel();
var view1 = new ExampleView();
var view2 = new ExampleView();
Assert.Null(view1.DataContext);
Assert.Null(view2.DataContext);
Assert.Null(view1.ViewModel);
Assert.Null(view2.ViewModel);
view1.DataContext = vm1;
Assert.Same(vm1, view1.DataContext);
Assert.Same(vm1, view1.ViewModel);
Assert.Null(view2.DataContext);
Assert.Null(view2.ViewModel);
view2.DataContext = vm2;
Assert.Same(vm1, view1.DataContext);
Assert.Same(vm1, view1.ViewModel);
Assert.Same(vm2, view2.DataContext);
Assert.Same(vm2, view2.ViewModel);
view1.ViewModel = null;
Assert.Null(view1.DataContext);
Assert.Null(view1.ViewModel);
Assert.Same(vm2, view2.DataContext);
Assert.Same(vm2, view2.ViewModel);
view2.ViewModel = null;
Assert.Null(view1.DataContext);
Assert.Null(view2.DataContext);
Assert.Null(view1.ViewModel);
Assert.Null(view2.ViewModel);
}
}
}

Loading…
Cancel
Save