Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Loader Snaps to DevDiagnostics's insights #3815

Merged
merged 6 commits into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions DevHome.sln
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestTools", "TestTools", "{
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestDumpAnalyzer", "tools\DevDiagnostics\TestTools\TestDumpAnalyzer\TestDumpAnalyzer.csproj", "{29963C5C-4CB6-4406-850A-99503CB87081}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utilities", "Utilities", "{81AB1B86-AE3C-4E5B-8918-CA6CCED95266}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EnableLoaderSnaps", "tools\DevDiagnostics\Utilities\EnableLoaderSnaps\EnableLoaderSnaps.csproj", "{EB097CCA-D4B6-4C99-9EB8-161F26345562}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestLoadFailure", "tools\DevDiagnostics\TestTools\TestLoadFailure\TestLoadFailure.vcxproj", "{F196A38B-190C-4B00-813D-DC0B7AD24CB7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestServiceCaller", "tools\DevDiagnostics\TestTools\TestServiceCaller\TestServiceCaller.csproj", "{024CB70C-3449-4204-9171-A25C6C25783D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DevHome.Database", "database\DevHome.Database\DevHome.Database.csproj", "{01CADE81-7333-4E24-A39B-95B7E58D4503}"
Expand Down Expand Up @@ -1255,6 +1261,42 @@ Global
{29963C5C-4CB6-4406-850A-99503CB87081}.Release|x64.Build.0 = Release|x64
{29963C5C-4CB6-4406-850A-99503CB87081}.Release|x86.ActiveCfg = Release|x86
{29963C5C-4CB6-4406-850A-99503CB87081}.Release|x86.Build.0 = Release|x86
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Debug_FailFast|arm64.ActiveCfg = Debug_FailFast|ARM64
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Debug_FailFast|arm64.Build.0 = Debug_FailFast|ARM64
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Debug_FailFast|x64.ActiveCfg = Debug_FailFast|x64
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Debug_FailFast|x64.Build.0 = Debug_FailFast|x64
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Debug_FailFast|x86.ActiveCfg = Debug_FailFast|x86
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Debug_FailFast|x86.Build.0 = Debug_FailFast|x86
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Debug|arm64.ActiveCfg = Debug|ARM64
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Debug|arm64.Build.0 = Debug|ARM64
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Debug|x64.ActiveCfg = Debug|x64
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Debug|x64.Build.0 = Debug|x64
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Debug|x86.ActiveCfg = Debug|x86
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Debug|x86.Build.0 = Debug|x86
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Release|arm64.ActiveCfg = Release|ARM64
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Release|arm64.Build.0 = Release|ARM64
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Release|x64.ActiveCfg = Release|x64
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Release|x64.Build.0 = Release|x64
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Release|x86.ActiveCfg = Release|x86
{EB097CCA-D4B6-4C99-9EB8-161F26345562}.Release|x86.Build.0 = Release|x86
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Debug_FailFast|arm64.ActiveCfg = Debug|x64
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Debug_FailFast|arm64.Build.0 = Debug|x64
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Debug_FailFast|x64.ActiveCfg = Debug|x64
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Debug_FailFast|x64.Build.0 = Debug|x64
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Debug_FailFast|x86.ActiveCfg = Debug|Win32
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Debug_FailFast|x86.Build.0 = Debug|Win32
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Debug|arm64.ActiveCfg = Debug|x64
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Debug|arm64.Build.0 = Debug|x64
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Debug|x64.ActiveCfg = Debug|x64
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Debug|x64.Build.0 = Debug|x64
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Debug|x86.ActiveCfg = Debug|Win32
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Debug|x86.Build.0 = Debug|Win32
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Release|arm64.ActiveCfg = Release|x64
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Release|arm64.Build.0 = Release|x64
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Release|x64.ActiveCfg = Release|x64
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Release|x64.Build.0 = Release|x64
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Release|x86.ActiveCfg = Release|Win32
{F196A38B-190C-4B00-813D-DC0B7AD24CB7}.Release|x86.Build.0 = Release|Win32
{024CB70C-3449-4204-9171-A25C6C25783D}.Debug_FailFast|arm64.ActiveCfg = Debug_FailFast|ARM64
{024CB70C-3449-4204-9171-A25C6C25783D}.Debug_FailFast|arm64.Build.0 = Debug_FailFast|ARM64
{024CB70C-3449-4204-9171-A25C6C25783D}.Debug_FailFast|x64.ActiveCfg = Debug_FailFast|x64
Expand Down Expand Up @@ -1383,6 +1425,9 @@ Global
{17E96025-8251-4D62-BFFB-C571F728B66B} = {E6BC5785-34E5-4A19-81A4-2CC8A37FD63F}
{7857275B-7970-4C26-B092-FF62EA890B1E} = {DB3D0F2C-1A7F-44B4-B408-B21A56212985}
{29963C5C-4CB6-4406-850A-99503CB87081} = {7857275B-7970-4C26-B092-FF62EA890B1E}
{81AB1B86-AE3C-4E5B-8918-CA6CCED95266} = {DB3D0F2C-1A7F-44B4-B408-B21A56212985}
{EB097CCA-D4B6-4C99-9EB8-161F26345562} = {81AB1B86-AE3C-4E5B-8918-CA6CCED95266}
{F196A38B-190C-4B00-813D-DC0B7AD24CB7} = {7857275B-7970-4C26-B092-FF62EA890B1E}
{024CB70C-3449-4204-9171-A25C6C25783D} = {7857275B-7970-4C26-B092-FF62EA890B1E}
{567A82BE-7E9E-4D95-AF45-4EE8D57FE16D} = {A972EC5B-FC61-4964-A6FF-F9633EB75DFD}
{82BD8133-F1D4-4383-BC4F-12EFAE1AFF91} = {567A82BE-7E9E-4D95-AF45-4EE8D57FE16D}
Expand All @@ -1396,5 +1441,7 @@ Global
build\cppversion\version.vcxitems*{13f1f098-262b-432d-977c-f710e6826c5c}*SharedItemsImports = 5
build\cppversion\version.vcxitems*{60e0fd98-5396-436d-bab7-187a853a5dc6}*SharedItemsImports = 5
build\cppversion\version.vcxitems*{8a0ad1a7-29e1-47e1-9579-91f2b460518f}*SharedItemsImports = 5
build\cppversion\version.vcxitems*{caac0cdf-9ab8-4f43-a3eb-38d785af5725}*SharedItemsImports = 5
build\cppversion\version.vcxitems*{eb097cca-d4b6-4c99-9eb8-161f26345562}*SharedItemsImports = 5
EndGlobalSection
EndGlobal
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$(SolutionDir)ToolingVersions.props" />
<Import Project="$(SolutionDir)Directory.CppBuild.props" />
<PropertyGroup>
<ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>None</ResolveAssemblyWarnOrErrorOnTargetArchitectureMismatch>
</PropertyGroup>
Expand Down
7 changes: 6 additions & 1 deletion service/DevHome.Service/DevHome.Service.csproj
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<Project Sdk="Microsoft.NET.Sdk.Worker">
<Import Project="$(SolutionDir)ToolingVersions.props" />
<Import Project="$(SolutionDir)Directory.CppBuild.props" />
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>DevHome.Service</RootNamespace>
Expand All @@ -11,6 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Diagnostics.Tracing.TraceEvent" Version="3.1.9" GeneratePathProperty="true" />
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.WindowsServices" Version="8.0.0" />
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.3.106">
Expand All @@ -19,6 +19,11 @@
</PackageReference>
</ItemGroup>

<ItemGroup>
<None Remove="$(PkgMicrosoft_Diagnostics_Tracing_TraceEvent)\lib\netstandard2.0\TraceReloggerLib.dll" />
<None Remove="$(PkgMicrosoft_Diagnostics_Tracing_TraceEvent)\lib\netstandard2.0\Dia2Lib.dll" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\DevHome.Service.Projection\DevHome.Service.Projection.csproj" />
</ItemGroup>
Expand Down
81 changes: 76 additions & 5 deletions service/DevHome.Service/DevHomeService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,95 @@

using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Diagnostics.Tracing.Parsers;
using Microsoft.Diagnostics.Tracing.Session;
using Windows.Win32.Foundation;

namespace DevHome.Service.Runtime;

[ComVisible(true)]
public class DevHomeService : IDevHomeService
public class DevHomeService : IDevHomeService, IDisposable
{
private readonly Process _owner;

public event MissingFileProcessLaunchFailureHandler? MissingFileProcessLaunchFailure;

private TraceEventSession? _etwSession;

public DevHomeService()
{
Process myCaller = ComHelpers.GetClientProcess();

ComHelpers.VerifyCaller(myCaller);

_owner = myCaller;
_owner.EnableRaisingEvents = true;

// Track our caller process
ServiceLifetimeController.RegisterProcess(myCaller);
ServiceLifetimeController.ServiceStop += ServiceLifetimeController_ServiceStop;
ServiceLifetimeController.RegisterProcess(_owner);

var crashDumpAnalyzerThread = new Thread(() =>
{
KernelEventETWListener();
});
crashDumpAnalyzerThread.Name = "KernelEventETWListenerThread";
crashDumpAnalyzerThread.Start();

_owner.Exited += Owner_Exited;
}

private void ServiceLifetimeController_ServiceStop()
{
// Be sure to stop our ETW session when we exit. It's possible this gets called multiple times
// if we have multiple instances of our object... that's ok.
_etwSession?.Stop();
}

private void Owner_Exited(object? sender, EventArgs e)
{
// The owner of our object has exited. We'll stop listening to ETW events from this channel, but keep it open in case there are
// other listeners of the channel in this process.
_etwSession?.Source.StopProcessing();
aeloros marked this conversation as resolved.
Show resolved Hide resolved
}

private void KernelEventETWListener()
{
_etwSession = new TraceEventSession("DevHome.Service.KernelEventETWListenerSession");

// Enable the kernel provider to look for processes exiting with non-zero exit codes
_etwSession.EnableKernelProvider(KernelTraceEventParser.Keywords.Process);

_etwSession.Source.Kernel.ProcessStop += data =>
{
// Only return data for processes in session 0 or the caller's session (don't let one session spy on another session)
if (data.SessionID == 0 || data.SessionID == _owner.SessionId)
{
if (data.ExitStatus == NTSTATUS.STATUS_DLL_NOT_FOUND || data.ExitStatus == (int)WIN32_ERROR.ERROR_MOD_NOT_FOUND)
{
MissingFileProcessLaunchFailureInfo info = default(MissingFileProcessLaunchFailureInfo);
info.processName = data.ImageFileName;
info.pid = data.ProcessID;
info.exitCode = data.ExitStatus;

try
{
MissingFileProcessLaunchFailure?.Invoke(info);
}
catch (Exception)
{
// We don't want to crash the process if the event handler throws an exception
}
}
}
};

_etwSession.Source.Process();
}

public int GetNumber()
public void Dispose()
{
return 42;
_etwSession?.Source.StopProcessing();
_etwSession?.Dispose();
GC.SuppressFinalize(this);
}
}
2 changes: 2 additions & 0 deletions service/DevHome.Service/NativeMethods.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ E_NOINTERFACE
GLOBALOPT_EH_VALUES
GLOBALOPT_PROPERTIES
GLOBALOPT_RO_FLAGS
STATUS_DLL_NOT_FOUND
WIN32_ERROR

34 changes: 22 additions & 12 deletions service/DevHome.Service/ServiceLifetimeController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@

namespace DevHome.Service;

internal delegate void ServiceStopEvent();

internal sealed class ServiceLifetimeController
{
private static readonly List<Process> _processes = new();

internal static event ServiceStopEvent? ServiceStop;

public static void RegisterProcess(Process p)
{
lock (_processes)
Expand All @@ -23,18 +27,24 @@ public static void RegisterProcess(Process p)
{
_processes.Add(p);
p.EnableRaisingEvents = true;
p.Exited += (sender, e) =>
{
lock (_processes)
{
_processes.Remove(p);
if (_processes.Count == 0)
{
// It's ok to stop the service now
WindowsBackgroundService.Stop();
}
}
};
p.Exited += ProcessExited;
}
}
}

private static void ProcessExited(object? sender, EventArgs e)
{
Process? p = sender as Process;
Debug.Assert(p is not null, "What is this object?");

lock (_processes)
{
_processes.Remove(p);
if (_processes.Count == 0)
{
// It's ok to stop the service now
ServiceStop?.Invoke();
WindowsBackgroundService.Stop();
}
}
}
Expand Down
11 changes: 10 additions & 1 deletion service/Devhome.Service.IDL/DevHome.Service.idl
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,17 @@ import "windows.foundation.idl";

namespace DevHome.Service
{
struct MissingFileProcessLaunchFailureInfo
{
String processName;
Int32 pid;
Int32 exitCode;
};

delegate void MissingFileProcessLaunchFailureHandler(MissingFileProcessLaunchFailureInfo failure);

interface IDevHomeService
{
Int32 GetNumber();
event MissingFileProcessLaunchFailureHandler MissingFileProcessLaunchFailure;
}
}
12 changes: 4 additions & 8 deletions src/Package-Can.appxmanifest
Original file line number Diff line number Diff line change
Expand Up @@ -333,21 +333,17 @@
</uap:SupportedFileTypes>
</uap:FileTypeAssociation>
</uap:Extension>

<desktop6:Extension Category="windows.service" Executable="DevHome.Service.exe" EntryPoint="DevHome.Service">
<desktop6:Service Name="DevHome-Can.Service" StartupType="manual" StartAccount="localSystem" />
</desktop6:Extension>

<com2:Extension Category="windows.comServer">
<com2:ComServer>
<com3:ServiceServer ServiceName="DevHome-Can.Service"
LaunchAndActivationPermission="O:SYG:SYD:(A;;11;;;IU)">
<com3:ServiceServer ServiceName="DevHome-Can.Service" LaunchAndActivationPermission="O:SYG:SYD:(A;;11;;;IU)">
<!-- Grant local activation rights to Interactive Users. -->
<com3:Class Id="0A920C6E-2569-44D1-A6E4-CE9FA44CD2A7" DisplayName="CLSID_DevHomeService"/>
<com3:Class Id="0A920C6E-2569-44D1-A6E4-CE9FA44CD2A7" DisplayName="CLSID_DevHomeService" />
</com3:ServiceServer>
</com2:ComServer>
</com2:Extension>

</Extensions>
</Application>
<Application Id="DevHome.DevDiagnostics" Executable="DevHome.DevDiagnostics.exe" EntryPoint="Windows.FullTrustApplication">
Expand Down Expand Up @@ -410,8 +406,8 @@
<Capabilities>
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="unvirtualizedResources" />
<rescap:Capability Name="packagedServices"/>
<rescap:Capability Name="localSystemServices"/>
<rescap:Capability Name="packagedServices" />
<rescap:Capability Name="localSystemServices" />
</Capabilities>
<genTemplate:Metadata>
<genTemplate:Item Name="generator" Value="Template Studio" />
Expand Down
28 changes: 5 additions & 23 deletions src/Package.appxmanifest
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3"
xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5"
xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:genTemplate="http://schemas.microsoft.com/appx/developer/templatestudio"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
xmlns:com2="http://schemas.microsoft.com/appx/manifest/com/windows10/2"
xmlns:com3="http://schemas.microsoft.com/appx/manifest/com/windows10/3"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6"
IgnorableNamespaces="uap uap3 uap5 uap10 genTemplate">

<Package xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10" xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10" xmlns:uap3="http://schemas.microsoft.com/appx/manifest/uap/windows10/3" xmlns:uap5="http://schemas.microsoft.com/appx/manifest/uap/windows10/5" xmlns:uap10="http://schemas.microsoft.com/appx/manifest/uap/windows10/10" xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities" xmlns:genTemplate="http://schemas.microsoft.com/appx/developer/templatestudio" xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10" xmlns:com2="http://schemas.microsoft.com/appx/manifest/com/windows10/2" xmlns:com3="http://schemas.microsoft.com/appx/manifest/com/windows10/3" xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10" xmlns:desktop6="http://schemas.microsoft.com/appx/manifest/desktop/windows10/6" IgnorableNamespaces="uap uap3 uap5 uap10 genTemplate">
<Extensions>
<Extension Category="windows.activatableClass.proxyStub">
<ProxyStub ClassId="00000355-0000-0000-C000-000000000046">
Expand Down Expand Up @@ -347,21 +333,17 @@
</uap:SupportedFileTypes>
</uap:FileTypeAssociation>
</uap:Extension>

<desktop6:Extension Category="windows.service" Executable="DevHome.Service.exe" EntryPoint="DevHome.Service.Service">
<desktop6:Service Name="DevHome.Service" StartupType="manual" StartAccount="localSystem" />
</desktop6:Extension>

<com2:Extension Category="windows.comServer">
<com2:ComServer>
<com3:ServiceServer ServiceName="DevHome.Service"
LaunchAndActivationPermission="O:SYG:SYD:(A;;11;;;IU)">
<com3:ServiceServer ServiceName="DevHome.Service" LaunchAndActivationPermission="O:SYG:SYD:(A;;11;;;IU)">
<!-- Grant local activation rights to Interactive Users. -->
<com3:Class Id="E8D40232-20A1-4F3B-9C0C-AAA6538698C6" DisplayName="CLSID_DevHomeService"/>
<com3:Class Id="E8D40232-20A1-4F3B-9C0C-AAA6538698C6" DisplayName="CLSID_DevHomeService" />
</com3:ServiceServer>
</com2:ComServer>
</com2:Extension>

</Extensions>
</Application>
<Application Id="DevHome.DevDiagnostics" Executable="DevHome.DevDiagnostics.exe" EntryPoint="Windows.FullTrustApplication">
Expand Down Expand Up @@ -424,8 +406,8 @@
<Capabilities>
<rescap:Capability Name="runFullTrust" />
<rescap:Capability Name="unvirtualizedResources" />
<rescap:Capability Name="packagedServices"/>
<rescap:Capability Name="localSystemServices"/>
<rescap:Capability Name="packagedServices" />
<rescap:Capability Name="localSystemServices" />
</Capabilities>
<genTemplate:Metadata>
<genTemplate:Item Name="generator" Value="Template Studio" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<UserControl
x:Class="DevHome.DevDiagnostics.Controls.ElevatedButtonControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:DevHome.DevDiagnostics.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid>
<Button Command="{x:Bind Command, Mode=OneWay}" AutomationProperties.AutomationId="ElevatedButtonControl">
<StackPanel Orientation="Horizontal" Spacing="10">
<SymbolIcon Symbol="Admin" AutomationProperties.AutomationId="ElevatedButtonIcon"/>
<TextBlock Margin="0" Text="{x:Bind Text, Mode=OneWay}" AutomationProperties.AutomationId="ElevatedButtonText"/>
</StackPanel>
</Button>
</Grid>
</UserControl>
Loading
Loading