Fixing and extending

pull/1/head
Ogoun 5 years ago
parent effaa70f4d
commit 96a52a3705

@ -6,6 +6,7 @@ using ZeroLevel.UnitTests.Models;
namespace ZeroLevel.UnitTests
{
// In developing, not working!
public class DumpTests
{
[Fact]

@ -0,0 +1,30 @@
using System;
using System.ComponentModel;
namespace ZeroLevel.WPF
{
public abstract class BaseViewModel
: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = this.PropertyChanged;
if (null != handler)
{
this.VerifyPropertyName(propertyName);
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
public void VerifyPropertyName(string propertyName)
{
if (TypeDescriptor.GetProperties(this)[propertyName] == null)
{
throw new ArgumentException("Invalid property name", propertyName);
}
}
}
}

@ -0,0 +1,115 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace ZeroLevel.WPF
{
public class ListBoxAutoScrollBehavior
{
static readonly Dictionary<ListBox, Capture> Associations =
new Dictionary<ListBox, Capture>();
public static bool GetScrollOnNewItem(DependencyObject obj)
{
return (bool)obj.GetValue(ScrollOnNewItemProperty);
}
public static void SetScrollOnNewItem(DependencyObject obj, bool value)
{
obj.SetValue(ScrollOnNewItemProperty, value);
}
public static readonly DependencyProperty ScrollOnNewItemProperty =
DependencyProperty.RegisterAttached(
"ScrollOnNewItem",
typeof(bool),
typeof(ListBoxAutoScrollBehavior),
new UIPropertyMetadata(false, OnScrollOnNewItemChanged));
public static void OnScrollOnNewItemChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var listBox = d as ListBox;
if (listBox == null) return;
bool oldValue = (bool)e.OldValue, newValue = (bool)e.NewValue;
if (newValue == oldValue) return;
if (newValue)
{
listBox.Loaded += ListBox_Loaded;
listBox.Unloaded += ListBox_Unloaded;
var itemsSourcePropertyDescriptor = TypeDescriptor.GetProperties(listBox)["ItemsSource"];
itemsSourcePropertyDescriptor.AddValueChanged(listBox, ListBox_ItemsSourceChanged);
}
else
{
listBox.Loaded -= ListBox_Loaded;
listBox.Unloaded -= ListBox_Unloaded;
if (Associations.ContainsKey(listBox))
Associations[listBox].Dispose();
var itemsSourcePropertyDescriptor = TypeDescriptor.GetProperties(listBox)["ItemsSource"];
itemsSourcePropertyDescriptor.RemoveValueChanged(listBox, ListBox_ItemsSourceChanged);
}
}
private static void ListBox_ItemsSourceChanged(object sender, EventArgs e)
{
var listBox = (ListBox)sender;
if (Associations.ContainsKey(listBox))
Associations[listBox].Dispose();
Associations[listBox] = new Capture(listBox);
}
private static void ListBox_Unloaded(object sender, RoutedEventArgs e)
{
var listBox = (ListBox)sender;
if (Associations.ContainsKey(listBox))
Associations[listBox].Dispose();
listBox.Unloaded -= ListBox_Unloaded;
}
private static void ListBox_Loaded(object sender, RoutedEventArgs e)
{
var listBox = (ListBox)sender;
var incc = listBox.Items as INotifyCollectionChanged;
if (incc == null) return;
listBox.Loaded -= ListBox_Loaded;
Associations[listBox] = new Capture(listBox);
}
private class Capture
: IDisposable
{
private readonly ListBox listBox;
private readonly INotifyCollectionChanged incc;
public Capture(ListBox listBox)
{
this.listBox = listBox;
incc = listBox.ItemsSource as INotifyCollectionChanged;
if (incc != null)
{
incc.CollectionChanged += incc_CollectionChanged;
}
}
private void incc_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
{
listBox.ScrollIntoView(e.NewItems[0]);
listBox.SelectedItem = e.NewItems[0];
}
}
public void Dispose()
{
if (incc != null)
incc.CollectionChanged -= incc_CollectionChanged;
}
}
}
}

