dev 19-3-25
This commit is contained in:
1 parent
53228907fc
commit
ce18931d5d
29 files changed
+1474
-85
No files matched your search
@@ -0,0 +1,152 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Data;
|
||||
using HandyControl.Tools;
|
||||
using HandyControl.Tools.Interop;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class NotifyIcon : FrameworkElement
|
||||
{
|
||||
private bool _added;
|
||||
|
||||
private readonly object _syncObj = new object();
|
||||
|
||||
private WindowClass _windowClass;
|
||||
|
||||
private readonly int _id;
|
||||
|
||||
private static int NextId;
|
||||
|
||||
private ImageSource _icon;
|
||||
|
||||
private IconHandle _defaultLargeIconHandle;
|
||||
|
||||
private IconHandle _defaultSmallIconHandle;
|
||||
|
||||
private IconHandle _currentLargeIconHandle;
|
||||
|
||||
private IconHandle _currentSmallIconHandle;
|
||||
|
||||
private const int WmTrayMouseMessage = NativeMethods.WM_USER + 1024;
|
||||
|
||||
public NotifyIcon()
|
||||
{
|
||||
_id = ++NextId;
|
||||
_windowClass = new WindowClass();
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
|
||||
"Icon", typeof(ImageSource), typeof(NotifyIcon), new PropertyMetadata(default(ImageSource), OnIconChanged));
|
||||
|
||||
private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var ctl = (NotifyIcon) d;
|
||||
ctl._icon = (ImageSource) e.NewValue;
|
||||
ctl.UpdateIcon();
|
||||
}
|
||||
|
||||
public ImageSource Icon
|
||||
{
|
||||
get => (ImageSource) GetValue(IconProperty);
|
||||
set => SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
private void UpdateIcon()
|
||||
{
|
||||
IconHandle largeIconHandle;
|
||||
IconHandle smallIconHandle;
|
||||
|
||||
if (_icon != null)
|
||||
{
|
||||
IconHelper.GetIconHandlesFromImageSource(_icon, out largeIconHandle, out smallIconHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_defaultLargeIconHandle == null && _defaultSmallIconHandle == null)
|
||||
{
|
||||
IconHelper.GetDefaultIconHandles(out largeIconHandle, out smallIconHandle);
|
||||
_defaultLargeIconHandle = largeIconHandle;
|
||||
_defaultSmallIconHandle = smallIconHandle;
|
||||
}
|
||||
else
|
||||
{
|
||||
largeIconHandle = _defaultLargeIconHandle;
|
||||
smallIconHandle = _defaultSmallIconHandle;
|
||||
}
|
||||
}
|
||||
|
||||
if (_currentLargeIconHandle != null && _currentLargeIconHandle != _defaultLargeIconHandle)
|
||||
{
|
||||
_currentLargeIconHandle.Dispose();
|
||||
}
|
||||
|
||||
if (_currentSmallIconHandle != null && _currentSmallIconHandle != _defaultSmallIconHandle)
|
||||
{
|
||||
_currentSmallIconHandle.Dispose();
|
||||
}
|
||||
|
||||
_currentLargeIconHandle = largeIconHandle;
|
||||
_currentSmallIconHandle = smallIconHandle;
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BalloonTipIconProperty = DependencyProperty.Register(
|
||||
"BalloonTipIcon", typeof(ToolTipIcon), typeof(NotifyIcon), new PropertyMetadata(default(ToolTipIcon)));
|
||||
|
||||
public ToolTipIcon BalloonTipIcon
|
||||
{
|
||||
get => (ToolTipIcon) GetValue(BalloonTipIconProperty);
|
||||
set => SetValue(BalloonTipIconProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty BalloonTipTitleProperty = DependencyProperty.Register(
|
||||
"BalloonTipTitle", typeof(string), typeof(NotifyIcon), new PropertyMetadata(default(string)));
|
||||
|
||||
public string BalloonTipTitle
|
||||
{
|
||||
get => (string) GetValue(BalloonTipTitleProperty);
|
||||
set => SetValue(BalloonTipTitleProperty, value);
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
|
||||
"Text", typeof(string), typeof(NotifyIcon), new PropertyMetadata(default(string)));
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => (string) GetValue(TextProperty);
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public void ShowBalloonTip(int timeout, string tipTitle, string tipText, ToolTipIcon tipIcon)
|
||||
{
|
||||
if (timeout < 0) return;
|
||||
if (string.IsNullOrEmpty(tipTitle)) return;
|
||||
|
||||
if (_added)
|
||||
{
|
||||
if (DesignerHelper.IsInDesignMode) return;
|
||||
|
||||
IntSecurity.UnrestrictedWindows.Demand();
|
||||
|
||||
var data = new NOTIFYICONDATA
|
||||
{
|
||||
hWnd = _windowClass.MessageWindowHandle,
|
||||
uID = _id,
|
||||
uFlags = NativeMethods.NIF_INFO,
|
||||
uTimeoutOrVersion = timeout,
|
||||
szInfoTitle = tipTitle,
|
||||
szInfo = tipText
|
||||
};
|
||||
|
||||
switch (tipIcon)
|
||||
{
|
||||
case ToolTipIcon.Info: data.dwInfoFlags = NativeMethods.NIIF_INFO; break;
|
||||
case ToolTipIcon.Warning: data.dwInfoFlags = NativeMethods.NIIF_WARNING; break;
|
||||
case ToolTipIcon.Error: data.dwInfoFlags = NativeMethods.NIIF_ERROR; break;
|
||||
case ToolTipIcon.None: data.dwInfoFlags = NativeMethods.NIIF_NONE; break;
|
||||
}
|
||||
UnsafeNativeMethods.Shell_NotifyIcon(NativeMethods.NIM_MODIFY, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
internal class NotifyIconNativeWindow
|
||||
{
|
||||
internal NotifyIcon Reference;
|
||||
|
||||
private GCHandle _rootRef;
|
||||
|
||||
public void LockReference(bool locked)
|
||||
{
|
||||
if (locked)
|
||||
{
|
||||
if (!_rootRef.IsAllocated)
|
||||
{
|
||||
_rootRef = GCHandle.Alloc(Reference, GCHandleType.Normal);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_rootRef.IsAllocated)
|
||||
{
|
||||
_rootRef.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Media;
|
||||
using HandyControl.Tools;
|
||||
|
||||
namespace HandyControl.Controls
|
||||
{
|
||||
public class NotifyIcon : FrameworkElement
|
||||
{
|
||||
private Popup _trayPopup;
|
||||
|
||||
private readonly object _syncObj = new object();
|
||||
|
||||
public static readonly DependencyProperty IconProperty = DependencyProperty.Register(
|
||||
"Icon", typeof(ImageSource), typeof(NotifyIcon), new PropertyMetadata(default(ImageSource)));
|
||||
|
||||
public ImageSource Icon
|
||||
{
|
||||
get => (ImageSource) GetValue(IconProperty);
|
||||
set => SetValue(IconProperty, value);
|
||||
}
|
||||
|
||||
private void UpdateIcon(bool showIconInTray)
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (DesignerHelper.IsInDesignMode) return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace HandyControl.Data
|
||||
{
|
||||
public enum ToolTipIcon
|
||||
{
|
||||
None,
|
||||
Info,
|
||||
Warning,
|
||||
Error
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
using HandyControl.Tools.Interop;
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace HandyControl.Data
|
||||
{
|
||||
public sealed class Icon : IDisposable
|
||||
{
|
||||
private IntPtr _handle;
|
||||
|
||||
~Icon()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
|
||||
internal Icon(IntPtr handle)
|
||||
{
|
||||
if (handle == IntPtr.Zero)
|
||||
{
|
||||
throw new ArgumentException("InvalidGDIHandle", typeof(Icon).Name);
|
||||
}
|
||||
_handle = handle;
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "UnusedParameter.Local")]
|
||||
private void Dispose(bool disposing)
|
||||
{
|
||||
if (_handle != IntPtr.Zero)
|
||||
{
|
||||
UnsafeNativeMethods.DestroyIcon(_handle);
|
||||
_handle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,8 +115,9 @@
|
||||
<Compile Include="Controls\Other\ChatBubble.cs" />
|
||||
<Compile Include="Controls\Other\Dialog.cs" />
|
||||
<Compile Include="Controls\Other\GotoTop.cs" />
|
||||
<Compile Include="Controls\Other\NotifyIcon.cs" />
|
||||
<Compile Include="Controls\NotifyIcon\NotifyIcon.cs" />
|
||||
<Compile Include="Controls\Other\Gravatar.cs" />
|
||||
<Compile Include="Controls\NotifyIcon\NotifyIconNativeWindow.cs" />
|
||||
<Compile Include="Controls\Panel\SimplePanel.cs" />
|
||||
<Compile Include="Controls\ProgressBar\WaveProgressBar.cs" />
|
||||
<Compile Include="Controls\Transfer\Transfer.cs" />
|
||||
@@ -172,11 +173,13 @@
|
||||
<Compile Include="Data\Enum\SkinType.cs" />
|
||||
<Compile Include="Data\Enum\StepStatus.cs" />
|
||||
<Compile Include="Data\Enum\TipPlacement.cs" />
|
||||
<Compile Include="Data\Enum\ToolTipIcon.cs" />
|
||||
<Compile Include="Data\Gif\GifFrameDimension.cs" />
|
||||
<Compile Include="Data\Gif\GifImageInfo.cs" />
|
||||
<Compile Include="Data\Gif\GifPropertyItem.cs" />
|
||||
<Compile Include="Data\Gif\GifPropertyItemInternal.cs" />
|
||||
<Compile Include="Data\Gif\GPStream.cs" />
|
||||
<Compile Include="Data\Icon.cs" />
|
||||
<Compile Include="Data\MessageBoxInfo.cs" />
|
||||
<Compile Include="Data\ResourceToken.cs" />
|
||||
<Compile Include="Data\SystemVersionInfo.cs" />
|
||||
@@ -224,8 +227,13 @@
|
||||
<Compile Include="Expression\Media\UnitType.cs" />
|
||||
<Compile Include="Expression\Shapes\Arc.cs" />
|
||||
<Compile Include="Expression\Shapes\PrimitiveShape.cs" />
|
||||
<Compile Include="Tools\Helper\CreateParams.cs" />
|
||||
<Compile Include="Tools\Helper\DesignerHelper.cs" />
|
||||
<Compile Include="Tools\Helper\ExternDllHelper.cs" />
|
||||
<Compile Include="Tools\Helper\IconHelper.cs" />
|
||||
<Compile Include="Tools\Interop\IntSecurity.cs" />
|
||||
<Compile Include="Tools\Interop\NOTIFYICONDATA.cs" />
|
||||
<Compile Include="Tools\Helper\SecurityHelper.cs" />
|
||||
<Compile Include="Tools\Helper\SingleOpenHelper.cs" />
|
||||
<Compile Include="Controls\TabControl\TabControl.cs" />
|
||||
<Compile Include="Controls\TabControl\TabItem.cs" />
|
||||
@@ -305,6 +313,20 @@
|
||||
<Compile Include="Tools\Converter\TreeViewItemMarginConverter.cs" />
|
||||
<Compile Include="Tools\Extension\ColorExtension.cs" />
|
||||
<Compile Include="Tools\Extension\UIElementExtension.cs" />
|
||||
<Compile Include="Tools\Interop\BitmapHandle.cs" />
|
||||
<Compile Include="Tools\Interop\BITMAPINFO.cs" />
|
||||
<Compile Include="Tools\Interop\CommonHandles.cs" />
|
||||
<Compile Include="Tools\Interop\ExternDll.cs" />
|
||||
<Compile Include="Tools\Interop\HandleCollector.cs" />
|
||||
<Compile Include="Tools\Interop\IconHandle.cs" />
|
||||
<Compile Include="Tools\Interop\ICONINFO.cs" />
|
||||
<Compile Include="Tools\Interop\NativeMethods.cs" />
|
||||
<Compile Include="Tools\Interop\NativeValues.cs" />
|
||||
<Compile Include="Tools\Interop\SafeFileMappingHandle.cs" />
|
||||
<Compile Include="Tools\Interop\UnsafeNativeMethods.cs" />
|
||||
<Compile Include="Tools\Interop\WindowClass.cs" />
|
||||
<Compile Include="Tools\Interop\WNDCLASS.cs" />
|
||||
<Compile Include="Tools\Interop\WpfSafeHandle.cs" />
|
||||
<Compile Include="Tools\MouseDragElementBehaviorEx.cs" />
|
||||
<Compile Include="Tools\StyleSelector\RadioGroupItemStyleSelector.cs" />
|
||||
<Compile Include="Tools\RegularJudgment.cs" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*refrence from https://github.com/lbugnion/mvvmlight*/
|
||||
// reference from https://github.com/lbugnion/mvvmlight
|
||||
|
||||
//The MIT License(MIT)
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
internal class CreateParams
|
||||
{
|
||||
public string ClassName { get; set; }
|
||||
|
||||
public string Caption { get; set; }
|
||||
|
||||
public int Style { get; set; }
|
||||
|
||||
public int ExStyle{ get; set; }
|
||||
|
||||
public int ClassStyle { get; set; }
|
||||
|
||||
public int X { get; set; }
|
||||
|
||||
public int Y { get; set; }
|
||||
|
||||
public int Width { get; set; }
|
||||
|
||||
public int Height { get; set; }
|
||||
|
||||
public IntPtr Parent { get; set; }
|
||||
|
||||
public object Param { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
var sb = new StringBuilder(64);
|
||||
sb.Append("CreateParams {'");
|
||||
sb.Append(ClassName);
|
||||
sb.Append("', '");
|
||||
sb.Append(Caption);
|
||||
sb.Append("', 0x");
|
||||
sb.Append(Convert.ToString(Style, 16));
|
||||
sb.Append(", 0x");
|
||||
sb.Append(Convert.ToString(ExStyle, 16));
|
||||
sb.Append(", {");
|
||||
sb.Append(X);
|
||||
sb.Append(", ");
|
||||
sb.Append(Y);
|
||||
sb.Append(", ");
|
||||
sb.Append(Width);
|
||||
sb.Append(", ");
|
||||
sb.Append(Height);
|
||||
sb.Append("}");
|
||||
sb.Append("}");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,49 +17,7 @@ namespace HandyControl.Tools
|
||||
|
||||
private const string User32 = "user32.dll";
|
||||
|
||||
private const string Shell32 = "shell32.dll";
|
||||
|
||||
public delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public class NOTIFYICONDATA
|
||||
{
|
||||
public int cbSize = Marshal.SizeOf(typeof(NOTIFYICONDATA));
|
||||
public IntPtr hWnd;
|
||||
public int uID;
|
||||
public int uFlags;
|
||||
public int uCallbackMessage;
|
||||
public IntPtr hIcon;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
|
||||
public string szTip;
|
||||
public int dwState = 0;
|
||||
public int dwStateMask = 0;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
||||
public string szInfo;
|
||||
public int uTimeoutOrVersion;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
|
||||
public string szInfoTitle;
|
||||
public int dwInfoFlags;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
public class WNDCLASS_D
|
||||
{
|
||||
public int style;
|
||||
public WndProc lpfnWndProc;
|
||||
public int cbClsExtra = 0;
|
||||
public int cbWndExtra = 0;
|
||||
public IntPtr hInstance = IntPtr.Zero;
|
||||
public IntPtr hIcon = IntPtr.Zero;
|
||||
public IntPtr hCursor = IntPtr.Zero;
|
||||
public IntPtr hbrBackground = IntPtr.Zero;
|
||||
public string lpszMenuName = null;
|
||||
public string lpszClassName = null;
|
||||
}
|
||||
|
||||
[DllImport(Shell32, CharSet = CharSet.Auto)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
public static extern int Shell_NotifyIcon(int message, NOTIFYICONDATA pnid);
|
||||
public delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
public const int E_FAIL = unchecked((int) 0x80004005);
|
||||
|
||||
@@ -114,7 +72,6 @@ namespace HandyControl.Tools
|
||||
[In]
|
||||
int len);
|
||||
|
||||
|
||||
int Write(
|
||||
[In]
|
||||
IntPtr buf,
|
||||
@@ -128,7 +85,6 @@ namespace HandyControl.Tools
|
||||
[In]
|
||||
int dwOrigin);
|
||||
|
||||
|
||||
void SetSize(
|
||||
[In, MarshalAs(UnmanagedType.I8)]
|
||||
long libNewSize);
|
||||
@@ -142,15 +98,12 @@ namespace HandyControl.Tools
|
||||
[Out, MarshalAs(UnmanagedType.LPArray)]
|
||||
long[] pcbRead);
|
||||
|
||||
|
||||
void Commit(
|
||||
[In]
|
||||
int grfCommitFlags);
|
||||
|
||||
|
||||
void Revert();
|
||||
|
||||
|
||||
void LockRegion(
|
||||
[In, MarshalAs(UnmanagedType.I8)]
|
||||
long libOffset,
|
||||
@@ -159,7 +112,6 @@ namespace HandyControl.Tools
|
||||
[In]
|
||||
int dwLockType);
|
||||
|
||||
|
||||
void UnlockRegion(
|
||||
[In, MarshalAs(UnmanagedType.I8)]
|
||||
long libOffset,
|
||||
@@ -168,7 +120,6 @@ namespace HandyControl.Tools
|
||||
[In]
|
||||
int dwLockType);
|
||||
|
||||
|
||||
void Stat(
|
||||
[In]
|
||||
IntPtr pStatstg,
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using HandyControl.Tools.Interop;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
internal static class IconHelper
|
||||
{
|
||||
private static Size _smallIconSize;
|
||||
private static Size _iconSize;
|
||||
private static int _systemBitDepth;
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
public static void GetIconHandlesFromImageSource(ImageSource image, out IconHandle largeIconHandle, out IconHandle smallIconHandle)
|
||||
{
|
||||
EnsureSystemMetrics();
|
||||
largeIconHandle = CreateIconHandleFromImageSource(image, _iconSize);
|
||||
smallIconHandle = CreateIconHandleFromImageSource(image, _smallIconSize);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static IconHandle CreateIconHandleFromImageSource(ImageSource image, Size size)
|
||||
{
|
||||
EnsureSystemMetrics();
|
||||
|
||||
var asGoodAsItGets = false;
|
||||
|
||||
var bf = image as BitmapFrame;
|
||||
if (bf?.Decoder?.Frames != null)
|
||||
{
|
||||
bf = GetBestMatch(bf.Decoder.Frames, size);
|
||||
|
||||
asGoodAsItGets = bf.Decoder is IconBitmapDecoder || bf.PixelWidth == (int)size.Width && bf.PixelHeight == (int)size.Height;
|
||||
|
||||
image = bf;
|
||||
}
|
||||
|
||||
if (!asGoodAsItGets)
|
||||
{
|
||||
bf = BitmapFrame.Create(GenerateBitmapSource(image, size));
|
||||
}
|
||||
|
||||
return CreateIconHandleFromBitmapFrame(bf);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
private static IconHandle CreateIconHandleFromBitmapFrame(BitmapFrame sourceBitmapFrame)
|
||||
{
|
||||
BitmapSource bitmapSource = sourceBitmapFrame;
|
||||
|
||||
if (bitmapSource.Format != PixelFormats.Bgra32 && bitmapSource.Format != PixelFormats.Pbgra32)
|
||||
{
|
||||
bitmapSource = new FormatConvertedBitmap(bitmapSource, PixelFormats.Bgra32, null, 0.0);
|
||||
}
|
||||
|
||||
var w = bitmapSource.PixelWidth;
|
||||
var h = bitmapSource.PixelHeight;
|
||||
var bpp = bitmapSource.Format.BitsPerPixel;
|
||||
var stride = (bpp * w + 31) / 32 * 4;
|
||||
var sizeCopyPixels = stride * h;
|
||||
var xor = new byte[sizeCopyPixels];
|
||||
bitmapSource.CopyPixels(xor, stride, 0);
|
||||
|
||||
return CreateIconCursor(xor, w, h, 0, 0, true);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
internal static IconHandle CreateIconCursor(byte[] colorArray, int width, int height, int xHotspot, int yHotspot, bool isIcon)
|
||||
{
|
||||
BitmapHandle colorBitmap = null;
|
||||
BitmapHandle maskBitmap = null;
|
||||
|
||||
try
|
||||
{
|
||||
var bi = new BITMAPINFO(width, -height, 32)
|
||||
{
|
||||
bmiHeader_biCompression = NativeMethods.BI_RGB
|
||||
};
|
||||
|
||||
var bits = IntPtr.Zero;
|
||||
colorBitmap = UnsafeNativeMethods.CreateDIBSection(new HandleRef(null, IntPtr.Zero), ref bi, NativeMethods.DIB_RGB_COLORS, ref bits, null, 0);
|
||||
|
||||
if (colorBitmap.IsInvalid || bits == IntPtr.Zero)
|
||||
{
|
||||
return IconHandle.GetInvalidIcon();
|
||||
}
|
||||
|
||||
Marshal.Copy(colorArray, 0, bits, colorArray.Length);
|
||||
var maskArray = GenerateMaskArray(width, height, colorArray);
|
||||
|
||||
maskBitmap = UnsafeNativeMethods.CreateBitmap(width, height, 1, 1, maskArray);
|
||||
if (maskBitmap.IsInvalid)
|
||||
{
|
||||
return IconHandle.GetInvalidIcon();
|
||||
}
|
||||
|
||||
var iconInfo = new ICONINFO
|
||||
{
|
||||
fIcon = isIcon,
|
||||
xHotspot = xHotspot,
|
||||
yHotspot = yHotspot,
|
||||
hbmMask = maskBitmap,
|
||||
hbmColor = colorBitmap
|
||||
};
|
||||
|
||||
return UnsafeNativeMethods.CreateIconIndirect(iconInfo);
|
||||
}
|
||||
finally
|
||||
{
|
||||
colorBitmap?.Dispose();
|
||||
maskBitmap?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] GenerateMaskArray(int width, int height, byte[] colorArray)
|
||||
{
|
||||
var nCount = width * height;
|
||||
var bytesPerScanLine = AlignToBytes(width, 2) / 8;
|
||||
var bitsMask = new byte[bytesPerScanLine * height];
|
||||
|
||||
for (var i = 0; i < nCount; i++)
|
||||
{
|
||||
var hPos = i % width;
|
||||
var vPos = i / width;
|
||||
var byteIndex = hPos / 8;
|
||||
var offsetBit = (byte)(0x80 >> (hPos % 8));
|
||||
|
||||
if (colorArray[i * 4 + 3] == 0x00)
|
||||
{
|
||||
bitsMask[byteIndex + bytesPerScanLine * vPos] |= offsetBit;
|
||||
}
|
||||
else
|
||||
{
|
||||
bitsMask[byteIndex + bytesPerScanLine * vPos] &= (byte)~offsetBit;
|
||||
}
|
||||
|
||||
if (hPos == width - 1 && width == 8)
|
||||
{
|
||||
bitsMask[1 + bytesPerScanLine * vPos] = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
return bitsMask;
|
||||
}
|
||||
|
||||
internal static int AlignToBytes(double original, int nBytesCount)
|
||||
{
|
||||
var nBitsCount = 8 << (nBytesCount - 1);
|
||||
return ((int)Math.Ceiling(original) + (nBitsCount - 1)) / nBitsCount * nBitsCount;
|
||||
}
|
||||
|
||||
private static BitmapSource GenerateBitmapSource(ImageSource img, Size renderSize)
|
||||
{
|
||||
var drawingDimensions = new Rect(0, 0, renderSize.Width, renderSize.Height);
|
||||
|
||||
var renderRatio = renderSize.Width / renderSize.Height;
|
||||
var aspectRatio = img.Width / img.Height;
|
||||
|
||||
if (img.Width <= renderSize.Width && img.Height <= renderSize.Height)
|
||||
{
|
||||
drawingDimensions = new Rect((renderSize.Width - img.Width) / 2, (renderSize.Height - img.Height) / 2, img.Width, img.Height);
|
||||
}
|
||||
else if (renderRatio > aspectRatio)
|
||||
{
|
||||
var scaledRenderWidth = (img.Width / img.Height) * renderSize.Width;
|
||||
drawingDimensions = new Rect((renderSize.Width - scaledRenderWidth) / 2, 0, scaledRenderWidth, renderSize.Height);
|
||||
}
|
||||
else if (renderRatio < aspectRatio)
|
||||
{
|
||||
var scaledRenderHeight = img.Height / img.Width * renderSize.Height;
|
||||
drawingDimensions = new Rect(0, (renderSize.Height - scaledRenderHeight) / 2, renderSize.Width, scaledRenderHeight);
|
||||
}
|
||||
|
||||
var dv = new DrawingVisual();
|
||||
var dc = dv.RenderOpen();
|
||||
dc.DrawImage(img, drawingDimensions);
|
||||
dc.Close();
|
||||
|
||||
var bmp = new RenderTargetBitmap((int)renderSize.Width, (int)renderSize.Height, 96, 96, PixelFormats.Pbgra32);
|
||||
bmp.Render(dv);
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
private static BitmapFrame GetBestMatch(ReadOnlyCollection<BitmapFrame> frames, Size size)
|
||||
{
|
||||
var bestScore = int.MaxValue;
|
||||
var bestBpp = 0;
|
||||
var bestIndex = 0;
|
||||
|
||||
var isBitmapIconDecoder = frames[0].Decoder is IconBitmapDecoder;
|
||||
|
||||
for (int i = 0; i < frames.Count && bestScore != 0; ++i)
|
||||
{
|
||||
var currentIconBitDepth = isBitmapIconDecoder ? frames[i].Thumbnail.Format.BitsPerPixel : frames[i].Format.BitsPerPixel;
|
||||
|
||||
if (currentIconBitDepth == 0)
|
||||
{
|
||||
currentIconBitDepth = 8;
|
||||
}
|
||||
|
||||
var score = MatchImage(frames[i], size, currentIconBitDepth);
|
||||
if (score < bestScore)
|
||||
{
|
||||
bestIndex = i;
|
||||
bestBpp = currentIconBitDepth;
|
||||
bestScore = score;
|
||||
}
|
||||
else if (score == bestScore)
|
||||
{
|
||||
if (bestBpp < currentIconBitDepth)
|
||||
{
|
||||
bestIndex = i;
|
||||
bestBpp = currentIconBitDepth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return frames[bestIndex];
|
||||
}
|
||||
|
||||
private static int MatchImage(BitmapFrame frame, Size size, int bpp)
|
||||
{
|
||||
var score = 2 * MyAbs(bpp, _systemBitDepth, false) +
|
||||
MyAbs(frame.PixelWidth, (int)size.Width, true) +
|
||||
MyAbs(frame.PixelHeight, (int)size.Height, true);
|
||||
|
||||
return score;
|
||||
}
|
||||
|
||||
private static int MyAbs(int valueHave, int valueWant, bool fPunish)
|
||||
{
|
||||
var diff = (valueHave - valueWant);
|
||||
|
||||
if (diff < 0)
|
||||
{
|
||||
diff = (fPunish ? -2 : -1) * diff;
|
||||
}
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
private static void EnsureSystemMetrics()
|
||||
{
|
||||
if (_systemBitDepth == 0)
|
||||
{
|
||||
var hdcDesktop = new HandleRef(null, UnsafeNativeMethods.GetDC(new HandleRef()));
|
||||
try
|
||||
{
|
||||
var sysBitDepth = UnsafeNativeMethods.GetDeviceCaps(hdcDesktop, NativeMethods.BITSPIXEL);
|
||||
sysBitDepth *= UnsafeNativeMethods.GetDeviceCaps(hdcDesktop, NativeMethods.PLANES);
|
||||
|
||||
if (sysBitDepth == 8)
|
||||
{
|
||||
sysBitDepth = 4;
|
||||
}
|
||||
|
||||
var cxSmallIcon = UnsafeNativeMethods.GetSystemMetrics(SM.CXSMICON);
|
||||
var cySmallIcon = UnsafeNativeMethods.GetSystemMetrics(SM.CYSMICON);
|
||||
var cxIcon = UnsafeNativeMethods.GetSystemMetrics(SM.CXICON);
|
||||
var cyIcon = UnsafeNativeMethods.GetSystemMetrics(SM.CYICON);
|
||||
|
||||
_smallIconSize = new Size(cxSmallIcon, cySmallIcon);
|
||||
_iconSize = new Size(cxIcon, cyIcon);
|
||||
_systemBitDepth = sysBitDepth;
|
||||
}
|
||||
finally
|
||||
{
|
||||
UnsafeNativeMethods.ReleaseDC(new HandleRef(), hdcDesktop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
public static void GetDefaultIconHandles(out IconHandle largeIconHandle, out IconHandle smallIconHandle)
|
||||
{
|
||||
largeIconHandle = null;
|
||||
smallIconHandle = null;
|
||||
|
||||
SecurityHelper.DemandUIWindowPermission();
|
||||
|
||||
var iconModuleFile = UnsafeNativeMethods.GetModuleFileName(new HandleRef());
|
||||
UnsafeNativeMethods.ExtractIconEx(iconModuleFile, 0, out largeIconHandle, out smallIconHandle, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace HandyControl.Tools
|
||||
{
|
||||
internal class SecurityHelper
|
||||
{
|
||||
private static UIPermission _allWindowsUIPermission;
|
||||
|
||||
[SecurityCritical]
|
||||
internal static void DemandUIWindowPermission()
|
||||
{
|
||||
if (_allWindowsUIPermission == null)
|
||||
{
|
||||
_allWindowsUIPermission = new UIPermission(UIPermissionWindow.AllWindows);
|
||||
}
|
||||
_allWindowsUIPermission.Demand();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, Pack = 2)]
|
||||
internal struct BITMAPINFO
|
||||
{
|
||||
public int bmiHeader_biSize;
|
||||
|
||||
public int bmiHeader_biWidth;
|
||||
|
||||
public int bmiHeader_biHeight;
|
||||
|
||||
public short bmiHeader_biPlanes;
|
||||
|
||||
public short bmiHeader_biBitCount;
|
||||
|
||||
public int bmiHeader_biCompression;
|
||||
|
||||
public int bmiHeader_biSizeImage;
|
||||
|
||||
public int bmiHeader_biXPelsPerMeter;
|
||||
|
||||
public int bmiHeader_biYPelsPerMeter;
|
||||
|
||||
public int bmiHeader_biClrUsed;
|
||||
|
||||
public int bmiHeader_biClrImportant;
|
||||
|
||||
public BITMAPINFO(int width, int height, short bpp)
|
||||
{
|
||||
bmiHeader_biSize = SizeOf();
|
||||
bmiHeader_biWidth = width;
|
||||
bmiHeader_biHeight = height;
|
||||
bmiHeader_biPlanes = 1;
|
||||
bmiHeader_biBitCount = bpp;
|
||||
bmiHeader_biCompression = 0;
|
||||
bmiHeader_biSizeImage = 0;
|
||||
bmiHeader_biXPelsPerMeter = 0;
|
||||
bmiHeader_biYPelsPerMeter = 0;
|
||||
bmiHeader_biClrUsed = 0;
|
||||
bmiHeader_biClrImportant = 0;
|
||||
}
|
||||
|
||||
[SecuritySafeCritical]
|
||||
private static int SizeOf()
|
||||
{
|
||||
return Marshal.SizeOf(typeof(BITMAPINFO));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal sealed class BitmapHandle : WpfSafeHandle
|
||||
{
|
||||
[SecurityCritical]
|
||||
private BitmapHandle(bool ownsHandle) : base(ownsHandle, CommonHandles.GDI)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return UnsafeNativeMethods.DeleteObject(handle);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
internal HandleRef MakeHandleRef(object obj)
|
||||
{
|
||||
return new HandleRef(obj, handle);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
internal static BitmapHandle CreateFromHandle(IntPtr hbitmap, bool ownsHandle = true)
|
||||
{
|
||||
return new BitmapHandle(ownsHandle)
|
||||
{
|
||||
handle = hbitmap,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal static class CommonHandles
|
||||
{
|
||||
public static readonly int Icon = HandleCollector.RegisterType(nameof(Icon), 20, 500);
|
||||
|
||||
public static readonly int HDC = HandleCollector.RegisterType(nameof(HDC), 100, 2);
|
||||
|
||||
public static readonly int GDI = HandleCollector.RegisterType(nameof(GDI), 50, 500);
|
||||
|
||||
public static readonly int Kernel = HandleCollector.RegisterType(nameof(Kernel), 0, 1000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal static class ExternDll
|
||||
{
|
||||
public const string
|
||||
User32 = "user32.dll",
|
||||
Gdi32 = "gdi32.dll",
|
||||
Kernel32 = "kernel32.dll",
|
||||
Shell32 = "shell32.dll";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
// reference from https://referencesource.microsoft.com/#WindowsBase/Shared/MS/Win32/HandleCollector.cs,d0f99220d8e1b708
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal static class HandleCollector
|
||||
{
|
||||
private static HandleType[] HandleTypes;
|
||||
private static int HandleTypeCount;
|
||||
|
||||
private static readonly object HandleMutex = new object();
|
||||
|
||||
internal static IntPtr Add(IntPtr handle, int type)
|
||||
{
|
||||
HandleTypes[type - 1].Add();
|
||||
return handle;
|
||||
}
|
||||
|
||||
[System.Security.SecuritySafeCritical]
|
||||
internal static SafeHandle Add(SafeHandle handle, int type)
|
||||
{
|
||||
HandleTypes[type - 1].Add();
|
||||
return handle;
|
||||
}
|
||||
|
||||
internal static void Add(int type)
|
||||
{
|
||||
HandleTypes[type - 1].Add();
|
||||
}
|
||||
|
||||
internal static int RegisterType(string typeName, int expense, int initialThreshold)
|
||||
{
|
||||
lock (HandleMutex)
|
||||
{
|
||||
if (HandleTypeCount == 0 || HandleTypeCount == HandleTypes.Length)
|
||||
{
|
||||
HandleType[] newTypes = new HandleType[HandleTypeCount + 10];
|
||||
if (HandleTypes != null)
|
||||
{
|
||||
Array.Copy(HandleTypes, 0, newTypes, 0, HandleTypeCount);
|
||||
}
|
||||
HandleTypes = newTypes;
|
||||
}
|
||||
|
||||
HandleTypes[HandleTypeCount++] = new HandleType(expense, initialThreshold);
|
||||
return HandleTypeCount;
|
||||
}
|
||||
}
|
||||
|
||||
internal static IntPtr Remove(IntPtr handle, int type)
|
||||
{
|
||||
HandleTypes[type - 1].Remove();
|
||||
return handle;
|
||||
}
|
||||
|
||||
[System.Security.SecuritySafeCritical]
|
||||
internal static SafeHandle Remove(SafeHandle handle, int type)
|
||||
{
|
||||
HandleTypes[type - 1].Remove();
|
||||
return handle;
|
||||
}
|
||||
|
||||
internal static void Remove(int type)
|
||||
{
|
||||
HandleTypes[type - 1].Remove();
|
||||
}
|
||||
|
||||
private class HandleType
|
||||
{
|
||||
private readonly int _initialThreshHold;
|
||||
private int _threshHold;
|
||||
private int _handleCount;
|
||||
private readonly int _deltaPercent;
|
||||
|
||||
internal HandleType(int expense, int initialThreshHold)
|
||||
{
|
||||
_initialThreshHold = initialThreshHold;
|
||||
_threshHold = initialThreshHold;
|
||||
_deltaPercent = 100 - expense;
|
||||
}
|
||||
|
||||
internal void Add()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
_handleCount++;
|
||||
var performCollect = NeedCollection();
|
||||
|
||||
if (!performCollect)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
GC.Collect();
|
||||
|
||||
var sleep = (100 - _deltaPercent) / 4;
|
||||
System.Threading.Thread.Sleep(sleep);
|
||||
}
|
||||
|
||||
private bool NeedCollection()
|
||||
{
|
||||
|
||||
if (_handleCount > _threshHold)
|
||||
{
|
||||
_threshHold = _handleCount + ((_handleCount * _deltaPercent) / 100);
|
||||
return true;
|
||||
}
|
||||
|
||||
var oldThreshHold = (100 * _threshHold) / (100 + _deltaPercent);
|
||||
if (oldThreshHold >= _initialThreshHold && _handleCount < (int)(oldThreshHold * .9F))
|
||||
{
|
||||
_threshHold = oldThreshHold;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal void Remove()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
_handleCount--;
|
||||
|
||||
_handleCount = Math.Max(0, _handleCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal class ICONINFO
|
||||
{
|
||||
public bool fIcon = false;
|
||||
public int xHotspot = 0;
|
||||
public int yHotspot = 0;
|
||||
public BitmapHandle hbmMask = null;
|
||||
public BitmapHandle hbmColor = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using System.Runtime.ConstrainedExecution;
|
||||
using System.Security;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal sealed class IconHandle : WpfSafeHandle
|
||||
{
|
||||
[SecurityCritical]
|
||||
private IconHandle() : base(true, CommonHandles.Icon)
|
||||
{
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
return UnsafeNativeMethods.DestroyIcon(handle);
|
||||
}
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
internal static IconHandle GetInvalidIcon()
|
||||
{
|
||||
return new IconHandle();
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
internal IntPtr CriticalGetHandle()
|
||||
{
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal class IntSecurity
|
||||
{
|
||||
public static CodeAccessPermission UnrestrictedWindows =>
|
||||
new Lazy<CodeAccessPermission>(() => AllWindows).Value;
|
||||
|
||||
public static CodeAccessPermission AllWindows =>
|
||||
new Lazy<CodeAccessPermission>(() => new UIPermission(UIPermissionWindow.AllWindows)).Value;
|
||||
|
||||
public static CodeAccessPermission CreateAnyWindow =>
|
||||
new Lazy<CodeAccessPermission>(() => SafeSubWindows).Value;
|
||||
|
||||
public static CodeAccessPermission SafeSubWindows =>
|
||||
new Lazy<CodeAccessPermission>(() => new UIPermission(UIPermissionWindow.SafeSubWindows)).Value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
public class NOTIFYICONDATA
|
||||
{
|
||||
public int cbSize = Marshal.SizeOf(typeof(NOTIFYICONDATA));
|
||||
public IntPtr hWnd;
|
||||
public int uID;
|
||||
public int uFlags;
|
||||
public int uCallbackMessage;
|
||||
public IntPtr hIcon;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
|
||||
public string szTip;
|
||||
public int dwState = 0;
|
||||
public int dwStateMask = 0;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
|
||||
public string szInfo;
|
||||
public int uTimeoutOrVersion;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
|
||||
public string szInfoTitle;
|
||||
public int dwInfoFlags;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
public delegate IntPtr WndProc(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "IdentifierTypo")]
|
||||
internal class NativeMethods
|
||||
{
|
||||
public const int
|
||||
WS_CHILD = 0x40000000,
|
||||
WM_USER = 0x0400,
|
||||
BITSPIXEL = 12,
|
||||
PLANES = 14,
|
||||
BI_RGB = 0,
|
||||
DIB_RGB_COLORS = 0,
|
||||
NIF_MESSAGE = 0x00000001,
|
||||
NIF_INFO = 0x00000010,
|
||||
NIF_ICON = 0x00000002,
|
||||
NIF_TIP = 0x00000004,
|
||||
NIM_ADD = 0x00000000,
|
||||
NIM_DELETE = 0x00000002,
|
||||
NIM_MODIFY = 0x00000001,
|
||||
NIIF_NONE = 0x00000000,
|
||||
NIIF_INFO = 0x00000001,
|
||||
NIIF_WARNING = 0x00000002,
|
||||
NIIF_ERROR = 0x00000003;
|
||||
|
||||
[DllImport(ExternDll.User32, CharSet = CharSet.Auto)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
public static extern int RegisterWindowMessage(string msg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal enum SM
|
||||
{
|
||||
CXSCREEN = 0,
|
||||
CYSCREEN = 1,
|
||||
CXVSCROLL = 2,
|
||||
CYHSCROLL = 3,
|
||||
CYCAPTION = 4,
|
||||
CXBORDER = 5,
|
||||
CYBORDER = 6,
|
||||
CXFIXEDFRAME = 7,
|
||||
CYFIXEDFRAME = 8,
|
||||
CYVTHUMB = 9,
|
||||
CXHTHUMB = 10,
|
||||
CXICON = 11,
|
||||
CYICON = 12,
|
||||
CXCURSOR = 13,
|
||||
CYCURSOR = 14,
|
||||
CYMENU = 15,
|
||||
CXFULLSCREEN = 16,
|
||||
CYFULLSCREEN = 17,
|
||||
CYKANJIWINDOW = 18,
|
||||
MOUSEPRESENT = 19,
|
||||
CYVSCROLL = 20,
|
||||
CXHSCROLL = 21,
|
||||
DEBUG = 22,
|
||||
SWAPBUTTON = 23,
|
||||
CXMIN = 28,
|
||||
CYMIN = 29,
|
||||
CXSIZE = 30,
|
||||
CYSIZE = 31,
|
||||
CXFRAME = 32,
|
||||
CXSIZEFRAME = CXFRAME,
|
||||
CYFRAME = 33,
|
||||
CYSIZEFRAME = CYFRAME,
|
||||
CXMINTRACK = 34,
|
||||
CYMINTRACK = 35,
|
||||
CXDOUBLECLK = 36,
|
||||
CYDOUBLECLK = 37,
|
||||
CXICONSPACING = 38,
|
||||
CYICONSPACING = 39,
|
||||
MENUDROPALIGNMENT = 40,
|
||||
PENWINDOWS = 41,
|
||||
DBCSENABLED = 42,
|
||||
CMOUSEBUTTONS = 43,
|
||||
SECURE = 44,
|
||||
CXEDGE = 45,
|
||||
CYEDGE = 46,
|
||||
CXMINSPACING = 47,
|
||||
CYMINSPACING = 48,
|
||||
CXSMICON = 49,
|
||||
CYSMICON = 50,
|
||||
CYSMCAPTION = 51,
|
||||
CXSMSIZE = 52,
|
||||
CYSMSIZE = 53,
|
||||
CXMENUSIZE = 54,
|
||||
CYMENUSIZE = 55,
|
||||
ARRANGE = 56,
|
||||
CXMINIMIZED = 57,
|
||||
CYMINIMIZED = 58,
|
||||
CXMAXTRACK = 59,
|
||||
CYMAXTRACK = 60,
|
||||
CXMAXIMIZED = 61,
|
||||
CYMAXIMIZED = 62,
|
||||
NETWORK = 63,
|
||||
CLEANBOOT = 67,
|
||||
CXDRAG = 68,
|
||||
CYDRAG = 69,
|
||||
SHOWSOUNDS = 70,
|
||||
CXMENUCHECK = 71,
|
||||
CYMENUCHECK = 72,
|
||||
SLOWMACHINE = 73,
|
||||
MIDEASTENABLED = 74,
|
||||
MOUSEWHEELPRESENT = 75,
|
||||
XVIRTUALSCREEN = 76,
|
||||
YVIRTUALSCREEN = 77,
|
||||
CXVIRTUALSCREEN = 78,
|
||||
CYVIRTUALSCREEN = 79,
|
||||
CMONITORS = 80,
|
||||
SAMEDISPLAYFORMAT = 81,
|
||||
IMMENABLED = 82,
|
||||
CXFOCUSBORDER = 83,
|
||||
CYFOCUSBORDER = 84,
|
||||
TABLETPC = 86,
|
||||
MEDIACENTER = 87,
|
||||
REMOTESESSION = 0x1000,
|
||||
REMOTECONTROL = 0x2001,
|
||||
}
|
||||
|
||||
internal static class Win32Constant
|
||||
{
|
||||
internal const int MAX_PATH = 260;
|
||||
internal const int INFOTIPSIZE = 1024;
|
||||
internal const int TRUE = 1;
|
||||
internal const int FALSE = 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Security;
|
||||
using System.Security.Permissions;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal sealed class SafeFileMappingHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
[SecurityCritical]
|
||||
internal SafeFileMappingHandle(IntPtr handle) : base(false)
|
||||
{
|
||||
SetHandle(handle);
|
||||
}
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
internal SafeFileMappingHandle() : base(true)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsInvalid
|
||||
{
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
get => handle == IntPtr.Zero;
|
||||
}
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
protected override bool ReleaseHandle()
|
||||
{
|
||||
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
|
||||
try
|
||||
{
|
||||
return CloseHandleNoThrow(new HandleRef(null, handle));
|
||||
}
|
||||
finally
|
||||
{
|
||||
CodeAccessPermission.RevertAssert();
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static bool CloseHandleNoThrow(HandleRef handle)
|
||||
{
|
||||
HandleCollector.Remove((IntPtr)handle, CommonHandles.Kernel);
|
||||
var result = UnsafeNativeMethods.IntCloseHandle(handle);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Security;
|
||||
using System.Text;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
internal class UnsafeNativeMethods
|
||||
{
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, EntryPoint = nameof(GetDC), CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr IntGetDC(HandleRef hWnd);
|
||||
|
||||
[SecurityCritical]
|
||||
public static IntPtr GetDC(HandleRef hWnd)
|
||||
{
|
||||
var hDc = IntGetDC(hWnd);
|
||||
if (hDc == IntPtr.Zero)
|
||||
{
|
||||
throw new Win32Exception();
|
||||
}
|
||||
|
||||
return HandleCollector.Add(hDc, CommonHandles.HDC);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.User32, ExactSpelling = true, EntryPoint = nameof(ReleaseDC), CharSet = CharSet.Auto)]
|
||||
public static extern int IntReleaseDC(HandleRef hWnd, HandleRef hDC);
|
||||
|
||||
[SecurityCritical]
|
||||
public static int ReleaseDC(HandleRef hWnd, HandleRef hDC)
|
||||
{
|
||||
HandleCollector.Remove((IntPtr)hDC, CommonHandles.HDC);
|
||||
return IntReleaseDC(hWnd, hDC);
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.Gdi32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto)]
|
||||
public static extern int GetDeviceCaps(HandleRef hDC, int nIndex);
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.User32)]
|
||||
public static extern int GetSystemMetrics(SM nIndex);
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.User32, EntryPoint = nameof(DestroyIcon), CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern bool IntDestroyIcon(IntPtr hIcon);
|
||||
|
||||
[SecurityCritical]
|
||||
public static bool DestroyIcon(IntPtr hIcon)
|
||||
{
|
||||
var result = IntDestroyIcon(hIcon);
|
||||
return result;
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.Gdi32, EntryPoint = nameof(DeleteObject), CharSet = CharSet.Auto, SetLastError = true)]
|
||||
private static extern bool IntDeleteObject(IntPtr hObject);
|
||||
|
||||
[SecurityCritical]
|
||||
public static bool DeleteObject(IntPtr hObject)
|
||||
{
|
||||
var result = IntDeleteObject(hObject);
|
||||
return result;
|
||||
}
|
||||
|
||||
[SecurityCritical]
|
||||
public static BitmapHandle CreateDIBSection(HandleRef hdc, ref BITMAPINFO bitmapInfo, int iUsage, ref IntPtr ppvBits, SafeFileMappingHandle hSection, int dwOffset)
|
||||
{
|
||||
if (hSection == null)
|
||||
{
|
||||
hSection = new SafeFileMappingHandle(IntPtr.Zero);
|
||||
}
|
||||
|
||||
var hBitmap = PrivateCreateDIBSection(hdc, ref bitmapInfo, iUsage, ref ppvBits, hSection, dwOffset);
|
||||
return hBitmap;
|
||||
}
|
||||
|
||||
[DllImport(ExternDll.Kernel32, EntryPoint = "CloseHandle", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
public static extern bool IntCloseHandle(HandleRef handle);
|
||||
|
||||
[SecurityCritical, SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.Gdi32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = nameof(CreateDIBSection))]
|
||||
private static extern BitmapHandle PrivateCreateDIBSection(HandleRef hdc, ref BITMAPINFO bitmapInfo, int iUsage, ref IntPtr ppvBits, SafeFileMappingHandle hSection, int dwOffset);
|
||||
|
||||
[SecurityCritical, SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.User32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = nameof(CreateIconIndirect))]
|
||||
private static extern IconHandle PrivateCreateIconIndirect([In, MarshalAs(UnmanagedType.LPStruct)]ICONINFO iconInfo);
|
||||
|
||||
[SecurityCritical]
|
||||
public static IconHandle CreateIconIndirect([In, MarshalAs(UnmanagedType.LPStruct)]ICONINFO iconInfo)
|
||||
{
|
||||
var hIcon = PrivateCreateIconIndirect(iconInfo);
|
||||
return hIcon;
|
||||
}
|
||||
|
||||
[SecurityCritical, SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.Gdi32, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Auto, EntryPoint = nameof(CreateBitmap))]
|
||||
private static extern BitmapHandle PrivateCreateBitmap(int width, int height, int planes, int bitsPerPixel, byte[] lpvBits);
|
||||
|
||||
[SecurityCritical]
|
||||
internal static BitmapHandle CreateBitmap(int width, int height, int planes, int bitsPerPixel, byte[] lpvBits)
|
||||
{
|
||||
var hBitmap = PrivateCreateBitmap(width, height, planes, bitsPerPixel, lpvBits);
|
||||
return hBitmap;
|
||||
}
|
||||
|
||||
[SecurityCritical, SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.Kernel32, EntryPoint = "GetModuleFileName", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
private static extern int IntGetModuleFileName(HandleRef hModule, StringBuilder buffer, int length);
|
||||
|
||||
[SecurityCritical]
|
||||
internal static string GetModuleFileName(HandleRef hModule)
|
||||
{
|
||||
var buffer = new StringBuilder(Win32Constant.MAX_PATH);
|
||||
while (true)
|
||||
{
|
||||
var size = IntGetModuleFileName(hModule, buffer, buffer.Capacity);
|
||||
if (size == 0)
|
||||
{
|
||||
throw new Win32Exception();
|
||||
}
|
||||
|
||||
if (size == buffer.Capacity)
|
||||
{
|
||||
buffer.EnsureCapacity(buffer.Capacity * 2);
|
||||
continue;
|
||||
}
|
||||
|
||||
return buffer.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[SecurityCritical, SuppressUnmanagedCodeSecurity]
|
||||
[DllImport(ExternDll.Shell32, CharSet = CharSet.Auto, BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||
internal static extern int ExtractIconEx(string szExeFileName, int nIconIndex, out IconHandle phiconLarge, out IconHandle phiconSmall, int nIcons);
|
||||
|
||||
[DllImport(ExternDll.Shell32, CharSet = CharSet.Auto)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
public static extern int Shell_NotifyIcon(int message, NOTIFYICONDATA pnid);
|
||||
|
||||
[SecurityCritical]
|
||||
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
[DllImport(ExternDll.User32, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "CreateWindowExW")]
|
||||
public static extern IntPtr CreateWindowEx(
|
||||
int dwExStyle,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string lpClassName,
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string lpWindowName,
|
||||
int dwStyle,
|
||||
int x,
|
||||
int y,
|
||||
int nWidth,
|
||||
int nHeight,
|
||||
IntPtr hWndParent,
|
||||
IntPtr hMenu,
|
||||
IntPtr hInstance,
|
||||
IntPtr lpParam);
|
||||
|
||||
[DllImport(ExternDll.User32, CharSet = CharSet.Auto, SetLastError = true)]
|
||||
[ResourceExposure(ResourceScope.None)]
|
||||
public static extern short RegisterClass(WNDCLASS wc);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
[SuppressMessage("ReSharper", "IdentifierTypo")]
|
||||
internal class WNDCLASS
|
||||
{
|
||||
public int style;
|
||||
public ExternDllHelper.WndProc lpfnWndProc;
|
||||
public int cbClsExtra = 0;
|
||||
public int cbWndExtra = 0;
|
||||
public IntPtr hInstance = IntPtr.Zero;
|
||||
public IntPtr hIcon = IntPtr.Zero;
|
||||
public IntPtr hCursor = IntPtr.Zero;
|
||||
public IntPtr hbrBackground = IntPtr.Zero;
|
||||
public string lpszMenuName = null;
|
||||
public string lpszClassName = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Security.Permissions;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
|
||||
internal class WindowClass
|
||||
{
|
||||
internal string WindowClassName;
|
||||
|
||||
private static readonly int WmTaskbarcreated = NativeMethods.RegisterWindowMessage("TaskbarCreated");
|
||||
|
||||
internal IntPtr MessageWindowHandle { get; private set; }
|
||||
|
||||
private readonly object _syncObj = new object();
|
||||
|
||||
private bool _added;
|
||||
|
||||
public WindowClass()
|
||||
{
|
||||
RegisterClass();
|
||||
}
|
||||
|
||||
private void RegisterClass()
|
||||
{
|
||||
WindowClassName = $"HandyControl.Controls.NotifyIcon{Guid.NewGuid()}";
|
||||
var wndclass = new WNDCLASS
|
||||
{
|
||||
style = 0,
|
||||
lpfnWndProc = Callback,
|
||||
cbClsExtra = 0,
|
||||
cbWndExtra = 0,
|
||||
hInstance = IntPtr.Zero,
|
||||
hIcon = IntPtr.Zero,
|
||||
hCursor = IntPtr.Zero,
|
||||
hbrBackground = IntPtr.Zero,
|
||||
lpszMenuName = string.Empty,
|
||||
lpszClassName = WindowClassName
|
||||
};
|
||||
|
||||
UnsafeNativeMethods.RegisterClass(wndclass);
|
||||
MessageWindowHandle = UnsafeNativeMethods.CreateWindowEx(0, WindowClassName, "", 0, 0, 0, 1, 1, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
|
||||
}
|
||||
|
||||
public IntPtr Callback(IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam)
|
||||
{
|
||||
if (msg == WmTaskbarcreated)
|
||||
{
|
||||
_added = false;
|
||||
AddIcon();
|
||||
}
|
||||
return IntPtr.Zero;
|
||||
}
|
||||
|
||||
private void AddIcon()
|
||||
{
|
||||
lock (_syncObj)
|
||||
{
|
||||
if (DesignerHelper.IsInDesignMode) return;
|
||||
|
||||
//NativeMethods.NOTIFYICONDATA data = new NativeMethods.NOTIFYICONDATA();
|
||||
//data.uCallbackMessage = WM_TRAYMOUSEMESSAGE;
|
||||
//data.uFlags = NativeMethods.NIF_MESSAGE;
|
||||
//if (showIconInTray)
|
||||
//{
|
||||
// if (window.Handle == IntPtr.Zero)
|
||||
// {
|
||||
// window.CreateHandle(new CreateParams());
|
||||
// }
|
||||
//}
|
||||
//data.hWnd = window.Handle;
|
||||
//data.uID = id;
|
||||
//data.hIcon = IntPtr.Zero;
|
||||
//data.szTip = null;
|
||||
//if (icon != null)
|
||||
//{
|
||||
// data.uFlags |= NativeMethods.NIF_ICON;
|
||||
// data.hIcon = icon.Handle;
|
||||
//}
|
||||
//data.uFlags |= NativeMethods.NIF_TIP;
|
||||
//data.szTip = text;
|
||||
|
||||
//if (showIconInTray && icon != null)
|
||||
//{
|
||||
// if (!added)
|
||||
// {
|
||||
// UnsafeNativeMethods.Shell_NotifyIcon(NativeMethods.NIM_ADD, data);
|
||||
// added = true;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// UnsafeNativeMethods.Shell_NotifyIcon(NativeMethods.NIM_MODIFY, data);
|
||||
// }
|
||||
//}
|
||||
//else if (added)
|
||||
//{
|
||||
// UnsafeNativeMethods.Shell_NotifyIcon(NativeMethods.NIM_DELETE, data);
|
||||
// added = false;
|
||||
//}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Security;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
namespace HandyControl.Tools.Interop
|
||||
{
|
||||
internal abstract class WpfSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
|
||||
{
|
||||
private readonly int _collectorId;
|
||||
|
||||
[SecurityCritical]
|
||||
protected WpfSafeHandle(bool ownsHandle, int collectorId) : base(ownsHandle)
|
||||
{
|
||||
HandleCollector.Add(collectorId);
|
||||
_collectorId = collectorId;
|
||||
}
|
||||
|
||||
[SecurityCritical, SecuritySafeCritical]
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
HandleCollector.Remove(_collectorId);
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -500,7 +500,7 @@
|
||||
</data>
|
||||
<data name="NotifyIcon" xml:space="preserve">
|
||||
<value>NotifyIcon</value>
|
||||
<data>
|
||||
</data>
|
||||
<data name="Badge" xml:space="preserve">
|
||||
<value>Badge</value>
|
||||
</data>
|
||||
|
||||
@@ -500,7 +500,7 @@
|
||||
</data>
|
||||
<data name="NotifyIcon" xml:space="preserve">
|
||||
<value>托盘图标</value>
|
||||
<data>
|
||||
</data>
|
||||
<data name="Badge" xml:space="preserve">
|
||||
<value>标记</value>
|
||||
</data>
|
||||
|
||||
Reference in new issue
Block a user