mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-21 13:57:49 +00:00
starts up to a toolbar icon with context menu. still much more to do
This commit is contained in:
parent
54206fd44d
commit
6b0543ba27
@ -1,7 +1,7 @@
|
||||
<Application x:Class="WinUI.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
StartupUri="MainWindow.xaml">
|
||||
StartupUri="ToolbarItem.xaml">
|
||||
<Application.Resources>
|
||||
|
||||
<ResourceDictionary>
|
||||
|
@ -5,6 +5,7 @@ using System.Data;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Hardcodet.Wpf.TaskbarNotification;
|
||||
|
||||
namespace WinUI
|
||||
{
|
||||
@ -13,5 +14,12 @@ namespace WinUI
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
private TaskbarIcon tb;
|
||||
|
||||
private void InitApplication()
|
||||
{
|
||||
tb = (TaskbarIcon)FindResource("NotifyIcon");
|
||||
tb.Visibility = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,102 +36,35 @@ namespace WinUI
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (InitAPIHandler())
|
||||
{
|
||||
networksPage.SetAPIHandler(handler);
|
||||
|
||||
updateStatus();
|
||||
if (!connected)
|
||||
{
|
||||
MessageBox.Show("Unable to connect to ZeroTier Service.");
|
||||
}
|
||||
|
||||
updateNetworks();
|
||||
//updatePeers();
|
||||
|
||||
DataObject.AddPastingHandler(joinNetworkID, OnPaste);
|
||||
|
||||
timer.Elapsed += new ElapsedEventHandler(OnUpdateTimer);
|
||||
timer.Interval = 2000;
|
||||
timer.Enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String readAuthToken(String path)
|
||||
public void SetAPIHandler(APIHandler handler)
|
||||
{
|
||||
String authToken = "";
|
||||
timer.Stop();
|
||||
timer = new Timer();
|
||||
|
||||
if (File.Exists(path))
|
||||
this.handler = handler;
|
||||
|
||||
networksPage.SetAPIHandler(handler);
|
||||
|
||||
updateStatus();
|
||||
|
||||
if (!connected)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] tmp = File.ReadAllBytes(path);
|
||||
authToken = System.Text.Encoding.UTF8.GetString(tmp).Trim();
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show("Unable to read ZeroTier One Auth Token from:\r\n" + path, "ZeroTier One");
|
||||
}
|
||||
MessageBox.Show("Unable to connect to ZerOTier Service");
|
||||
return;
|
||||
}
|
||||
|
||||
return authToken;
|
||||
}
|
||||
|
||||
private Int32 readPort(String path)
|
||||
{
|
||||
Int32 port = 9993;
|
||||
|
||||
try
|
||||
{
|
||||
byte[] tmp = File.ReadAllBytes(path);
|
||||
port = Int32.Parse(System.Text.Encoding.ASCII.GetString(tmp).Trim());
|
||||
if ((port <= 0) || (port > 65535))
|
||||
port = 9993;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
private bool InitAPIHandler()
|
||||
{
|
||||
String localZtDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\ZeroTier\\One";
|
||||
String globalZtDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\ZeroTier\\One";
|
||||
|
||||
String authToken = "";
|
||||
Int32 port = 9993;
|
||||
|
||||
if (!File.Exists(localZtDir + "\\authtoken.secret") || !File.Exists(localZtDir + "\\zerotier-one.port"))
|
||||
{
|
||||
// launch external process to copy file into place
|
||||
String curPath = System.Reflection.Assembly.GetEntryAssembly().Location;
|
||||
int index = curPath.LastIndexOf("\\");
|
||||
curPath = curPath.Substring(0, index);
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo(curPath + "\\copyutil.exe", globalZtDir + " " + localZtDir);
|
||||
startInfo.Verb = "runas";
|
||||
|
||||
|
||||
var process = Process.Start(startInfo);
|
||||
process.WaitForExit();
|
||||
}
|
||||
|
||||
authToken = readAuthToken(localZtDir + "\\authtoken.secret");
|
||||
|
||||
if ((authToken == null) || (authToken.Length <= 0))
|
||||
{
|
||||
MessageBox.Show("Unable to read ZeroTier One authtoken", "ZeroTier One");
|
||||
this.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
port = readPort(localZtDir + "\\zerotier-one.port");
|
||||
handler = new APIHandler(port, authToken);
|
||||
return true;
|
||||
updateNetworks();
|
||||
|
||||
DataObject.AddPastingHandler(joinNetworkID, OnPaste);
|
||||
|
||||
timer.Elapsed += new ElapsedEventHandler(OnUpdateTimer);
|
||||
timer.Interval = 2000;
|
||||
timer.Enabled = true;
|
||||
}
|
||||
|
||||
|
||||
private void updateStatus()
|
||||
{
|
||||
|
52
windows/WinUI/Properties/Resources.Designer.cs
generated
52
windows/WinUI/Properties/Resources.Designer.cs
generated
@ -8,10 +8,10 @@
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace WinUI.Properties
|
||||
{
|
||||
|
||||
|
||||
namespace WinUI.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
@ -22,50 +22,52 @@ namespace WinUI.Properties
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources
|
||||
{
|
||||
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources()
|
||||
{
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager
|
||||
{
|
||||
get
|
||||
{
|
||||
if ((resourceMan == null))
|
||||
{
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WinUI.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture
|
||||
{
|
||||
get
|
||||
{
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set
|
||||
{
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
|
||||
/// </summary>
|
||||
internal static System.Drawing.Icon ZeroTierIcon {
|
||||
get {
|
||||
object obj = ResourceManager.GetObject("ZeroTierIcon", resourceCulture);
|
||||
return ((System.Drawing.Icon)(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -46,7 +46,7 @@
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
@ -60,6 +60,7 @@
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
@ -68,9 +69,10 @@
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
@ -85,9 +87,10 @@
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
@ -109,9 +112,13 @@
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||
<data name="ZeroTierIcon" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||
<value>..\ZeroTierIcon.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
|
||||
</data>
|
||||
</root>
|
BIN
windows/WinUI/Resources/ZeroTierIcon.ico
Normal file
BIN
windows/WinUI/Resources/ZeroTierIcon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 44 KiB |
@ -1,4 +1,9 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/interactivedesigner/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d">
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/interactivedesigner/2006"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d"
|
||||
xmlns:tb="http://www.hardcodet.net/taskbar">
|
||||
|
||||
<!-- SimpleStyles.XAML defines a set of control styles which are simplified starting points for creating your own controls -->
|
||||
|
||||
@ -1118,4 +1123,6 @@
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<tb:TaskbarIcon x:Key="NotifyIcon" IconSource="ZeroTierIcon.ico" ToolTipText="ZeroTier One"/>
|
||||
</ResourceDictionary>
|
||||
|
32
windows/WinUI/ToolbarItem.xaml
Normal file
32
windows/WinUI/ToolbarItem.xaml
Normal file
@ -0,0 +1,32 @@
|
||||
<Window x:Class="WinUI.ToolbarItem"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:WinUI"
|
||||
xmlns:tb="http://www.hardcodet.net/taskbar"
|
||||
mc:Ignorable="d"
|
||||
Height="300" Width="300" Visibility="Hidden">
|
||||
<Grid>
|
||||
<tb:TaskbarIcon x:Name="MyNotifyIcon"
|
||||
IconSource="ZeroTierIcon.ico"
|
||||
ToolTipText="ZeroTier One"
|
||||
TrayContextMenuOpen="ToolbarItem_TrayContextMenuOpen"
|
||||
PreviewTrayContextMenuOpen="ToolbarItem_PreviewTrayContextMenuOpen">
|
||||
<tb:TaskbarIcon.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Node ID: abeb9f9bc5"/>
|
||||
<Separator/>
|
||||
<MenuItem Header="Join Network..."/>
|
||||
<MenuItem Header="Show Networks..."/>
|
||||
<Separator/>
|
||||
<MenuItem Header="About..."/>
|
||||
<MenuItem Header="Preferences..."/>
|
||||
<Separator/>
|
||||
<MenuItem Header="Quit"/>
|
||||
</ContextMenu>
|
||||
</tb:TaskbarIcon.ContextMenu>
|
||||
|
||||
</tb:TaskbarIcon>
|
||||
</Grid>
|
||||
</Window>
|
127
windows/WinUI/ToolbarItem.xaml.cs
Normal file
127
windows/WinUI/ToolbarItem.xaml.cs
Normal file
@ -0,0 +1,127 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Timers;
|
||||
using System.Windows.Threading;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace WinUI
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ToolbarItem.xaml
|
||||
/// </summary>
|
||||
public partial class ToolbarItem : Window
|
||||
{
|
||||
APIHandler handler;
|
||||
|
||||
public ToolbarItem()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
if (InitAPIHandler())
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox.Show("ZeroTier API Initialization Failed");
|
||||
}
|
||||
}
|
||||
|
||||
private String readAuthToken(String path)
|
||||
{
|
||||
String authToken = "";
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] tmp = File.ReadAllBytes(path);
|
||||
authToken = System.Text.Encoding.UTF8.GetString(tmp).Trim();
|
||||
}
|
||||
catch
|
||||
{
|
||||
MessageBox.Show("Unable to read ZeroTier One Auth Token from:\r\n" + path, "ZeroTier One");
|
||||
}
|
||||
}
|
||||
|
||||
return authToken;
|
||||
}
|
||||
|
||||
private Int32 readPort(String path)
|
||||
{
|
||||
Int32 port = 9993;
|
||||
|
||||
try
|
||||
{
|
||||
byte[] tmp = File.ReadAllBytes(path);
|
||||
port = Int32.Parse(System.Text.Encoding.ASCII.GetString(tmp).Trim());
|
||||
if ((port <= 0) || (port > 65535))
|
||||
port = 9993;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return port;
|
||||
}
|
||||
|
||||
private bool InitAPIHandler()
|
||||
{
|
||||
String localZtDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\ZeroTier\\One";
|
||||
String globalZtDir = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\ZeroTier\\One";
|
||||
|
||||
String authToken = "";
|
||||
Int32 port = 9993;
|
||||
|
||||
if (!File.Exists(localZtDir + "\\authtoken.secret") || !File.Exists(localZtDir + "\\zerotier-one.port"))
|
||||
{
|
||||
// launch external process to copy file into place
|
||||
String curPath = System.Reflection.Assembly.GetEntryAssembly().Location;
|
||||
int index = curPath.LastIndexOf("\\");
|
||||
curPath = curPath.Substring(0, index);
|
||||
ProcessStartInfo startInfo = new ProcessStartInfo(curPath + "\\copyutil.exe", globalZtDir + " " + localZtDir);
|
||||
startInfo.Verb = "runas";
|
||||
|
||||
|
||||
var process = Process.Start(startInfo);
|
||||
process.WaitForExit();
|
||||
}
|
||||
|
||||
authToken = readAuthToken(localZtDir + "\\authtoken.secret");
|
||||
|
||||
if ((authToken == null) || (authToken.Length <= 0))
|
||||
{
|
||||
MessageBox.Show("Unable to read ZeroTier One authtoken", "ZeroTier One");
|
||||
this.Close();
|
||||
return false;
|
||||
}
|
||||
|
||||
port = readPort(localZtDir + "\\zerotier-one.port");
|
||||
handler = new APIHandler(port, authToken);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void ToolbarItem_TrayContextMenuOpen(object sender, System.Windows.RoutedEventArgs e)
|
||||
{
|
||||
Console.WriteLine("TrayContextMenuOpen");
|
||||
}
|
||||
|
||||
private void ToolbarItem_PreviewTrayContextMenuOpen(object sender, System.Windows.RoutedEventArgs e)
|
||||
{
|
||||
Console.WriteLine("PreviewTrayContextMenuOpen");
|
||||
}
|
||||
}
|
||||
}
|
@ -66,6 +66,10 @@
|
||||
<PropertyGroup />
|
||||
<ItemGroup>
|
||||
<Reference Include="Accessibility" />
|
||||
<Reference Include="Hardcodet.Wpf.TaskbarNotification, Version=1.0.5.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Hardcodet.NotifyIcon.Wpf.1.0.8\lib\net45\Hardcodet.Wpf.TaskbarNotification.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
@ -104,6 +108,9 @@
|
||||
<Compile Include="PeersPage.xaml.cs">
|
||||
<DependentUpon>PeersPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ToolbarItem.xaml.cs">
|
||||
<DependentUpon>ToolbarItem.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ZeroTierPeerPhysicalPath.cs" />
|
||||
<Compile Include="ZeroTierPeer.cs" />
|
||||
<Compile Include="ZeroTierNetwork.cs" />
|
||||
@ -141,6 +148,10 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="ToolbarItem.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="NetworkInfoView.xaml.cs">
|
||||
@ -214,6 +225,9 @@
|
||||
</BlendEmbeddedFont>
|
||||
<Resource Include="ZeroTierIcon.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Resources\ZeroTierIcon.ico" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<Import Project="$(MSBuildExtensionsPath)\Microsoft\Expression\Blend\.NETFramework\v4.5\Microsoft.Expression.Blend.WPF.targets" />
|
||||
<PropertyGroup>
|
||||
|
Loading…
Reference in New Issue
Block a user