@ -0,0 +1,128 @@
/*
*
Sample
*
<ItemsControl ItemsSource="{Binding}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
ScrollViewer.HorizontalScrollBarVisibility ="Hidden" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controls:AlignableWrapPanel HorizontalContentAlignment="Center" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<DataTemplate>
<Grid Margin="15" HorizontalAlignment="Center">
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
*/
using System;
using System.Windows;
using System.Windows.Controls;
namespace ZeroLevel.WPF
{
/// <summary>
/// Позволяет делать горизонтальное выравнивание элементов
/// </summary>
public class AlignableWrapPanel : Panel
{
public HorizontalAlignment HorizontalContentAlignment
{
get { return (HorizontalAlignment)GetValue(HorizontalContentAlignmentProperty); }
set { SetValue(HorizontalContentAlignmentProperty, value); }
}
public static readonly DependencyProperty HorizontalContentAlignmentProperty =
DependencyProperty.Register("HorizontalContentAlignment", typeof(HorizontalAlignment), typeof(AlignableWrapPanel), new FrameworkPropertyMetadata(HorizontalAlignment.Left, FrameworkPropertyMetadataOptions.AffectsArrange));
protected override Size MeasureOverride(Size constraint)
{
Size curLineSize = new Size();
Size panelSize = new Size();
UIElementCollection children = base.InternalChildren;
for (int i = 0; i < children.Count; i++)
{
UIElement child = children[i] as UIElement;
// Flow passes its own constraint to children
child.Measure(constraint);
Size sz = child.DesiredSize;
if (curLineSize.Width + sz.Width > constraint.Width) //need to switch to another line
{
panelSize.Width = Math.Max(curLineSize.Width, panelSize.Width);
panelSize.Height += curLineSize.Height;
curLineSize = sz;
if (sz.Width > constraint.Width) // if the element is wider then the constraint - give it a separate line
{
panelSize.Width = Math.Max(sz.Width, panelSize.Width);
panelSize.Height += sz.Height;
curLineSize = new Size();
}
}
else //continue to accumulate a line
{
curLineSize.Width += sz.Width;
curLineSize.Height = Math.Max(sz.Height, curLineSize.Height);
}
}
// the last line size, if any need to be added
panelSize.Width = Math.Max(curLineSize.Width, panelSize.Width);
panelSize.Height += curLineSize.Height;
return panelSize;
}
protected override Size ArrangeOverride(Size arrangeBounds)
{
int firstInLine = 0;
Size curLineSize = new Size();
double accumulatedHeight = 0;
UIElementCollection children = this.InternalChildren;
for (int i = 0; i < children.Count; i++)
{
Size sz = children[i].DesiredSize;
if (curLineSize.Width + sz.Width > arrangeBounds.Width) //need to switch to another line
{
ArrangeLine(accumulatedHeight, curLineSize, arrangeBounds.Width, firstInLine, i);
accumulatedHeight += curLineSize.Height;
curLineSize = sz;
if (sz.Width > arrangeBounds.Width) //the element is wider then the constraint - give it a separate line
{
ArrangeLine(accumulatedHeight, sz, arrangeBounds.Width, i, ++i);
accumulatedHeight += sz.Height;
curLineSize = new Size();
}
firstInLine = i;
}
else //continue to accumulate a line
{
curLineSize.Width += sz.Width;
curLineSize.Height = Math.Max(sz.Height, curLineSize.Height);
}
}
if (firstInLine < children.Count)
ArrangeLine(accumulatedHeight, curLineSize, arrangeBounds.Width, firstInLine, children.Count);
return arrangeBounds;
}
private void ArrangeLine(double y, Size lineSize, double boundsWidth, int start, int end)
{
double x = 0;
if (this.HorizontalContentAlignment == HorizontalAlignment.Center)
{
x = (boundsWidth - lineSize.Width) / 2;
}
else if (this.HorizontalContentAlignment == HorizontalAlignment.Right)
{
x = (boundsWidth - lineSize.Width);
}
UIElementCollection children = InternalChildren;
for (int i = start; i < end; i++)
{
UIElement child = children[i];
child.Arrange(new Rect(x, y, child.DesiredSize.Width, lineSize.Height));
x += child.DesiredSize.Width;
}
}
}
}

@ -0,0 +1,27 @@
using System.Windows.Controls;
namespace ZeroLevel.WPF.Controls
{
public static class ControlUnlocker
{
public static void UnlockControl(Control control)
{
if (control != null)
{
if (control.Parent != null)
{
if (control.Parent is Panel)
{
var parent = (System.Windows.Controls.Panel)control.Parent;
parent.Children.Remove(control);
}
else if (control.Parent is ContentControl)
{
var parent = (ContentControl)control.Parent;
parent.Content = null;
}
}
}
}
}
}

