fixed a bug of Screenshot on win7

This commit is contained in:
NaBian committed 2020-04-18 23:22:39 +08:00
1 parent dc64d5cacb
commit f4087574c0
11 files changed
+850 -450

No files matched your search

@@ -13,6 +13,7 @@ using System.Windows.Media.Imaging;
using System.Windows.Resources;
using HandyControl.Data;
using HandyControl.Tools;
using HandyControl.Tools.Interop;
namespace HandyControl.Controls
{
@@ -123,7 +124,7 @@ namespace HandyControl.Controls
try
{
StopAnimate();
ExternDllHelper.Gdip.GdipDisposeImage(new HandleRef(this, NativeImage));
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(this, NativeImage));
}
catch
{
@@ -139,17 +140,17 @@ namespace HandyControl.Controls
{
filename = Path.GetFullPath(filename);
var status = ExternDllHelper.Gdip.GdipCreateBitmapFromFile(filename, out var bitmap);
var status = InteropMethods.Gdip.GdipCreateBitmapFromFile(filename, out var bitmap);
if (status != ExternDllHelper.Gdip.Ok)
throw ExternDllHelper.Gdip.StatusException(status);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
status = ExternDllHelper.Gdip.GdipImageForceValidation(new HandleRef(null, bitmap));
status = InteropMethods.Gdip.GdipImageForceValidation(new HandleRef(null, bitmap));
if (status != ExternDllHelper.Gdip.Ok)
if (status != InteropMethods.Gdip.Ok)
{
ExternDllHelper.Gdip.GdipDisposeImage(new HandleRef(null, bitmap));
throw ExternDllHelper.Gdip.StatusException(status);
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(null, bitmap));
throw InteropMethods.Gdip.StatusException(status);
}
SetNativeImage(bitmap);
@@ -162,17 +163,17 @@ namespace HandyControl.Controls
if (stream == null)
throw new ArgumentException("stream null");
var status = ExternDllHelper.Gdip.GdipCreateBitmapFromStream(new GPStream(stream), out var bitmap);
var status = InteropMethods.Gdip.GdipCreateBitmapFromStream(new GPStream(stream), out var bitmap);
if (status != ExternDllHelper.Gdip.Ok)
throw ExternDllHelper.Gdip.StatusException(status);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
status = ExternDllHelper.Gdip.GdipImageForceValidation(new HandleRef(null, bitmap));
status = InteropMethods.Gdip.GdipImageForceValidation(new HandleRef(null, bitmap));
if (status != ExternDllHelper.Gdip.Ok)
if (status != InteropMethods.Gdip.Ok)
{
ExternDllHelper.Gdip.GdipDisposeImage(new HandleRef(null, bitmap));
throw ExternDllHelper.Gdip.StatusException(status);
InteropMethods.Gdip.GdipDisposeImage(new HandleRef(null, bitmap));
throw InteropMethods.Gdip.StatusException(status);
}
SetNativeImage(bitmap);
@@ -296,10 +297,10 @@ namespace HandyControl.Controls
{
var guid = new Guid();
var status = ExternDllHelper.Gdip.GdipGetImageRawFormat(new HandleRef(this, NativeImage), ref guid);
var status = InteropMethods.Gdip.GdipGetImageRawFormat(new HandleRef(this, NativeImage), ref guid);
if (status != ExternDllHelper.Gdip.Ok)
throw ExternDllHelper.Gdip.StatusException(status);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
return guid;
}
@@ -321,11 +322,11 @@ namespace HandyControl.Controls
{
get
{
var status = ExternDllHelper.Gdip.GdipImageGetFrameDimensionsCount(new HandleRef(this, NativeImage), out var count);
var status = InteropMethods.Gdip.GdipImageGetFrameDimensionsCount(new HandleRef(this, NativeImage), out var count);
if (status != ExternDllHelper.Gdip.Ok)
if (status != InteropMethods.Gdip.Ok)
{
throw ExternDllHelper.Gdip.StatusException(status);
throw InteropMethods.Gdip.StatusException(status);
}
if (count <= 0)
@@ -338,15 +339,15 @@ namespace HandyControl.Controls
var buffer = Marshal.AllocHGlobal(checked(size * count));
if (buffer == IntPtr.Zero)
{
throw ExternDllHelper.Gdip.StatusException(ExternDllHelper.Gdip.OutOfMemory);
throw InteropMethods.Gdip.StatusException(InteropMethods.Gdip.OutOfMemory);
}
status = ExternDllHelper.Gdip.GdipImageGetFrameDimensionsList(new HandleRef(this, NativeImage), buffer, count);
status = InteropMethods.Gdip.GdipImageGetFrameDimensionsList(new HandleRef(this, NativeImage), buffer, count);
if (status != ExternDllHelper.Gdip.Ok)
if (status != InteropMethods.Gdip.Ok)
{
Marshal.FreeHGlobal(buffer);
throw ExternDllHelper.Gdip.StatusException(status);
throw InteropMethods.Gdip.StatusException(status);
}
var guids = new Guid[count];
@@ -355,7 +356,7 @@ namespace HandyControl.Controls
{
for (var i = 0; i < count; i++)
{
guids[i] = (Guid)ExternDllHelper.PtrToStructure((IntPtr)((long)buffer + size * i), typeof(Guid));
guids[i] = (Guid)InteropMethods.PtrToStructure((IntPtr)((long)buffer + size * i), typeof(Guid));
}
}
finally
@@ -372,10 +373,10 @@ namespace HandyControl.Controls
var count = new[] { 0 };
var dimensionId = dimension.Guid;
var status = ExternDllHelper.Gdip.GdipImageGetFrameCount(new HandleRef(this, NativeImage), ref dimensionId, count);
var status = InteropMethods.Gdip.GdipImageGetFrameCount(new HandleRef(this, NativeImage), ref dimensionId, count);
if (status != ExternDllHelper.Gdip.Ok)
throw ExternDllHelper.Gdip.StatusException(status);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
return count[0];
}
@@ -384,10 +385,10 @@ namespace HandyControl.Controls
{
GifPropertyItem propitem;
var status = ExternDllHelper.Gdip.GdipGetPropertyItemSize(new HandleRef(this, NativeImage), propid, out var size);
var status = InteropMethods.Gdip.GdipGetPropertyItemSize(new HandleRef(this, NativeImage), propid, out var size);
if (status != ExternDllHelper.Gdip.Ok)
throw ExternDllHelper.Gdip.StatusException(status);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
if (size == 0)
return null;
@@ -395,15 +396,15 @@ namespace HandyControl.Controls
var propdata = Marshal.AllocHGlobal(size);
if (propdata == IntPtr.Zero)
throw ExternDllHelper.Gdip.StatusException(ExternDllHelper.Gdip.OutOfMemory);
throw InteropMethods.Gdip.StatusException(InteropMethods.Gdip.OutOfMemory);
status = ExternDllHelper.Gdip.GdipGetPropertyItem(new HandleRef(this, NativeImage), propid, size, propdata);
status = InteropMethods.Gdip.GdipGetPropertyItem(new HandleRef(this, NativeImage), propid, size, propdata);
try
{
if (status != ExternDllHelper.Gdip.Ok)
if (status != InteropMethods.Gdip.Ok)
{
throw ExternDllHelper.Gdip.StatusException(status);
throw InteropMethods.Gdip.StatusException(status);
}
propitem = GifPropertyItemInternal.ConvertFromMemory(propdata, 1)[0];
@@ -421,10 +422,10 @@ namespace HandyControl.Controls
var count = new[] { 0 };
var dimensionId = dimension.Guid;
var status = ExternDllHelper.Gdip.GdipImageSelectActiveFrame(new HandleRef(this, NativeImage), ref dimensionId, frameIndex);
var status = InteropMethods.Gdip.GdipImageSelectActiveFrame(new HandleRef(this, NativeImage), ref dimensionId, frameIndex);
if (status != ExternDllHelper.Gdip.Ok)
throw ExternDllHelper.Gdip.StatusException(status);
if (status != InteropMethods.Gdip.Ok)
throw InteropMethods.Gdip.StatusException(status);
return count[0];
}
@@ -441,16 +442,16 @@ namespace HandyControl.Controls
[ResourceConsumption(ResourceScope.Machine)]
internal IntPtr GetHbitmap(Color background)
{
var status = ExternDllHelper.Gdip.GdipCreateHBITMAPFromBitmap(new HandleRef(this, NativeImage), out var hBitmap,
var status = InteropMethods.Gdip.GdipCreateHBITMAPFromBitmap(new HandleRef(this, NativeImage), out var hBitmap,
ColorHelper.ToWin32(background));
if (status == 2 && (Width >= short.MaxValue || Height >= short.MaxValue))
{
throw new ArgumentException("GdiplusInvalidSize");
}
if (status != ExternDllHelper.Gdip.Ok && NativeImage != IntPtr.Zero)
if (status != InteropMethods.Gdip.Ok && NativeImage != IntPtr.Zero)
{
throw ExternDllHelper.Gdip.StatusException(status);
throw InteropMethods.Gdip.StatusException(status);
}
return hBitmap;
@@ -474,7 +475,7 @@ namespace HandyControl.Controls
{
if (handle != IntPtr.Zero)
{
ExternDllHelper.DeleteObject(handle);
InteropMethods.DeleteObject(handle);
}
}
}
@@ -1,8 +1,10 @@
using System;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using HandyControl.Data;
@@ -31,6 +33,8 @@ namespace HandyControl.Controls
private BitmapSource _imageSource;
private static readonly Guid BmpGuid = new Guid("{b96b3cab-0728-11d3-9d7b-0000f81ef32e}");
#region const
private const int IntervalLength = 1;
@@ -554,13 +558,63 @@ namespace HandyControl.Controls
var desktopWindowWidth = _desktopWindowRect.Right - _desktopWindowRect.Left;
var desktopWindowHeight = _desktopWindowRect.Bottom - _desktopWindowRect.Top;
var bitmap = InteropMethods.CreateCompatibleBitmap(hdcSrc, desktopWindowWidth, desktopWindowHeight);
var hOld = InteropMethods.SelectObject(hdcDest, bitmap);
var hbitmap = InteropMethods.CreateCompatibleBitmap(hdcSrc, desktopWindowWidth, desktopWindowHeight);
var hOld = InteropMethods.SelectObject(hdcDest, hbitmap);
InteropMethods.BitBlt(hdcDest, 0, 0, desktopWindowWidth, desktopWindowHeight, hdcSrc, 0, 0, InteropValues.SRCCOPY);
InteropMethods.SelectObject(hdcDest, hOld);
InteropMethods.DeleteDC(hdcDest);
InteropMethods.ReleaseDC(_desktopWindowHandle, hdcSrc);
return Imaging.CreateBitmapSourceFromHBitmap(bitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
var status = InteropMethods.Gdip.GdipCreateBitmapFromHBITMAP(new HandleRef(null, hbitmap), new HandleRef(null, IntPtr.Zero), out var bitmap);
if (status != InteropMethods.Gdip.Ok) throw InteropMethods.Gdip.StatusException(status);
using var ms = new MemoryStream();
status = InteropMethods.Gdip.GdipGetImageEncodersSize(out var numEncoders, out var size);
if (status != InteropMethods.Gdip.Ok) throw InteropMethods.Gdip.StatusException(status);
var memory = Marshal.AllocHGlobal(size);
try
{
status = InteropMethods.Gdip.GdipGetImageEncoders(numEncoders, size, memory);
if (status != InteropMethods.Gdip.Ok) throw InteropMethods.Gdip.StatusException(status);
var codecInfo = ImageCodecInfo.ConvertFromMemory(memory, numEncoders).FirstOrDefault(item => item.FormatID.Equals(BmpGuid));
if (codecInfo == null) throw new Exception("ImageCodecInfo is null");
var encoderParamsMemory = IntPtr.Zero;
try
{
var g = codecInfo.Clsid;
status = InteropMethods.Gdip.GdipSaveImageToStream(new HandleRef(this, bitmap),
new InteropValues.ComStreamFromDataStream(ms), ref g,
new HandleRef(null, encoderParamsMemory));
}
finally
{
if (encoderParamsMemory != IntPtr.Zero)
{
Marshal.FreeHGlobal(encoderParamsMemory);
}
}
if (status != InteropMethods.Gdip.Ok)
{
throw InteropMethods.Gdip.StatusException(status);
}
}
finally
{
Marshal.FreeHGlobal(memory);
}
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = ms;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
private void MoveElement(InteropValues.POINT point)
@@ -3,6 +3,7 @@ using System.Windows;
using System.Windows.Media;
using HandyControl.Data;
using HandyControl.Tools;
using HandyControl.Tools.Interop;
namespace HandyControl.Controls
{
@@ -33,12 +34,12 @@ namespace HandyControl.Controls
return;
}
var accentPolicy = new ExternDllHelper.ACCENTPOLICY();
var accentPolicy = new InteropValues.ACCENTPOLICY();
var accentPolicySize = Marshal.SizeOf(accentPolicy);
accentPolicy.AccentState = SystemVersionInfo < SystemVersionInfo.Windows10_1809
? ExternDllHelper.ACCENTSTATE.ACCENT_ENABLE_BLURBEHIND
: ExternDllHelper.ACCENTSTATE.ACCENT_ENABLE_ACRYLICBLURBEHIND;
? InteropValues.ACCENTSTATE.ACCENT_ENABLE_BLURBEHIND
: InteropValues.ACCENTSTATE.ACCENT_ENABLE_ACRYLICBLURBEHIND;
accentPolicy.AccentFlags = 2;
accentPolicy.GradientColor = ResourceHelper.GetResource<uint>(ResourceToken.BlurGradientValue);
@@ -46,14 +47,14 @@ namespace HandyControl.Controls
var accentPtr = Marshal.AllocHGlobal(accentPolicySize);
Marshal.StructureToPtr(accentPolicy, accentPtr, false);
var data = new ExternDllHelper.WINCOMPATTRDATA
var data = new InteropValues.WINCOMPATTRDATA
{
Attribute = ExternDllHelper.WINDOWCOMPOSITIONATTRIB.WCA_ACCENT_POLICY,
Attribute = InteropValues.WINDOWCOMPOSITIONATTRIB.WCA_ACCENT_POLICY,
DataSize = accentPolicySize,
Data = accentPtr
};
ExternDllHelper.SetWindowCompositionAttribute(window.GetHandle(), ref data);
InteropMethods.Gdip.SetWindowCompositionAttribute(window.GetHandle(), ref data);
Marshal.FreeHGlobal(accentPtr);
}
@@ -0,0 +1,18 @@
using System;
namespace HandyControl.Data
{
[Flags]
internal enum ImageCodecFlags
{
Encoder = 0x00000001,
Decoder = 0x00000002,
SupportBitmap = 0x00000004,
SupportVector = 0x00000008,
SeekableEncode = 0x00000010,
BlockingDecode = 0x00000020,
Builtin = 0x00010000,
System = 0x00020000,
User = 0x00040000
}
}
@@ -3,12 +3,12 @@ using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using HandyControl.Tools;
using HandyControl.Tools.Interop;
namespace HandyControl.Data
{
// ReSharper disable once InconsistentNaming
internal class GPStream : ExternDllHelper.IStream
internal class GPStream : InteropValues.IStream
{
protected Stream DataStream;
@@ -55,7 +55,7 @@ namespace HandyControl.Data
_virtualPosition = -1;
}
public virtual ExternDllHelper.IStream Clone()
public virtual InteropValues.IStream Clone()
{
NotImplemented();
return null;
@@ -72,7 +72,7 @@ namespace HandyControl.Data
UIPermission(SecurityAction.Demand, Window = UIPermissionWindow.AllWindows),
SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)
]
public virtual long CopyTo(ExternDllHelper.IStream pstm, long cb, long[] pcbRead)
public virtual long CopyTo(InteropValues.IStream pstm, long cb, long[] pcbRead)
{
const int bufsize = 4096;
@@ -117,7 +117,7 @@ namespace HandyControl.Data
protected static ExternalException EFail(string msg)
{
throw new ExternalException(msg, ExternDllHelper.E_FAIL);
throw new ExternalException(msg, InteropMethods.E_FAIL);
}
protected static void NotImplemented()
@@ -154,7 +154,7 @@ namespace HandyControl.Data
var len = DataStream.Length;
switch (origin)
{
case ExternDllHelper.StreamConsts.STREAM_SEEK_SET:
case InteropValues.StreamConsts.STREAM_SEEK_SET:
if (offset <= len)
{
DataStream.Position = offset;
@@ -165,7 +165,7 @@ namespace HandyControl.Data
_virtualPosition = offset;
}
break;
case ExternDllHelper.StreamConsts.STREAM_SEEK_END:
case InteropValues.StreamConsts.STREAM_SEEK_END:
if (offset <= 0)
{
DataStream.Position = len + offset;
@@ -176,7 +176,7 @@ namespace HandyControl.Data
_virtualPosition = len + offset;
}
break;
case ExternDllHelper.StreamConsts.STREAM_SEEK_CUR:
case InteropValues.StreamConsts.STREAM_SEEK_CUR:
if (offset + pos <= len)
{
DataStream.Position = pos + offset;
@@ -1,6 +1,6 @@
using System;
using System.Runtime.InteropServices;
using HandyControl.Tools;
using HandyControl.Tools.Interop;
namespace HandyControl.Data
{
@@ -85,7 +85,7 @@ namespace HandyControl.Data
GifPropertyItemInternal propcopy = null;
try
{
propcopy = (GifPropertyItemInternal) ExternDllHelper.PtrToStructure(propdata,
propcopy = (GifPropertyItemInternal) InteropMethods.PtrToStructure(propdata,
typeof(GifPropertyItemInternal));
props[i] = new GifPropertyItem
@@ -0,0 +1,158 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using HandyControl.Tools.Interop;
namespace HandyControl.Data
{
internal sealed class ImageCodecInfo
{
private string _dllName;
public Guid Clsid { get; set; }
public Guid FormatID { get; set; }
public string CodecName { get; set; }
public string DllName
{
[SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
get
{
if (_dllName != null)
{
new System.Security.Permissions.FileIOPermission(System.Security.Permissions.FileIOPermissionAccess.PathDiscovery, _dllName).Demand();
}
return _dllName;
}
[SuppressMessage("Microsoft.Security", "CA2103:ReviewImperativeSecurity")]
set
{
if (value != null)
{
new System.Security.Permissions.FileIOPermission(System.Security.Permissions.FileIOPermissionAccess.PathDiscovery, value).Demand();
}
_dllName = value;
}
}
public string FormatDescription { get; set; }
public string FilenameExtension { get; set; }
public string MimeType { get; set; }
public ImageCodecFlags Flags { get; set; }
public int Version { get; set; }
public byte[][] SignaturePatterns { get; set; }
public byte[][] SignatureMasks { get; set; }
public static ImageCodecInfo[] GetImageDecoders()
{
ImageCodecInfo[] imageCodecs;
var status = InteropMethods.Gdip.GdipGetImageDecodersSize(out var numDecoders, out var size);
if (status != InteropMethods.Gdip.Ok)
{
throw InteropMethods.Gdip.StatusException(status);
}
var memory = Marshal.AllocHGlobal(size);
try
{
status = InteropMethods.Gdip.GdipGetImageDecoders(numDecoders, size, memory);
if (status != InteropMethods.Gdip.Ok)
{
throw InteropMethods.Gdip.StatusException(status);
}
imageCodecs = ConvertFromMemory(memory, numDecoders);
}
finally
{
Marshal.FreeHGlobal(memory);
}
return imageCodecs;
}
public static ImageCodecInfo[] GetImageEncoders()
{
ImageCodecInfo[] imageCodecs;
var status = InteropMethods.Gdip.GdipGetImageEncodersSize(out var numEncoders, out var size);
if (status != InteropMethods.Gdip.Ok)
{
throw InteropMethods.Gdip.StatusException(status);
}
var memory = Marshal.AllocHGlobal(size);
try
{
status = InteropMethods.Gdip.GdipGetImageEncoders(numEncoders, size, memory);
if (status != InteropMethods.Gdip.Ok)
{
throw InteropMethods.Gdip.StatusException(status);
}
imageCodecs = ConvertFromMemory(memory, numEncoders);
}
finally
{
Marshal.FreeHGlobal(memory);
}
return imageCodecs;
}
public static ImageCodecInfo[] ConvertFromMemory(IntPtr memoryStart, int numCodecs)
{
var codecs = new ImageCodecInfo[numCodecs];
int index;
for (index = 0; index < numCodecs; index++)
{
var curcodec = (IntPtr)((long)memoryStart + Marshal.SizeOf(typeof(InteropValues.ImageCodecInfoPrivate)) * index);
var codecp = new InteropValues.ImageCodecInfoPrivate();
InteropMethods.PtrToStructure(curcodec, codecp);
codecs[index] = new ImageCodecInfo
{
Clsid = codecp.Clsid,
FormatID = codecp.FormatID,
CodecName = Marshal.PtrToStringUni(codecp.CodecName),
DllName = Marshal.PtrToStringUni(codecp.DllName),
FormatDescription = Marshal.PtrToStringUni(codecp.FormatDescription),
FilenameExtension = Marshal.PtrToStringUni(codecp.FilenameExtension),
MimeType = Marshal.PtrToStringUni(codecp.MimeType),
Flags = (ImageCodecFlags) codecp.Flags,
Version = codecp.Version,
SignaturePatterns = new byte[codecp.SigCount][],
SignatureMasks = new byte[codecp.SigCount][]
};
for (var j = 0; j < codecp.SigCount; j++)
{
codecs[index].SignaturePatterns[j] = new byte[codecp.SigSize];
codecs[index].SignatureMasks[j] = new byte[codecp.SigSize];
Marshal.Copy((IntPtr)((long)codecp.SigMask + j * codecp.SigSize), codecs[index].SignatureMasks[j], 0, codecp.SigSize);
Marshal.Copy((IntPtr)((long)codecp.SigPattern + j * codecp.SigSize), codecs[index].SignaturePatterns[j], 0, codecp.SigSize);
}
}
return codecs;
}
}
}
@@ -51,6 +51,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Data\Enum\DrawerShowMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Data\Enum\HatchStyle.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Data\Enum\HitMode.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Data\Enum\ImageCodecFlags.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Data\Enum\ShowAnimation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Data\Enum\NotifyIconInfoType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Data\Enum\StrokePosition.cs" />
@@ -61,6 +62,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Data\GlowWindow\GlowDrawingContext.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Data\GlowWindow\GlowEdge.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Data\HwndWrapper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Data\ImageCodecInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interactivity\Commands\CloseWindowCommand.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interactivity\Commands\OpenLinkCommand.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Interactivity\Commands\StartScreenshotCommand.cs" />
@@ -317,7 +319,6 @@
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\ConfigHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\DesignerHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\DpiHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\ExternDllHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\IconHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\ResourceHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Tools\Helper\ScreenHelper.cs" />
@@ -1,362 +0,0 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using System.Threading;
namespace HandyControl.Tools
{
[SuppressMessage("ReSharper", "InconsistentNaming")]
internal class ExternDllHelper
{
private const string Gdi32 = "gdi32.dll";
private const string User32 = "user32.dll";
public const int E_FAIL = unchecked((int) 0x80004005);
[StructLayout(LayoutKind.Sequential)]
internal struct WINCOMPATTRDATA
{
public WINDOWCOMPOSITIONATTRIB Attribute;
public IntPtr Data;
public int DataSize;
}
internal enum WINDOWCOMPOSITIONATTRIB
{
WCA_ACCENT_POLICY = 19
}
internal enum ACCENTSTATE
{
ACCENT_DISABLED = 0,
ACCENT_ENABLE_GRADIENT = 1,
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
ACCENT_ENABLE_BLURBEHIND = 3,
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4,
ACCENT_INVALID_STATE = 5
}
[StructLayout(LayoutKind.Sequential)]
internal struct ACCENTPOLICY
{
public ACCENTSTATE AccentState;
public int AccentFlags;
public uint GradientColor;
public int AnimationId;
}
[DllImport(User32)]
internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WINCOMPATTRDATA data);
[ReflectionPermission(SecurityAction.Assert, Unrestricted = true), SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static object PtrToStructure(IntPtr lparam, Type cls) => Marshal.PtrToStructure(lparam, cls);
[DllImport(Gdi32, CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteObject(IntPtr hObject);
[ComImport, Guid("0000000C-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IStream
{
int Read(
[In]
IntPtr buf,
[In]
int len);
int Write(
[In]
IntPtr buf,
[In]
int len);
[return: MarshalAs(UnmanagedType.I8)]
long Seek(
[In, MarshalAs(UnmanagedType.I8)]
long dlibMove,
[In]
int dwOrigin);
void SetSize(
[In, MarshalAs(UnmanagedType.I8)]
long libNewSize);
[return: MarshalAs(UnmanagedType.I8)]
long CopyTo(
[In, MarshalAs(UnmanagedType.Interface)]
IStream pstm,
[In, MarshalAs(UnmanagedType.I8)]
long cb,
[Out, MarshalAs(UnmanagedType.LPArray)]
long[] pcbRead);
void Commit(
[In]
int grfCommitFlags);
void Revert();
void LockRegion(
[In, MarshalAs(UnmanagedType.I8)]
long libOffset,
[In, MarshalAs(UnmanagedType.I8)]
long cb,
[In]
int dwLockType);
void UnlockRegion(
[In, MarshalAs(UnmanagedType.I8)]
long libOffset,
[In, MarshalAs(UnmanagedType.I8)]
long cb,
[In]
int dwLockType);
void Stat(
[In]
IntPtr pStatstg,
[In]
int grfStatFlag);
[return: MarshalAs(UnmanagedType.Interface)]
IStream Clone();
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
public class StreamConsts
{
public const int LOCK_WRITE = 0x1;
public const int LOCK_EXCLUSIVE = 0x2;
public const int LOCK_ONLYONCE = 0x4;
public const int STATFLAG_DEFAULT = 0x0;
public const int STATFLAG_NONAME = 0x1;
public const int STATFLAG_NOOPEN = 0x2;
public const int STGC_DEFAULT = 0x0;
public const int STGC_OVERWRITE = 0x1;
public const int STGC_ONLYIFCURRENT = 0x2;
public const int STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 0x4;
public const int STREAM_SEEK_SET = 0x0;
public const int STREAM_SEEK_CUR = 0x1;
public const int STREAM_SEEK_END = 0x2;
}
internal class Gdip
{
private const string Gdiplus = "gdiplus.dll";
private const string ThreadDataSlotName = "system.drawing.threaddata";
private static IntPtr InitToken;
private static bool Initialized => InitToken != IntPtr.Zero;
static Gdip()
{
Initialize();
}
[StructLayout(LayoutKind.Sequential)]
private struct StartupInput
{
private int GdiplusVersion;
private readonly IntPtr DebugEventCallback;
private bool SuppressBackgroundThread;
private bool SuppressExternalCodecs;
public static StartupInput GetDefault()
{
var result = new StartupInput
{
GdiplusVersion = 1,
SuppressBackgroundThread = false,
SuppressExternalCodecs = false
};
return result;
}
}
[StructLayout(LayoutKind.Sequential)]
private struct StartupOutput
{
private readonly IntPtr hook;
private readonly IntPtr unhook;
}
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
[SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals")]
private static void Initialize()
{
var input = StartupInput.GetDefault();
var status = GdiplusStartup(out InitToken, ref input, out _);
if (status != Ok)
{
throw StatusException(status);
}
var currentDomain = AppDomain.CurrentDomain;
currentDomain.ProcessExit += OnProcessExit;
if (!currentDomain.IsDefaultAppDomain())
{
currentDomain.DomainUnload += OnProcessExit;
}
}
[PrePrepareMethod]
[ResourceExposure(ResourceScope.AppDomain)]
[ResourceConsumption(ResourceScope.AppDomain)]
private static void OnProcessExit(object sender, EventArgs e) => Shutdown();
[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")]
[ResourceExposure(ResourceScope.AppDomain)]
[ResourceConsumption(ResourceScope.AppDomain)]
private static void Shutdown()
{
if (Initialized)
{
ClearThreadData();
// unhook our shutdown handlers as we do not need to shut down more than once
var currentDomain = AppDomain.CurrentDomain;
currentDomain.ProcessExit -= OnProcessExit;
if (!currentDomain.IsDefaultAppDomain())
{
currentDomain.DomainUnload -= OnProcessExit;
}
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ClearThreadData()
{
var slot = Thread.GetNamedDataSlot(ThreadDataSlotName);
Thread.SetData(slot, null);
}
//----------------------------------------------------------------------------------------
// Status codes
//----------------------------------------------------------------------------------------
internal const int Ok = 0;
internal const int GenericError = 1;
internal const int InvalidParameter = 2;
internal const int OutOfMemory = 3;
internal const int ObjectBusy = 4;
internal const int InsufficientBuffer = 5;
internal const int NotImplemented = 6;
internal const int Win32Error = 7;
internal const int WrongState = 8;
internal const int Aborted = 9;
internal const int FileNotFound = 10;
internal const int ValueOverflow = 11;
internal const int AccessDenied = 12;
internal const int UnknownImageFormat = 13;
internal const int FontFamilyNotFound = 14;
internal const int FontStyleNotFound = 15;
internal const int NotTrueTypeFont = 16;
internal const int UnsupportedGdiplusVersion = 17;
internal const int GdiplusNotInitialized = 18;
internal const int PropertyNotFound = 19;
internal const int PropertyNotSupported = 20;
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipImageGetFrameDimensionsCount(HandleRef image, out int count);
internal static Exception StatusException(int status)
{
switch (status)
{
case GenericError: return new ExternalException("GdiplusGenericError");
case InvalidParameter: return new ArgumentException("GdiplusInvalidParameter");
case OutOfMemory: return new OutOfMemoryException("GdiplusOutOfMemory");
case ObjectBusy: return new InvalidOperationException("GdiplusObjectBusy");
case InsufficientBuffer: return new OutOfMemoryException("GdiplusInsufficientBuffer");
case NotImplemented: return new NotImplementedException("GdiplusNotImplemented");
case Win32Error: return new ExternalException("GdiplusGenericError");
case WrongState: return new InvalidOperationException("GdiplusWrongState");
case Aborted: return new ExternalException("GdiplusAborted");
case FileNotFound: return new FileNotFoundException("GdiplusFileNotFound");
case ValueOverflow: return new OverflowException("GdiplusOverflow");
case AccessDenied: return new ExternalException("GdiplusAccessDenied");
case UnknownImageFormat: return new ArgumentException("GdiplusUnknownImageFormat");
case PropertyNotFound: return new ArgumentException("GdiplusPropertyNotFoundError");
case PropertyNotSupported: return new ArgumentException("GdiplusPropertyNotSupportedError");
case FontFamilyNotFound: return new ArgumentException("GdiplusFontFamilyNotFound");
case FontStyleNotFound: return new ArgumentException("GdiplusFontStyleNotFound");
case NotTrueTypeFont: return new ArgumentException("GdiplusNotTrueTypeFont_NoName");
case UnsupportedGdiplusVersion: return new ExternalException("GdiplusUnsupportedGdiplusVersion");
case GdiplusNotInitialized: return new ExternalException("GdiplusNotInitialized");
}
return new ExternalException("GdiplusUnknown");
}
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipImageGetFrameDimensionsList(HandleRef image, IntPtr buffer, int count);
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipImageGetFrameCount(HandleRef image, ref Guid dimensionId, int[] count);
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipGetPropertyItemSize(HandleRef image, int propid, out int size);
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipGetPropertyItem(HandleRef image, int propid, int size, IntPtr buffer);
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.Machine)]
internal static extern int GdipCreateHBITMAPFromBitmap(HandleRef nativeBitmap, out IntPtr hbitmap, int argbBackground);
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipImageSelectActiveFrame(HandleRef image, ref Guid dimensionId, int frameIndex);
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.Machine)]
internal static extern int GdipCreateBitmapFromFile(string filename, out IntPtr bitmap);
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipImageForceValidation(HandleRef image);
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, EntryPoint = "GdipDisposeImage", CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
private static extern int IntGdipDisposeImage(HandleRef image);
internal static int GdipDisposeImage(HandleRef image)
{
if (!Initialized) return Ok;
var result = IntGdipDisposeImage(image);
return result;
}
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.Process)]
private static extern int GdiplusStartup(out IntPtr token, ref StartupInput input, out StartupOutput output);
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipGetImageRawFormat(HandleRef image, ref Guid format);
[DllImport(Gdiplus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.Machine)]
internal static extern int GdipCreateBitmapFromStream(IStream stream, out IntPtr bitmap);
}
}
}
@@ -1,15 +1,24 @@
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
namespace HandyControl.Tools.Interop
{
internal class InteropMethods
{
#region common
public const int E_FAIL = unchecked((int)0x80004005);
internal static readonly IntPtr HRGN_NONE = new IntPtr(-1);
[DllImport(InteropValues.ExternDll.User32, CharSet = CharSet.Auto)]
@@ -101,7 +110,7 @@ namespace HandyControl.Tools.Interop
[SecurityCritical]
internal static int ReleaseDC(HandleRef hWnd, HandleRef hDC)
{
HandleCollector.Remove((IntPtr) hDC, CommonHandles.HDC);
HandleCollector.Remove((IntPtr)hDC, CommonHandles.HDC);
return IntReleaseDC(hWnd, hDC);
}
@@ -280,7 +289,7 @@ namespace HandyControl.Tools.Interop
[DllImport(InteropValues.ExternDll.User32, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetWindowPlacement(IntPtr hwnd, InteropValues.WINDOWPLACEMENT lpwndpl);
internal static InteropValues.WINDOWPLACEMENT GetWindowPlacement(IntPtr hwnd)
{
InteropValues.WINDOWPLACEMENT wINDOWPLACEMENT = new InteropValues.WINDOWPLACEMENT();
@@ -298,18 +307,18 @@ namespace HandyControl.Tools.Interop
internal static int HiWord(int value) => (short)(value >> 16);
internal static int LoWord(int value) => (short)(value & 65535);
[DllImport(InteropValues.ExternDll.User32)]
internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags);
[DllImport(InteropValues.ExternDll.User32)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool EnumThreadWindows(uint dwThreadId, InteropValues.EnumWindowsProc lpfn, IntPtr lParam);
[DllImport(InteropValues.ExternDll.Gdi32)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeleteDC(IntPtr hdc);
[DllImport(InteropValues.ExternDll.Gdi32, SetLastError = true)]
internal static extern IntPtr CreateCompatibleDC(IntPtr hdc);
@@ -321,26 +330,26 @@ namespace HandyControl.Tools.Interop
[DllImport(InteropValues.ExternDll.User32)]
internal static extern IntPtr MonitorFromPoint(InteropValues.POINT pt, int flags);
[DllImport(InteropValues.ExternDll.User32)]
internal static extern IntPtr GetWindow(IntPtr hwnd, int nCmd);
[DllImport(InteropValues.ExternDll.User32)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool IsWindowVisible(IntPtr hwnd);
[DllImport(InteropValues.ExternDll.User32)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool IsIconic(IntPtr hwnd);
[DllImport(InteropValues.ExternDll.User32)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool IsZoomed(IntPtr hwnd);
[DllImport(InteropValues.ExternDll.User32, CharSet = CharSet.Auto, ExactSpelling = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, int flags);
internal static System.Windows.Point GetCursorPos()
{
var result = default(System.Windows.Point);
@@ -365,19 +374,19 @@ namespace HandyControl.Tools.Interop
}
return SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
}
[DllImport(InteropValues.ExternDll.User32, CharSet = CharSet.Auto, EntryPoint = "SetWindowLong")]
internal static extern IntPtr SetWindowLongPtr32(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport(InteropValues.ExternDll.User32, CharSet = CharSet.Auto, EntryPoint = "SetWindowLongPtr")]
internal static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
[DllImport(InteropValues.ExternDll.User32, CharSet = CharSet.Unicode)]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[DllImport(InteropValues.ExternDll.User32, CharSet = CharSet.Unicode)]
private static extern IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr dwNewLong);
internal static IntPtr SetWindowLongPtr(IntPtr hWnd, InteropValues.GWLP nIndex, IntPtr dwNewLong)
{
if (IntPtr.Size == 8)
@@ -386,7 +395,7 @@ namespace HandyControl.Tools.Interop
}
return new IntPtr(SetWindowLong(hWnd, (int)nIndex, dwNewLong.ToInt32()));
}
internal static int SetWindowLong(IntPtr hWnd, InteropValues.GWL nIndex, int dwNewLong) => SetWindowLong(hWnd, (int)nIndex, dwNewLong);
[DllImport(InteropValues.ExternDll.User32, CharSet = CharSet.Unicode)]
@@ -401,37 +410,37 @@ namespace HandyControl.Tools.Interop
[DllImport(InteropValues.ExternDll.User32)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DestroyWindow(IntPtr hwnd);
[DllImport(InteropValues.ExternDll.User32)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool UnregisterClass(IntPtr classAtom, IntPtr hInstance);
[DllImport(InteropValues.ExternDll.User32)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDest, ref InteropValues.POINT pptDest, ref InteropValues.SIZE psize, IntPtr hdcSrc, ref InteropValues.POINT pptSrc, uint crKey, [In] ref InteropValues.BLENDFUNCTION pblend, uint dwFlags);
[DllImport(InteropValues.ExternDll.User32)]
internal static extern bool RedrawWindow(IntPtr hWnd, IntPtr lprcUpdate, IntPtr hrgnUpdate, InteropValues.RedrawWindowFlags flags);
[DllImport(InteropValues.ExternDll.User32)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr lprcClip, InteropValues.EnumMonitorsDelegate lpfnEnum, IntPtr dwData);
[DllImport(InteropValues.ExternDll.User32)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool IntersectRect(out InteropValues.RECT lprcDst, [In] ref InteropValues.RECT lprcSrc1, [In] ref InteropValues.RECT lprcSrc2);
[DllImport(InteropValues.ExternDll.User32)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetMonitorInfo(IntPtr hMonitor, ref InteropValues.MONITORINFO monitorInfo);
[DllImport(InteropValues.ExternDll.Gdi32, SetLastError = true)]
internal static extern IntPtr CreateDIBSection(IntPtr hdc, ref InteropValues.BITMAPINFO pbmi, uint iUsage, out IntPtr ppvBits, IntPtr hSection, uint dwOffset);
[DllImport(InteropValues.ExternDll.MsImg)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool AlphaBlend(IntPtr hdcDest, int xoriginDest, int yoriginDest, int wDest, int hDest, IntPtr hdcSrc, int xoriginSrc, int yoriginSrc, int wSrc, int hSrc, InteropValues.BLENDFUNCTION pfn);
internal static int GET_SC_WPARAM(IntPtr wParam) => (int)wParam & 65520;
[DllImport(InteropValues.ExternDll.User32)]
@@ -446,5 +455,251 @@ namespace HandyControl.Tools.Interop
[DllImport(InteropValues.ExternDll.User32)]
[ResourceExposure(ResourceScope.None)]
internal static extern bool EnableWindow(IntPtr hWnd, bool enable);
[ReflectionPermission(SecurityAction.Assert, Unrestricted = true), SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)]
internal static object PtrToStructure(IntPtr lparam, Type cls) => Marshal.PtrToStructure(lparam, cls);
[ReflectionPermission(SecurityAction.Assert, Unrestricted = true),
SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static void PtrToStructure(IntPtr lparam, object data) => Marshal.PtrToStructure(lparam, data);
#endregion
internal class Gdip
{
private const string ThreadDataSlotName = "system.drawing.threaddata";
private static IntPtr InitToken;
private static bool Initialized => InitToken != IntPtr.Zero;
internal const int
Ok = 0,
GenericError = 1,
InvalidParameter = 2,
OutOfMemory = 3,
ObjectBusy = 4,
InsufficientBuffer = 5,
NotImplemented = 6,
Win32Error = 7,
WrongState = 8,
Aborted = 9,
FileNotFound = 10,
ValueOverflow = 11,
AccessDenied = 12,
UnknownImageFormat = 13,
FontFamilyNotFound = 14,
FontStyleNotFound = 15,
NotTrueTypeFont = 16,
UnsupportedGdiplusVersion = 17,
GdiplusNotInitialized = 18,
PropertyNotFound = 19,
PropertyNotSupported = 20,
E_UNEXPECTED = unchecked((int)0x8000FFFF);
static Gdip()
{
Initialize();
}
[StructLayout(LayoutKind.Sequential)]
private struct StartupInput
{
private int GdiplusVersion;
private readonly IntPtr DebugEventCallback;
private bool SuppressBackgroundThread;
private bool SuppressExternalCodecs;
public static StartupInput GetDefault()
{
var result = new StartupInput
{
GdiplusVersion = 1,
SuppressBackgroundThread = false,
SuppressExternalCodecs = false
};
return result;
}
}
[StructLayout(LayoutKind.Sequential)]
private struct StartupOutput
{
private readonly IntPtr hook;
private readonly IntPtr unhook;
}
[ResourceExposure(ResourceScope.None)]
[ResourceConsumption(ResourceScope.AppDomain, ResourceScope.AppDomain)]
[SuppressMessage("Microsoft.Performance", "CA1804:RemoveUnusedLocals")]
private static void Initialize()
{
var input = StartupInput.GetDefault();
var status = GdiplusStartup(out InitToken, ref input, out _);
if (status != Ok)
{
throw StatusException(status);
}
var currentDomain = AppDomain.CurrentDomain;
currentDomain.ProcessExit += OnProcessExit;
if (!currentDomain.IsDefaultAppDomain())
{
currentDomain.DomainUnload += OnProcessExit;
}
}
[PrePrepareMethod]
[ResourceExposure(ResourceScope.AppDomain)]
[ResourceConsumption(ResourceScope.AppDomain)]
private static void OnProcessExit(object sender, EventArgs e) => Shutdown();
[SuppressMessage("Microsoft.Reliability", "CA2001:AvoidCallingProblematicMethods")]
[ResourceExposure(ResourceScope.AppDomain)]
[ResourceConsumption(ResourceScope.AppDomain)]
private static void Shutdown()
{
if (Initialized)
{
ClearThreadData();
// unhook our shutdown handlers as we do not need to shut down more than once
var currentDomain = AppDomain.CurrentDomain;
currentDomain.ProcessExit -= OnProcessExit;
if (!currentDomain.IsDefaultAppDomain())
{
currentDomain.DomainUnload -= OnProcessExit;
}
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ClearThreadData()
{
var slot = Thread.GetNamedDataSlot(ThreadDataSlotName);
Thread.SetData(slot, null);
}
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipImageGetFrameDimensionsCount(HandleRef image, out int count);
internal static Exception StatusException(int status)
{
switch (status)
{
case GenericError: return new ExternalException("GdiplusGenericError");
case InvalidParameter: return new ArgumentException("GdiplusInvalidParameter");
case OutOfMemory: return new OutOfMemoryException("GdiplusOutOfMemory");
case ObjectBusy: return new InvalidOperationException("GdiplusObjectBusy");
case InsufficientBuffer: return new OutOfMemoryException("GdiplusInsufficientBuffer");
case NotImplemented: return new NotImplementedException("GdiplusNotImplemented");
case Win32Error: return new ExternalException("GdiplusGenericError");
case WrongState: return new InvalidOperationException("GdiplusWrongState");
case Aborted: return new ExternalException("GdiplusAborted");
case FileNotFound: return new FileNotFoundException("GdiplusFileNotFound");
case ValueOverflow: return new OverflowException("GdiplusOverflow");
case AccessDenied: return new ExternalException("GdiplusAccessDenied");
case UnknownImageFormat: return new ArgumentException("GdiplusUnknownImageFormat");
case PropertyNotFound: return new ArgumentException("GdiplusPropertyNotFoundError");
case PropertyNotSupported: return new ArgumentException("GdiplusPropertyNotSupportedError");
case FontFamilyNotFound: return new ArgumentException("GdiplusFontFamilyNotFound");
case FontStyleNotFound: return new ArgumentException("GdiplusFontStyleNotFound");
case NotTrueTypeFont: return new ArgumentException("GdiplusNotTrueTypeFont_NoName");
case UnsupportedGdiplusVersion: return new ExternalException("GdiplusUnsupportedGdiplusVersion");
case GdiplusNotInitialized: return new ExternalException("GdiplusNotInitialized");
}
return new ExternalException("GdiplusUnknown");
}
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipImageGetFrameDimensionsList(HandleRef image, IntPtr buffer, int count);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipImageGetFrameCount(HandleRef image, ref Guid dimensionId, int[] count);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipGetPropertyItemSize(HandleRef image, int propid, out int size);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipGetPropertyItem(HandleRef image, int propid, int size, IntPtr buffer);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.Machine)]
internal static extern int GdipCreateHBITMAPFromBitmap(HandleRef nativeBitmap, out IntPtr hbitmap, int argbBackground);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipImageSelectActiveFrame(HandleRef image, ref Guid dimensionId, int frameIndex);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.Machine)]
internal static extern int GdipCreateBitmapFromFile(string filename, out IntPtr bitmap);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipImageForceValidation(HandleRef image);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, EntryPoint = "GdipDisposeImage", CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
private static extern int IntGdipDisposeImage(HandleRef image);
internal static int GdipDisposeImage(HandleRef image)
{
if (!Initialized) return Ok;
var result = IntGdipDisposeImage(image);
return result;
}
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.Process)]
private static extern int GdiplusStartup(out IntPtr token, ref StartupInput input, out StartupOutput output);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipGetImageRawFormat(HandleRef image, ref Guid format);
[DllImport(InteropValues.ExternDll.User32)]
internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref InteropValues.WINCOMPATTRDATA data);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.Machine)]
internal static extern int GdipCreateBitmapFromStream(InteropValues.IStream stream, out IntPtr bitmap);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.Machine)]
internal static extern int GdipCreateBitmapFromHBITMAP(HandleRef hbitmap, HandleRef hpalette, out IntPtr bitmap);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipGetImageEncodersSize(out int numEncoders, out int size);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipGetImageDecodersSize(out int numDecoders, out int size);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipGetImageDecoders(int numDecoders, int size, IntPtr decoders);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipGetImageEncoders(int numEncoders, int size, IntPtr encoders);
[DllImport(InteropValues.ExternDll.GdiPlus, SetLastError = true, ExactSpelling = true, CharSet = CharSet.Unicode)]
[ResourceExposure(ResourceScope.None)]
internal static extern int GdipSaveImageToStream(HandleRef image, InteropValues.IStream stream, ref Guid classId, HandleRef encoderParams);
}
}
}
@@ -1,4 +1,6 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Runtime.InteropServices;
using System.Security;
using System.Windows;
@@ -12,6 +14,7 @@ namespace HandyControl.Tools.Interop
public const string
User32 = "user32.dll",
Gdi32 = "gdi32.dll",
GdiPlus = "gdiplus.dll",
Kernel32 = "kernel32.dll",
Shell32 = "shell32.dll",
MsImg = "msimg32.dll";
@@ -31,6 +34,7 @@ namespace HandyControl.Tools.Interop
PLANES = 14,
BI_RGB = 0,
DIB_RGB_COLORS = 0,
E_FAIL = unchecked((int)0x80004005),
NIF_MESSAGE = 0x00000001,
NIF_ICON = 0x00000002,
NIF_TIP = 0x00000004,
@@ -659,5 +663,275 @@ namespace HandyControl.Tools.Interop
public BitmapHandle hbmMask = null;
public BitmapHandle hbmColor = null;
}
internal enum WINDOWCOMPOSITIONATTRIB
{
WCA_ACCENT_POLICY = 19
}
[StructLayout(LayoutKind.Sequential)]
internal struct WINCOMPATTRDATA
{
public WINDOWCOMPOSITIONATTRIB Attribute;
public IntPtr Data;
public int DataSize;
}
internal enum ACCENTSTATE
{
ACCENT_DISABLED = 0,
ACCENT_ENABLE_GRADIENT = 1,
ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
ACCENT_ENABLE_BLURBEHIND = 3,
ACCENT_ENABLE_ACRYLICBLURBEHIND = 4,
ACCENT_INVALID_STATE = 5
}
[StructLayout(LayoutKind.Sequential)]
internal struct ACCENTPOLICY
{
public ACCENTSTATE AccentState;
public int AccentFlags;
public uint GradientColor;
public int AnimationId;
}
[ComImport, Guid("0000000C-0000-0000-C000-000000000046"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal interface IStream
{
int Read([In] IntPtr buf, [In] int len);
int Write([In] IntPtr buf, [In] int len);
[return: MarshalAs(UnmanagedType.I8)]
long Seek([In, MarshalAs(UnmanagedType.I8)] long dlibMove, [In] int dwOrigin);
void SetSize([In, MarshalAs(UnmanagedType.I8)] long libNewSize);
[return: MarshalAs(UnmanagedType.I8)]
long CopyTo([In, MarshalAs(UnmanagedType.Interface)] IStream pstm, [In, MarshalAs(UnmanagedType.I8)] long cb, [Out, MarshalAs(UnmanagedType.LPArray)] long[] pcbRead);
void Commit([In]int grfCommitFlags);
void Revert();
void LockRegion([In, MarshalAs(UnmanagedType.I8)]long libOffset, [In, MarshalAs(UnmanagedType.I8)] long cb, [In] int dwLockType);
void UnlockRegion([In, MarshalAs(UnmanagedType.I8)] long libOffset, [In, MarshalAs(UnmanagedType.I8)] long cb, [In] int dwLockType);
void Stat([In] IntPtr pStatstg, [In] int grfStatFlag);
[return: MarshalAs(UnmanagedType.Interface)]
IStream Clone();
}
[SuppressMessage("ReSharper", "InconsistentNaming")]
internal class StreamConsts
{
public const int LOCK_WRITE = 0x1;
public const int LOCK_EXCLUSIVE = 0x2;
public const int LOCK_ONLYONCE = 0x4;
public const int STATFLAG_DEFAULT = 0x0;
public const int STATFLAG_NONAME = 0x1;
public const int STATFLAG_NOOPEN = 0x2;
public const int STGC_DEFAULT = 0x0;
public const int STGC_OVERWRITE = 0x1;
public const int STGC_ONLYIFCURRENT = 0x2;
public const int STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 0x4;
public const int STREAM_SEEK_SET = 0x0;
public const int STREAM_SEEK_CUR = 0x1;
public const int STREAM_SEEK_END = 0x2;
}
[StructLayout(LayoutKind.Sequential, Pack = 8)]
internal class ImageCodecInfoPrivate
{
[MarshalAs(UnmanagedType.Struct)]
public Guid Clsid;
[MarshalAs(UnmanagedType.Struct)]
public Guid FormatID;
public IntPtr CodecName = IntPtr.Zero;
public IntPtr DllName = IntPtr.Zero;
public IntPtr FormatDescription = IntPtr.Zero;
public IntPtr FilenameExtension = IntPtr.Zero;
public IntPtr MimeType = IntPtr.Zero;
public int Flags;
public int Version;
public int SigCount;
public int SigSize;
public IntPtr SigPattern = IntPtr.Zero;
public IntPtr SigMask = IntPtr.Zero;
}
internal class ComStreamFromDataStream : IStream
{
protected Stream DataStream;
// to support seeking ahead of the stream length...
private long _virtualPosition = -1;
internal ComStreamFromDataStream(Stream dataStream)
{
this.DataStream = dataStream ?? throw new ArgumentNullException(nameof(dataStream));
}
private void ActualizeVirtualPosition()
{
if (_virtualPosition == -1) return;
if (_virtualPosition > DataStream.Length)
DataStream.SetLength(_virtualPosition);
DataStream.Position = _virtualPosition;
_virtualPosition = -1;
}
public virtual IStream Clone()
{
NotImplemented();
return null;
}
public virtual void Commit(int grfCommitFlags)
{
DataStream.Flush();
ActualizeVirtualPosition();
}
public virtual long CopyTo(IStream pstm, long cb, long[] pcbRead)
{
const int bufsize = 4096; // one page
var buffer = Marshal.AllocHGlobal(bufsize);
if (buffer == IntPtr.Zero) throw new OutOfMemoryException();
long written = 0;
try
{
while (written < cb)
{
var toRead = bufsize;
if (written + toRead > cb) toRead = (int)(cb - written);
var read = Read(buffer, toRead);
if (read == 0) break;
if (pstm.Write(buffer, read) != read)
{
throw EFail("Wrote an incorrect number of bytes");
}
written += read;
}
}
finally
{
Marshal.FreeHGlobal(buffer);
}
if (pcbRead != null && pcbRead.Length > 0)
{
pcbRead[0] = written;
}
return written;
}
public virtual Stream GetDataStream() => DataStream;
public virtual void LockRegion(long libOffset, long cb, int dwLockType)
{
}
protected static ExternalException EFail(string msg) => throw new ExternalException(msg, E_FAIL);
protected static void NotImplemented() => throw new NotImplementedException();
public virtual int Read(IntPtr buf, int length)
{
var buffer = new byte[length];
var count = Read(buffer, length);
Marshal.Copy(buffer, 0, buf, length);
return count;
}
public virtual int Read(byte[] buffer, int length)
{
ActualizeVirtualPosition();
return DataStream.Read(buffer, 0, length);
}
public virtual void Revert() => NotImplemented();
public virtual long Seek(long offset, int origin)
{
var pos = _virtualPosition;
if (_virtualPosition == -1)
{
pos = DataStream.Position;
}
var len = DataStream.Length;
switch (origin)
{
case StreamConsts.STREAM_SEEK_SET:
if (offset <= len)
{
DataStream.Position = offset;
_virtualPosition = -1;
}
else
{
_virtualPosition = offset;
}
break;
case StreamConsts.STREAM_SEEK_END:
if (offset <= 0)
{
DataStream.Position = len + offset;
_virtualPosition = -1;
}
else
{
_virtualPosition = len + offset;
}
break;
case StreamConsts.STREAM_SEEK_CUR:
if (offset + pos <= len)
{
DataStream.Position = pos + offset;
_virtualPosition = -1;
}
else
{
_virtualPosition = offset + pos;
}
break;
}
return _virtualPosition != -1 ? _virtualPosition : DataStream.Position;
}
public virtual void SetSize(long value) => DataStream.SetLength(value);
public virtual void Stat(IntPtr pstatstg, int grfStatFlag) => NotImplemented();
public virtual void UnlockRegion(long libOffset, long cb, int dwLockType)
{
}
public virtual int Write(IntPtr buf, int length)
{
var buffer = new byte[length];
Marshal.Copy(buf, buffer, 0, length);
return Write(buffer, length);
}
public virtual int Write(byte[] buffer, int length)
{
ActualizeVirtualPosition();
DataStream.Write(buffer, 0, length);
return length;
}
}
}
}