@ -0,0 +1,267 @@
using System;
using System.Windows;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
namespace ZeroLevel.WPF
{
public static class VirtualToggleButton
{
#region attached properties
#region IsChecked
/// <summary>
/// IsChecked Attached Dependency Property
/// </summary>
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.RegisterAttached("IsChecked", typeof(Nullable<bool>), typeof(VirtualToggleButton),
new FrameworkPropertyMetadata((Nullable<bool>)false,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
new PropertyChangedCallback(OnIsCheckedChanged)));
/// <summary>
/// Gets the IsChecked property. This dependency property
/// indicates whether the toggle button is checked.
/// </summary>
public static Nullable<bool> GetIsChecked(DependencyObject d)
{
return (Nullable<bool>)d.GetValue(IsCheckedProperty);
}
/// <summary>
/// Sets the IsChecked property. This dependency property
/// indicates whether the toggle button is checked.
/// </summary>
public static void SetIsChecked(DependencyObject d, Nullable<bool> value)
{
d.SetValue(IsCheckedProperty, value);
}
/// <summary>
/// Handles changes to the IsChecked property.
/// </summary>
private static void OnIsCheckedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
UIElement pseudobutton = d as UIElement;
if (pseudobutton != null)
{
Nullable<bool> newValue = (Nullable<bool>)e.NewValue;
if (newValue == true)
{
RaiseCheckedEvent(pseudobutton);
}
else if (newValue == false)
{
RaiseUncheckedEvent(pseudobutton);
}
else
{
RaiseIndeterminateEvent(pseudobutton);
}
}
}
#endregion
#region IsThreeState
/// <summary>
/// IsThreeState Attached Dependency Property
/// </summary>
public static readonly DependencyProperty IsThreeStateProperty =
DependencyProperty.RegisterAttached("IsThreeState", typeof(bool), typeof(VirtualToggleButton),
new FrameworkPropertyMetadata((bool)false));
/// <summary>
/// Gets the IsThreeState property. This dependency property
/// indicates whether the control supports two or three states.
/// IsChecked can be set to null as a third state when IsThreeState is true.
/// </summary>
public static bool GetIsThreeState(DependencyObject d)
{
return (bool)d.GetValue(IsThreeStateProperty);
}
/// <summary>
/// Sets the IsThreeState property. This dependency property
/// indicates whether the control supports two or three states.
/// IsChecked can be set to null as a third state when IsThreeState is true.
/// </summary>
public static void SetIsThreeState(DependencyObject d, bool value)
{
d.SetValue(IsThreeStateProperty, value);
}
#endregion
#region IsVirtualToggleButton
/// <summary>
/// IsVirtualToggleButton Attached Dependency Property
/// </summary>
public static readonly DependencyProperty IsVirtualToggleButtonProperty =
DependencyProperty.RegisterAttached("IsVirtualToggleButton", typeof(bool), typeof(VirtualToggleButton),
new FrameworkPropertyMetadata((bool)false,
new PropertyChangedCallback(OnIsVirtualToggleButtonChanged)));
/// <summary>
/// Gets the IsVirtualToggleButton property. This dependency property
/// indicates whether the object to which the property is attached is treated as a VirtualToggleButton.
/// If true, the object will respond to keyboard and mouse input the same way a ToggleButton would.
/// </summary>
public static bool GetIsVirtualToggleButton(DependencyObject d)
{
return (bool)d.GetValue(IsVirtualToggleButtonProperty);
}
/// <summary>
/// Sets the IsVirtualToggleButton property. This dependency property
/// indicates whether the object to which the property is attached is treated as a VirtualToggleButton.
/// If true, the object will respond to keyboard and mouse input the same way a ToggleButton would.
/// </summary>
public static void SetIsVirtualToggleButton(DependencyObject d, bool value)
{
d.SetValue(IsVirtualToggleButtonProperty, value);
}
/// <summary>
/// Handles changes to the IsVirtualToggleButton property.
/// </summary>
private static void OnIsVirtualToggleButtonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
IInputElement element = d as IInputElement;
if (element != null)
{
if ((bool)e.NewValue)
{
element.MouseLeftButtonDown += OnMouseLeftButtonDown;
element.KeyDown += OnKeyDown;
}
else
{
element.MouseLeftButtonDown -= OnMouseLeftButtonDown;
element.KeyDown -= OnKeyDown;
}
}
}
#endregion
#endregion
#region routed events
#region Checked
/// <summary>
/// A static helper method to raise the Checked event on a target element.
/// </summary>
/// <param name="target">UIElement or ContentElement on which to raise the event</param>
internal static RoutedEventArgs RaiseCheckedEvent(UIElement target)
{
if (target == null) return null;
RoutedEventArgs args = new RoutedEventArgs();
args.RoutedEvent = ToggleButton.CheckedEvent;
RaiseEvent(target, args);
return args;
}
#endregion
#region Unchecked
/// <summary>
/// A static helper method to raise the Unchecked event on a target element.
/// </summary>
/// <param name="target">UIElement or ContentElement on which to raise the event</param>
internal static RoutedEventArgs RaiseUncheckedEvent(UIElement target)
{
if (target == null) return null;
RoutedEventArgs args = new RoutedEventArgs();
args.RoutedEvent = ToggleButton.UncheckedEvent;
RaiseEvent(target, args);
return args;
}
#endregion
#region Indeterminate
/// <summary>
/// A static helper method to raise the Indeterminate event on a target element.
/// </summary>
/// <param name="target">UIElement or ContentElement on which to raise the event</param>
internal static RoutedEventArgs RaiseIndeterminateEvent(UIElement target)
{
if (target == null) return null;
RoutedEventArgs args = new RoutedEventArgs();
args.RoutedEvent = ToggleButton.IndeterminateEvent;
RaiseEvent(target, args);
return args;
}
#endregion
#endregion
#region private methods
private static void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
e.Handled = true;
UpdateIsChecked(sender as DependencyObject);
}
private static void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.OriginalSource == sender)
{
if (e.Key == Key.Space)
{
// ignore alt+space which invokes the system menu
if ((Keyboard.Modifiers & ModifierKeys.Alt) == ModifierKeys.Alt) return;
UpdateIsChecked(sender as DependencyObject);
e.Handled = true;
}
else if (e.Key == Key.Enter && (bool)(sender as DependencyObject).GetValue(KeyboardNavigation.AcceptsReturnProperty))
{
UpdateIsChecked(sender as DependencyObject);
e.Handled = true;
}
}
}
private static void UpdateIsChecked(DependencyObject d)
{
Nullable<bool> isChecked = GetIsChecked(d);
if (isChecked == true)
{
SetIsChecked(d, GetIsThreeState(d) ? (Nullable<bool>)null : (Nullable<bool>)false);
}
else
{
SetIsChecked(d, isChecked.HasValue);
}
}
private static void RaiseEvent(DependencyObject target, RoutedEventArgs args)
{
if (target is UIElement)
{
(target as UIElement).RaiseEvent(args);
}
else if (target is ContentElement)
{
(target as ContentElement).RaiseEvent(args);
}
}
#endregion
}
}

@ -0,0 +1,33 @@
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Markup;
namespace ZeroLevel.WPF
{
public abstract class BaseConvertor<T>
: MarkupExtension, IValueConverter
where T : class, new()
{
/// <summary>
/// Must be implemented in inheritor.
/// </summary>
public abstract object Convert(object value, Type targetType, object parameter, CultureInfo culture);
/// <summary>
/// Override if needed.
/// </summary>
public virtual object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
throw new NotImplementedException();
}
#region MarkupExtension members
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
#endregion
}
}

@ -0,0 +1,34 @@
using System;
using System.Globalization;
using System.Windows;
namespace ZeroLevel.WPF
{
public sealed class BoolToVisibilityConverter : BaseConvertor<BoolToVisibilityConverter>
{
public Visibility TrueValue { get; set; }
public Visibility FalseValue { get; set; }
public BoolToVisibilityConverter()
{
TrueValue = Visibility.Visible;
FalseValue = Visibility.Collapsed;
}
public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is bool))
return null;
return (bool)value ? TrueValue : FalseValue;
}
public override object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (Equals(value, TrueValue))
return true;
if (Equals(value, FalseValue))
return false;
return null;
}
}
}

@ -0,0 +1,43 @@
using System;
using System.Windows.Data;
namespace ZeroLevel.WPF
{
public class BooleanAndConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
foreach (object value in values)
{
if ((value is bool) && (bool)value == false)
{
return false;
}
}
return true;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException("BooleanAndConverter is a OneWay converter.");
}
}
public class BooleanOrConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
foreach (object value in values)
{
if ((value is bool) && (bool)value == true)
{
return true;
}
}
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException("BooleanAndConverter is a OneWay converter.");
}
}
}

@ -0,0 +1,65 @@
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Media.Imaging;
namespace ZeroLevel.WPF
{
public static class BitmapSourceHelper
{
public static BitmapSource LoadBitmap(Bitmap bmp)
{
if (ImageFormat.Jpeg.Equals(bmp.RawFormat))
{
return LoadBitmap(bmp, ImageFormat.Jpeg);
}
else if (ImageFormat.Png.Equals(bmp.RawFormat))
{
return LoadBitmap(bmp, ImageFormat.Png);
}
else if (ImageFormat.Gif.Equals(bmp.RawFormat))
{
return LoadBitmap(bmp, ImageFormat.Gif);
}
else if (ImageFormat.Bmp.Equals(bmp.RawFormat) || ImageFormat.MemoryBmp.Equals(bmp.RawFormat))
{
return LoadBitmap(bmp, ImageFormat.Bmp);
}
else if (ImageFormat.Emf.Equals(bmp.RawFormat))
{
return LoadBitmap(bmp, ImageFormat.Emf);
}
else if (ImageFormat.Exif.Equals(bmp.RawFormat))
{
return LoadBitmap(bmp, ImageFormat.Exif);
}
else if (ImageFormat.Icon.Equals(bmp.RawFormat))
{
return LoadBitmap(bmp, ImageFormat.Icon);
}
else if (ImageFormat.Tiff.Equals(bmp.RawFormat))
{
return LoadBitmap(bmp, ImageFormat.Tiff);
}
else if (ImageFormat.Wmf.Equals(bmp.RawFormat))
{
return LoadBitmap(bmp, ImageFormat.Wmf);
}
return LoadBitmap(bmp, ImageFormat.Bmp);
}
public static BitmapSource LoadBitmap(Bitmap bmp, ImageFormat format)
{
var bi = new BitmapImage();
using (var ms = new System.IO.MemoryStream())
{
bi.BeginInit();
bi.StreamSource = ms;
bi.CacheOption = BitmapCacheOption.OnLoad;
bmp.Save(ms, format);
bi.EndInit();
bi.Freeze();
}
return bi;
}
}
}

@ -0,0 +1,33 @@
using System;
namespace ZeroLevel.WPF
{
public class RelayCommand
: System.Windows.Input.ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _execute;
public RelayCommand(Predicate<object> canExecute, Action<object> execute)
{
_canExecute = canExecute;
_execute = execute;
}
public event EventHandler CanExecuteChanged
{
add => System.Windows.Input.CommandManager.RequerySuggested += value;
remove => System.Windows.Input.CommandManager.RequerySuggested -= value;
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
}

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="System.Drawing.Common" Version="4.7.0" />
<PackageReference Include="WindowsBase" Version="4.6.1055" />
</ItemGroup>
<ItemGroup>
<Reference Include="PresentationCore">
<HintPath>..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\PresentationCore.dll</HintPath>
</Reference>
<Reference Include="PresentationFramework">
<HintPath>..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\PresentationFramework.dll</HintPath>
</Reference>
<Reference Include="System.Xaml">
<HintPath>..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2\System.Xaml.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

@ -35,7 +35,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ConfigurationTests", "Confi
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DependencyInjectionTests", "DependencyInjectionTests\DependencyInjectionTests.csproj", "{665B38E3-A5F2-4AD0-946B-209D80C1AA40}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZeroLevel.Logger", "ZeroLevel.Logger\ZeroLevel.Logger.csproj", "{D1C061DB-3565-43C3-B8F3-628DE4908750}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ZeroLevel.Logger", "ZeroLevel.Logger\ZeroLevel.Logger.csproj", "{D1C061DB-3565-43C3-B8F3-628DE4908750}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZeroLevel.WPF", "ZeroLevel.WPF\ZeroLevel.WPF.csproj", "{0D70D688-1E21-4E9D-AA49-4D255DF27D8D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@ -227,6 +229,18 @@ Global
{D1C061DB-3565-43C3-B8F3-628DE4908750}.Release|x64.Build.0 = Release|Any CPU
{D1C061DB-3565-43C3-B8F3-628DE4908750}.Release|x86.ActiveCfg = Release|Any CPU
{D1C061DB-3565-43C3-B8F3-628DE4908750}.Release|x86.Build.0 = Release|Any CPU
{0D70D688-1E21-4E9D-AA49-4D255DF27D8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0D70D688-1E21-4E9D-AA49-4D255DF27D8D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D70D688-1E21-4E9D-AA49-4D255DF27D8D}.Debug|x64.ActiveCfg = Debug|Any CPU
{0D70D688-1E21-4E9D-AA49-4D255DF27D8D}.Debug|x64.Build.0 = Debug|Any CPU
{0D70D688-1E21-4E9D-AA49-4D255DF27D8D}.Debug|x86.ActiveCfg = Debug|Any CPU
{0D70D688-1E21-4E9D-AA49-4D255DF27D8D}.Debug|x86.Build.0 = Debug|Any CPU
{0D70D688-1E21-4E9D-AA49-4D255DF27D8D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D70D688-1E21-4E9D-AA49-4D255DF27D8D}.Release|Any CPU.Build.0 = Release|Any CPU
{0D70D688-1E21-4E9D-AA49-4D255DF27D8D}.Release|x64.ActiveCfg = Release|Any CPU
{0D70D688-1E21-4E9D-AA49-4D255DF27D8D}.Release|x64.Build.0 = Release|Any CPU
{0D70D688-1E21-4E9D-AA49-4D255DF27D8D}.Release|x86.ActiveCfg = Release|Any CPU
{0D70D688-1E21-4E9D-AA49-4D255DF27D8D}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

@ -0,0 +1,35 @@
using System;
using System.Threading.Tasks;
namespace ZeroLevel.Services.Extensions
{
public static class TaskExtension
{
public static T WaitResult<T>(this Task<T> task)
{
if (task == null)
{
throw new ArgumentNullException(nameof(task));
}
task.Wait();
if (task.IsFaulted)
{
if (task.Exception != null) throw task.Exception;
}
return task.Result;
}
public static void WaitWithoutResult(this Task task)
{
if (task == null)
{
throw new ArgumentNullException(nameof(task));
}
task.Wait();
if (task.IsFaulted)
{
if (task.Exception != null) throw task.Exception;
}
}
}
}

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
namespace ZeroLevel.Services.Reflection
{
/// <summary>
/// Performs read of stack trace
/// </summary>
public static class StackTraceReader
{
/// <summary>
/// Read current stack trace
/// </summary>
/// <returns>Result - enumerable of tuples as 'Type':'MethodName'</returns>
public static Tuple<string, string>[] ReadFrames()
{
var result = new List<Tuple<string, string>>();
var stackTrace = new StackTrace();
foreach (var frame in stackTrace.GetFrames() ?? Enumerable.Empty<StackFrame>())
{
var method = frame.GetMethod();
if (method != null && method.DeclaringType != null)
{
var type = method.DeclaringType.Name;
if (false == type.Equals("StackTraceReader", StringComparison.Ordinal))
{
result.Add(new Tuple<string, string>(type, method.Name));
}
}
}
return result.ToArray();
}
}
}

@ -121,6 +121,7 @@ namespace ZeroLevel.Services.Serialization
public static T DeserializeCompatible<T>(byte[] data)
{
if (data == null || data.Length == 0) return default(T);
if (typeof(IBinarySerializable).IsAssignableFrom(typeof(T)))
{
using (var reader = new MemoryStreamReader(data))
@ -168,6 +169,7 @@ namespace ZeroLevel.Services.Serialization
public static T Copy<T>(T value)
where T : IBinarySerializable
{
if (default == value) return default;
using (var writer = new MemoryStreamWriter())
{
value.Serialize(writer);

@ -0,0 +1,286 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Text;
namespace ZeroLevel.Services.Windows
{
public sealed class WindowsLibraryLoader
{
#region Fields
private const string ProcessorArchitecture = "PROCESSOR_ARCHITECTURE";
private const string DllFileExtension = ".dll";
private const string DllDirectory = "dll";
private readonly Dictionary<string, int> _ProcessorArchitectureAddressWidthPlatforms = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase)
{
{"x86", 4},
{"AMD64", 8},
{"IA64", 8},
{"ARM", 4}
};
private readonly Dictionary<string, string> _ProcessorArchitecturePlatforms = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{"x86", "x86"},
{"AMD64", "x64"},
{"IA64", "Itanium"},
{"ARM", "WinCE"}
};
private readonly object _SyncLock = new object();
private static readonly IDictionary<string, IntPtr> LoadedLibraries = new Dictionary<string, IntPtr>();
[System.Runtime.InteropServices.DllImport("kernel32", EntryPoint = "LoadLibrary", CallingConvention = System.Runtime.InteropServices.CallingConvention.Winapi, SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
private static extern IntPtr Win32LoadLibrary(string dllPath);
#endregion
#region Properties
public static bool IsCurrentPlatformSupported()
{
return RuntimeInformation.IsOSPlatform(System.Runtime.InteropServices.OSPlatform.Windows);
}
public static bool IsWindows()
{
return Environment.OSVersion.Platform == PlatformID.Win32NT ||
Environment.OSVersion.Platform == PlatformID.Win32S ||
Environment.OSVersion.Platform == PlatformID.Win32Windows ||
Environment.OSVersion.Platform == PlatformID.WinCE;
}
#endregion
#region Methods
#region Helpers
private static string FixUpDllFileName(string fileName)
{
if (string.IsNullOrEmpty(fileName))
return fileName;
if (!System.Runtime.InteropServices.RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
return fileName;
if (!fileName.EndsWith(DllFileExtension, StringComparison.OrdinalIgnoreCase))
return $"{fileName}{DllFileExtension}";
return fileName;
}
private ProcessArchitectureInfo GetProcessArchitecture()
{
// BUG: Will this always be reliable?
var processArchitecture = Environment.GetEnvironmentVariable(ProcessorArchitecture);
var processInfo = new ProcessArchitectureInfo();
if (!string.IsNullOrEmpty(processArchitecture))
{
// Sanity check
processInfo.Architecture = processArchitecture;
}
else
{
processInfo.AddWarning("Failed to detect processor architecture, falling back to x86.");
processInfo.Architecture = (IntPtr.Size == 8) ? "x64" : "x86";
}
var addressWidth = this._ProcessorArchitectureAddressWidthPlatforms[processInfo.Architecture];
if (addressWidth != IntPtr.Size)
{
if (String.Equals(processInfo.Architecture, "AMD64", StringComparison.OrdinalIgnoreCase) && IntPtr.Size == 4)
{
// fall back to x86 if detected x64 but has an address width of 32 bits.
processInfo.Architecture = "x86";
processInfo.AddWarning("Expected the detected processing architecture of {0} to have an address width of {1} Bytes but was {2} Bytes, falling back to x86.", processInfo.Architecture, addressWidth, IntPtr.Size);
}
else
{
// no fallback possible
processInfo.AddWarning("Expected the detected processing architecture of {0} to have an address width of {1} Bytes but was {2} Bytes.", processInfo.Architecture, addressWidth, IntPtr.Size);
}
}
return processInfo;
}
private string GetPlatformName(string processorArchitecture)
{
if (String.IsNullOrEmpty(processorArchitecture))
return null;
string platformName;
if (this._ProcessorArchitecturePlatforms.TryGetValue(processorArchitecture, out platformName))
{
return platformName;
}
return null;
}
public void LoadLibraries(IEnumerable<string> dlls)
{
if (!IsWindows())
return;
foreach (var dll in dlls)
LoadLibrary(dll);
}
private void LoadLibrary(string dllName)
{
if (!IsCurrentPlatformSupported())
return;
try
{
lock (this._SyncLock)
{
if (LoadedLibraries.ContainsKey(dllName))
return;
var processArch = GetProcessArchitecture();
IntPtr dllHandle;
// Try loading from executing assembly domain
var executingAssembly = GetType().GetTypeInfo().Assembly;
var baseDirectory = Path.GetDirectoryName(executingAssembly.Location);
dllHandle = LoadLibraryInternal(dllName, baseDirectory, processArch);
if (dllHandle != IntPtr.Zero) return;
// Gets the pathname of the base directory that the assembly resolver uses to probe for assemblies.
// https://github.com/dotnet/corefx/issues/2221
baseDirectory = AppContext.BaseDirectory;
dllHandle = LoadLibraryInternal(dllName, baseDirectory, processArch);
if (dllHandle != IntPtr.Zero) return;
// Finally try the working directory
baseDirectory = Path.GetFullPath(Directory.GetCurrentDirectory());
dllHandle = LoadLibraryInternal(dllName, baseDirectory, processArch);
if (dllHandle != IntPtr.Zero) return;
var errorMessage = new StringBuilder();
errorMessage.Append($"Failed to find dll \"{dllName}\", for processor architecture {processArch.Architecture}.");
if (processArch.HasWarnings)
{
// include process detection warnings
errorMessage.Append($"\r\nWarnings: \r\n{processArch.WarningText()}");
}
throw new Exception(errorMessage.ToString());
}
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
}
}
private IntPtr LoadLibraryInternal(string dllName, string baseDirectory, ProcessArchitectureInfo processArchInfo)
{
var platformName = GetPlatformName(processArchInfo.Architecture);
var expectedDllDirectory = Path.Combine(
Path.Combine(baseDirectory, DllDirectory), platformName);
return this.LoadLibraryRaw(dllName, expectedDllDirectory);
}
private IntPtr LoadLibraryRaw(string dllName, string baseDirectory)
{
var libraryHandle = IntPtr.Zero;
var fileName = FixUpDllFileName(Path.Combine(baseDirectory, dllName));
// Show where we're trying to load the file from
Debug.WriteLine($"Trying to load native library \"{fileName}\"...");
if (File.Exists(fileName))
{
// Attempt to load dll
try
{
libraryHandle = Win32LoadLibrary(fileName);
if (libraryHandle != IntPtr.Zero)
{
// library has been loaded
Debug.WriteLine($"Successfully loaded native library \"{fileName}\".");
LoadedLibraries.Add(dllName, libraryHandle);
}
else
{
Debug.WriteLine($"Failed to load native library \"{fileName}\".\r\nCheck windows event log.");
}
}
catch (Exception e)
{
var lastError = Marshal.GetLastWin32Error();
Debug.WriteLine($"Failed to load native library \"{fileName}\".\r\nLast Error:{lastError}\r\nCheck inner exception and\\or windows event log.\r\nInner Exception: {e}");
}
}
else
{
Debug.WriteLine(string.Format(System.Globalization.CultureInfo.CurrentCulture, "The native library \"{0}\" does not exist.", fileName));
}
return libraryHandle;
}
#endregion
#endregion
private class ProcessArchitectureInfo
{
#region Constructors
public ProcessArchitectureInfo()
{
this.Warnings = new List<string>();
}
#endregion
#region Properties
public string Architecture
{
get; set;
}
private List<string> Warnings
{
get;
}
#endregion
#region Methods
public void AddWarning(string format, params object[] args)
{
Warnings.Add(String.Format(format, args));
}
public bool HasWarnings => Warnings.Count > 0;
public string WarningText()
{
return string.Join("\r\n", Warnings.ToArray());
}
#endregion
}
}
}

@ -6,16 +6,16 @@
</Description>
<Authors>ogoun</Authors>
<Company>ogoun</Company>
<AssemblyVersion>3.1.7.0</AssemblyVersion>
<PackageReleaseNotes>Fixes</PackageReleaseNotes>
<AssemblyVersion>3.1.8.0</AssemblyVersion>
<PackageReleaseNotes>Fixing and extending</PackageReleaseNotes>
<PackageProjectUrl>https://github.com/ogoun/Zero/wiki</PackageProjectUrl>
<Copyright>Copyright Ogoun 2019</Copyright>
<PackageLicenseUrl></PackageLicenseUrl>
<PackageIconUrl>https://raw.githubusercontent.com/ogoun/Zero/master/zero.png</PackageIconUrl>
<RepositoryUrl>https://github.com/ogoun/Zero</RepositoryUrl>
<RepositoryType>GitHub</RepositoryType>
<Version>3.1.7</Version>
<FileVersion>3.1.7.0</FileVersion>
<Version>3.1.8</Version>
<FileVersion>3.1.8.0</FileVersion>
<Platforms>AnyCPU;x64</Platforms>
</PropertyGroup>

Loading…
Cancel
Save

Powered by TurnKey Linux.