From 58417130e0657c1bbead0785958d9dacfab53207 Mon Sep 17 00:00:00 2001 From: Joe Castro Date: Mon, 18 Feb 2013 19:47:46 -0800 Subject: [PATCH 01/21] Initial commit --- .gitignore | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 4 ++ 2 files changed, 112 insertions(+) create mode 100644 .gitignore create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bdc3535 --- /dev/null +++ b/.gitignore @@ -0,0 +1,108 @@ +# Build Folders (you can keep bin if you'd like, to store dlls and pdbs) +[Bb]in/ +[Oo]bj/ + +# mstest test results +TestResults + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Rr]elease/ +x64/ +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.log +*.vspscc +*.vssscc +.builds + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper* + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish + +# Publish Web Output +*.Publish.xml + +# NuGet Packages Directory +packages + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +[Bb]in +[Oo]bj +sql +TestResults +[Tt]est[Rr]esult* +*.Cache +ClientBin +[Ss]tyle[Cc]op.* +~$* +*.dbmdl +Generated_Code #added for RIA/Silverlight projects + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML diff --git a/README.md b/README.md new file mode 100644 index 0000000..2413fca --- /dev/null +++ b/README.md @@ -0,0 +1,4 @@ +wpf-shell +========= + +Further extensions of the WPF Shell Integration Library \ No newline at end of file From 89517baf72678ba164294fbb5711d3614c58bbdd Mon Sep 17 00:00:00 2001 From: Joe Castro Date: Mon, 18 Feb 2013 19:55:37 -0800 Subject: [PATCH 02/21] Cloning snapshot of most recent release of WPF Shell Integration Library http://archive.msdn.microsoft.com/WPFShell --- Microsoft.Windows.Shell.sln | 42 + Microsoft.Windows.Shell/JumpItem.cs | 17 + Microsoft.Windows.Shell/JumpList.cs | 1151 ++++++ Microsoft.Windows.Shell/JumpPath.cs | 14 + Microsoft.Windows.Shell/JumpTask.cs | 26 + .../Microsoft.Windows.Shell.csproj | 165 + .../Properties/AssemblyInfo.cs | 31 + Microsoft.Windows.Shell/Standard/ComGuids.cs | 95 + Microsoft.Windows.Shell/Standard/Debug.cs | 373 ++ .../Standard/DoubleUtil.cs | 132 + Microsoft.Windows.Shell/Standard/DpiHelper.cs | 86 + .../Standard/ErrorCodes.cs | 508 +++ .../Standard/MessageWindow.cs | 169 + .../Standard/NativeMethods.cs | 3458 +++++++++++++++++ .../Standard/ShellProvider.cs | 967 +++++ .../Standard/StreamHelper.cs | 341 ++ Microsoft.Windows.Shell/Standard/Utilities.cs | 1037 +++++ Microsoft.Windows.Shell/Standard/Verify.cs | 312 ++ Microsoft.Windows.Shell/SystemCommands.cs | 91 + Microsoft.Windows.Shell/SystemParameters2.cs | 557 +++ Microsoft.Windows.Shell/TaskbarItemInfo.cs | 856 ++++ Microsoft.Windows.Shell/ThumbButtonInfo.cs | 347 ++ .../ThumbButtonInfoCollection.cs | 36 + Microsoft.Windows.Shell/WindowChrome.cs | 235 ++ Microsoft.Windows.Shell/WindowChromeWorker.cs | 1195 ++++++ Microsoft.Windows.Shell/app.config | 3 + TaskbarSample/App.xaml | 36 + TaskbarSample/App.xaml.cs | 45 + TaskbarSample/Images/CircleGreen.png | Bin 0 -> 141343 bytes TaskbarSample/Images/CircleRed.png | Bin 0 -> 143116 bytes TaskbarSample/Images/CircleYellow.png | Bin 0 -> 116381 bytes TaskbarSample/Images/Copy.png | Bin 0 -> 643 bytes TaskbarSample/Images/Cut.png | Bin 0 -> 628 bytes TaskbarSample/Images/Paste.png | Bin 0 -> 730 bytes TaskbarSample/MainWindow.xaml | 219 ++ TaskbarSample/MainWindow.xaml.cs | 141 + TaskbarSample/Properties/AssemblyInfo.cs | 26 + TaskbarSample/TaskbarSample.csproj | 162 + TaskbarSample/app.config | 3 + TaskbarSample/app.ico | Bin 0 -> 98182 bytes WindowChromeSample/App.xaml | 4 + .../CaptionButtonRectToMarginConverter.cs | 25 + WindowChromeSample/Properties/AssemblyInfo.cs | 24 + .../SelectableChromeWindow.xaml | 102 + .../SelectableChromeWindow.xaml.cs | 40 + WindowChromeSample/WindowChromeSample.csproj | 176 + WindowChromeSample/app.config | 3 + WindowChromeSample/app.ico | Bin 0 -> 98182 bytes 48 files changed, 13250 insertions(+) create mode 100644 Microsoft.Windows.Shell.sln create mode 100644 Microsoft.Windows.Shell/JumpItem.cs create mode 100644 Microsoft.Windows.Shell/JumpList.cs create mode 100644 Microsoft.Windows.Shell/JumpPath.cs create mode 100644 Microsoft.Windows.Shell/JumpTask.cs create mode 100644 Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj create mode 100644 Microsoft.Windows.Shell/Properties/AssemblyInfo.cs create mode 100644 Microsoft.Windows.Shell/Standard/ComGuids.cs create mode 100644 Microsoft.Windows.Shell/Standard/Debug.cs create mode 100644 Microsoft.Windows.Shell/Standard/DoubleUtil.cs create mode 100644 Microsoft.Windows.Shell/Standard/DpiHelper.cs create mode 100644 Microsoft.Windows.Shell/Standard/ErrorCodes.cs create mode 100644 Microsoft.Windows.Shell/Standard/MessageWindow.cs create mode 100644 Microsoft.Windows.Shell/Standard/NativeMethods.cs create mode 100644 Microsoft.Windows.Shell/Standard/ShellProvider.cs create mode 100644 Microsoft.Windows.Shell/Standard/StreamHelper.cs create mode 100644 Microsoft.Windows.Shell/Standard/Utilities.cs create mode 100644 Microsoft.Windows.Shell/Standard/Verify.cs create mode 100644 Microsoft.Windows.Shell/SystemCommands.cs create mode 100644 Microsoft.Windows.Shell/SystemParameters2.cs create mode 100644 Microsoft.Windows.Shell/TaskbarItemInfo.cs create mode 100644 Microsoft.Windows.Shell/ThumbButtonInfo.cs create mode 100644 Microsoft.Windows.Shell/ThumbButtonInfoCollection.cs create mode 100644 Microsoft.Windows.Shell/WindowChrome.cs create mode 100644 Microsoft.Windows.Shell/WindowChromeWorker.cs create mode 100644 Microsoft.Windows.Shell/app.config create mode 100644 TaskbarSample/App.xaml create mode 100644 TaskbarSample/App.xaml.cs create mode 100644 TaskbarSample/Images/CircleGreen.png create mode 100644 TaskbarSample/Images/CircleRed.png create mode 100644 TaskbarSample/Images/CircleYellow.png create mode 100644 TaskbarSample/Images/Copy.png create mode 100644 TaskbarSample/Images/Cut.png create mode 100644 TaskbarSample/Images/Paste.png create mode 100644 TaskbarSample/MainWindow.xaml create mode 100644 TaskbarSample/MainWindow.xaml.cs create mode 100644 TaskbarSample/Properties/AssemblyInfo.cs create mode 100644 TaskbarSample/TaskbarSample.csproj create mode 100644 TaskbarSample/app.config create mode 100644 TaskbarSample/app.ico create mode 100644 WindowChromeSample/App.xaml create mode 100644 WindowChromeSample/CaptionButtonRectToMarginConverter.cs create mode 100644 WindowChromeSample/Properties/AssemblyInfo.cs create mode 100644 WindowChromeSample/SelectableChromeWindow.xaml create mode 100644 WindowChromeSample/SelectableChromeWindow.xaml.cs create mode 100644 WindowChromeSample/WindowChromeSample.csproj create mode 100644 WindowChromeSample/app.config create mode 100644 WindowChromeSample/app.ico diff --git a/Microsoft.Windows.Shell.sln b/Microsoft.Windows.Shell.sln new file mode 100644 index 0000000..04b6074 --- /dev/null +++ b/Microsoft.Windows.Shell.sln @@ -0,0 +1,42 @@ + +Microsoft Visual Studio Solution File, Format Version 11.00 +# Visual Studio 2010 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Windows.Shell", "Microsoft.Windows.Shell\Microsoft.Windows.Shell.csproj", "{55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TaskbarSample", "TaskbarSample\TaskbarSample.csproj", "{F7D0B052-2123-4DFD-B844-C545A1082514}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowChromeSample", "WindowChromeSample\WindowChromeSample.csproj", "{7E654166-1387-43D9-956C-6B473C514545}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Debug|x86.ActiveCfg = Debug|x86 + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Debug|x86.Build.0 = Debug|x86 + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Release|Any CPU.Build.0 = Release|Any CPU + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Release|x86.ActiveCfg = Release|x86 + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Release|x86.Build.0 = Release|x86 + {F7D0B052-2123-4DFD-B844-C545A1082514}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F7D0B052-2123-4DFD-B844-C545A1082514}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F7D0B052-2123-4DFD-B844-C545A1082514}.Debug|x86.ActiveCfg = Debug|Any CPU + {F7D0B052-2123-4DFD-B844-C545A1082514}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F7D0B052-2123-4DFD-B844-C545A1082514}.Release|Any CPU.Build.0 = Release|Any CPU + {F7D0B052-2123-4DFD-B844-C545A1082514}.Release|x86.ActiveCfg = Release|Any CPU + {7E654166-1387-43D9-956C-6B473C514545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7E654166-1387-43D9-956C-6B473C514545}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7E654166-1387-43D9-956C-6B473C514545}.Debug|x86.ActiveCfg = Debug|Any CPU + {7E654166-1387-43D9-956C-6B473C514545}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7E654166-1387-43D9-956C-6B473C514545}.Release|Any CPU.Build.0 = Release|Any CPU + {7E654166-1387-43D9-956C-6B473C514545}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Microsoft.Windows.Shell/JumpItem.cs b/Microsoft.Windows.Shell/JumpItem.cs new file mode 100644 index 0000000..ed71a97 --- /dev/null +++ b/Microsoft.Windows.Shell/JumpItem.cs @@ -0,0 +1,17 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Microsoft.Windows.Shell +{ + public abstract class JumpItem + { + // This class is just provided to strongly type the JumpList's contents. + // It's not externally extendable. + internal JumpItem() + { + } + + public string CustomCategory { get; set; } + } +} diff --git a/Microsoft.Windows.Shell/JumpList.cs b/Microsoft.Windows.Shell/JumpList.cs new file mode 100644 index 0000000..62c2580 --- /dev/null +++ b/Microsoft.Windows.Shell/JumpList.cs @@ -0,0 +1,1151 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Microsoft.Windows.Shell +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Reflection; + using System.Text; + using System.Threading; + using System.Windows; + using System.Windows.Markup; + using Standard; + + /// + /// The list of possible reasons why a JumpItem would be rejected from a JumpList when applied. + /// + public enum JumpItemRejectionReason + { + /// + /// Unknown reason. This should not be used. + /// + None, + /// + /// The item was rejected because it was invalid for a jump list. E.g. the file path didn't exist. + /// + /// + /// If the application is running on a system where jump lists are not available (like XP or Vista) + /// items will get rejected with this reason. + /// + InvalidItem, + /// + /// The item was rejected because the program was not registered to handle the file extension. + /// + NoRegisteredHandler, + /// + /// The item was rejected because the user had explicitly removed it since the last time a JumpList was applied. + /// + RemovedByUser, + } + + /// + /// EventArgs for JumpList.JumpItemsRejected event. + /// + public sealed class JumpItemsRejectedEventArgs : EventArgs + { + public JumpItemsRejectedEventArgs() + : this(null, null) + { } + + public JumpItemsRejectedEventArgs(IList rejectedItems, IList reasons) + { + // If one of the collections is null then the other has to be, too. + if ((rejectedItems == null && reasons != null) + || (reasons == null && rejectedItems != null) + || (rejectedItems != null && reasons != null && rejectedItems.Count != reasons.Count)) + { + throw new ArgumentException("The counts of rejected items doesn't match the count of reasons."); + } + + // We don't want the contents of the list getting modified in the event handler, + // so use a read-only copy + if (rejectedItems != null) + { + RejectedItems = new List(rejectedItems).AsReadOnly(); + RejectionReasons = new List(reasons).AsReadOnly(); + } + else + { + RejectedItems = new List().AsReadOnly(); + RejectionReasons = new List().AsReadOnly(); + } + } + + public IList RejectedItems { get; private set; } + public IList RejectionReasons { get; private set; } + } + + /// + /// EventArgs for JumpList.JumpItemsRemovedByUser event. + /// + public sealed class JumpItemsRemovedEventArgs : EventArgs + { + public JumpItemsRemovedEventArgs() + : this(null) + { } + + public JumpItemsRemovedEventArgs(IList removedItems) + { + if (removedItems != null) + { + RemovedItems = new List(removedItems).AsReadOnly(); + } + else + { + RemovedItems = new List().AsReadOnly(); + } + } + + public IList RemovedItems { get; private set; } + } + + /// + /// Manage the tasks and files that Shell associates with this application. + /// This allows modification of the Jump List UI in Windows 7 that appears on the Taskbar and Start Menu. + /// + [ContentProperty("JumpItems")] + public sealed class JumpList : ISupportInitialize + { + [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] + static JumpList() + { + // Passing NULL for the HMODULE returns the running executable path. + _FullName = NativeMethods.GetModuleFileName(IntPtr.Zero); + } + + /// + /// Add the item at the specified file path to the application's JumpList's recent items. + /// + /// + /// This makes the item eligible for inclusion in the special Recent and Frequent categories. + /// + public static void AddToRecentCategory(string itemPath) + { + Verify.FileExists(itemPath, "itemPath"); + itemPath = Path.GetFullPath(itemPath); + NativeMethods.SHAddToRecentDocs(itemPath); + } + + /// + /// Add the item to the application's JumpList's recent items. + /// + /// + /// This makes the item eligible for inclusion in the special Recent and Frequent categories. + /// + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + public static void AddToRecentCategory(JumpPath jumpPath) + { + Verify.IsNotNull(jumpPath, "jumpPath"); + AddToRecentCategory(jumpPath.Path); + } + + /// + /// Add the task at the specified file path to the application's JumpList's recent items. + /// + /// + /// This makes the item eligible for inclusion in the special Recent and Frequent categories. + /// + public static void AddToRecentCategory(JumpTask jumpTask) + { + Verify.IsNotNull(jumpTask, "jumpTask"); + + // SHAddToRecentDocs only allows IShellLinks in Windows 7 and later. + // Silently fail this if that's not the case. + // We don't give feedback on success here, so this is okay. + if (Utility.IsOSWindows7OrNewer) + { + IShellLinkW shellLink = CreateLinkFromJumpTask(jumpTask, false); + try + { + if (shellLink != null) + { + NativeMethods.SHAddToRecentDocs(shellLink); + } + } + finally + { + Utility.SafeRelease(ref shellLink); + } + } + } + + private class _RejectedJumpItemPair + { + public JumpItem JumpItem { get; set; } + public JumpItemRejectionReason Reason { get; set; } + } + + private class _ShellObjectPair + { + // JumpPath/JumpTask + public JumpItem JumpItem { get; set; } + // IShellItem/IShellLink + public object ShellObject { get; set; } + + /// + /// Releases all native references in a list of _ShellObjectPairs. + /// + /// The list from which to release the resources. + public static void ReleaseShellObjects(List<_ShellObjectPair> list) + { + if (list != null) + { + foreach (_ShellObjectPair shellMap in list) + { + object o = shellMap.ShellObject; + shellMap.ShellObject = null; + Utility.SafeRelease(ref o); + } + } + } + } + + #region Attached Property Methods + + /// + /// Set the JumpList attached property on an Application. + /// + public static void SetJumpList(Application application, JumpList value) + { + Verify.IsNotNull(application, "application"); + + lock (s_lock) + { + // If this was associated with a different application, remove the association. + JumpList oldValue; + if (s_applicationMap.TryGetValue(application, out oldValue) && oldValue != null) + { + oldValue._application = null; + } + + // Associate the jumplist with the application so we can retrieve it later. + s_applicationMap[application] = value; + + if (value != null) + { + value._application = application; + } + } + + if (value != null) + { + // Changes will only get applied if the list isn't in an ISupportInitialize block. + value.ApplyFromApplication(); + } + } + + /// + /// Get the JumpList attached property for an Application. + /// + public static JumpList GetJumpList(Application application) + { + Verify.IsNotNull(application, "application"); + + JumpList value; + s_applicationMap.TryGetValue(application, out value); + return value; + } + + #endregion + + // static lock to ensure integrity when modifying instances as attached properties on Application. + private static readonly object s_lock = new object(); + private static readonly Dictionary s_applicationMap = new Dictionary(); + + private Application _application; + + // Used to enforce the ISupportInitialize contract. It's not required to BeginInit to use this class, + // but it is useful for XAML scenarios so we can apply the changes when both EndInit has been called + // and the Application attached property has been set. + private bool? _initializing; + + // The internal list of JumpItems in this JumpList + private List _jumpItems; + + public JumpList() + : this(null, false, false) + { + // Restore the ability to use ISupportInitialize. + _initializing = null; + } + + public JumpList(IEnumerable items, bool showFrequent, bool showRecent) + { + if (items != null) + { + _jumpItems = new List(items); + } + else + { + _jumpItems = new List(); + } + + ShowFrequentCategory = showFrequent; + ShowRecentCategory = showRecent; + + // Using this constructor precludes using ISupportInitialize. + _initializing = false; + } + + /// + /// Whether to show the special "Frequent" category. + /// + /// + /// This category is managed by the Shell and keeps track of items that are frequently accessed by this program. + /// Applications can request that specific items are included here by calling JumpList.AddToRecentCategory. + /// Because of duplication, applications generally should not have both ShowRecentCategory and ShowFrequentCategory set at the same time. + /// + public bool ShowFrequentCategory { get; set; } + + /// + /// Whether to show the special "Recent" category. + /// + /// + /// This category is managed by the Shell and keeps track of items that have been recently accessed by this program. + /// Applications can request that specific items are included here by calling JumpList.AddToRecentCategory + /// Because of duplication, applications generally should not have both ShowRecentCategory and ShowFrequentCategory set at the same time. + /// + public bool ShowRecentCategory { get; set; } + + /// + /// The list of JumpItems to be in the JumpList. After a call to Apply this list will contain only those items that were successfully added. + /// + /// + /// This object is not guaranteed to retain its identity after a call to Apply or other implicit setting of the JumpList. + /// It should be requeried at such times. + /// + [SuppressMessage("Microsoft.Design", "CA1002:DoNotExposeGenericLists")] + public List JumpItems + { + get { return _jumpItems; } + } + + private bool _IsUnmodified + { + get + { + return _initializing == null + && JumpItems.Count == 0 + && !ShowRecentCategory + && !ShowFrequentCategory; + } + } + + #region ISupportInitialize Members + + /// + /// Prepare the JumpList for modification. + /// + /// + /// This works in concert with the Application.JumpList attached property. The JumpList will automatically be applied + /// to the current application when attached and a corresponding call to EndInit is made. + /// Nested calls to BeginInit are not allowed. + /// + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "BeginInit")] + public void BeginInit() + { + if (!_IsUnmodified) + { + throw new InvalidOperationException("Calls to BeginInit cannot be nested."); + } + + _initializing = true; + } + + /// + /// Signal the end of initialization of this JumpList. If it is attached to the current Application, apply the contents of the jump list. + /// + /// + /// Calls to EndInit must be paired with calls to BeginInit. + /// + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "EndInit")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "BeginInit")] + public void EndInit() + { + if (_initializing != true) + { + throw new NotSupportedException("Can't call EndInit without first calling BeginInit."); + } + + _initializing = false; + + // EndInit only implicitly applies the list if the current Application has been set as an attached property. + ApplyFromApplication(); + } + + #endregion + + /// + /// Get the AppUserModelId for the running process. + /// + /// + /// This is a Shell property that currently is only used as part of a heuristic + /// for what taskbar item an HWND should be associated with, e.g. you can put + /// windows from multiple processes into the same group, or you can prevent glomming + /// of HWNDs that would otherwise be shown together. + /// + /// Even though this property isn't exposed on the public WPF OM + /// we still want to make sure that the jump list gets associated with + /// the current running app even if the client has explicitly changed the id. + /// + /// It's straightforward to p/invoke to set these for the running application or + /// the HWND. Not so much for this object. + /// + private static string _RuntimeId + { + get + { + string appId; + HRESULT hr = NativeMethods.GetCurrentProcessExplicitAppUserModelID(out appId); + if (hr == HRESULT.E_FAIL) + { + // This is how Shell signals that the app id hasn't been set. + hr = HRESULT.S_OK; + appId = null; + } + hr.ThrowIfFailed(); + return appId; + } + } + + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "JumpList")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "EndInit")] + public void Apply() + { + if (_initializing == true) + { + throw new InvalidOperationException("The JumpList can't be applied until EndInit has been called."); + } + + // After this attempting to use ISupportInitialize is invalid. + _initializing = false; + + _ApplyList(); + } + + private void ApplyFromApplication() + { + // If we're here and the caller has modified the JumpList without using ISupportInitialize + // we still want to apply the changes. + if (_initializing != true && !_IsUnmodified) + { + _initializing = false; + } + + if (_application == Application.Current && _initializing == false) + { + // If we're applying due to being an attached property, then don't apply + // unless we're really on the current application and wait until EndInit + // has been called, or the list has otherwise been modified. + _ApplyList(); + } + } + + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "JumpLists")] + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.Verify.IsApartmentState(System.Threading.ApartmentState,System.String)")] + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + private void _ApplyList() + { + Debug.Assert(_initializing == false); + Verify.IsApartmentState(ApartmentState.STA, "JumpLists can only be effected on STA threads."); + + // We don't want to force applications to conditionally check this before constructing a JumpList, + // but if we're not on 7 then this isn't going to work. Fail fast. + if (!Utility.IsOSWindows7OrNewer) + { + RejectEverything(); + return; + } + + List successList; + List<_RejectedJumpItemPair> rejectedList; + List<_ShellObjectPair> removedList; + + try + { + _BuildShellLists(out successList, out rejectedList, out removedList); + } + catch (Exception) + { + // It's not okay to throw an exception here. If Shell is rejecting the JumpList for some reason + // we don't want to be responsible for the app throwing an exception in its startup path. + // For common use patterns there isn't really any user code on the stack, so there isn't + // an opportunity to catch this in the app. + // We can instead handle this. + Assert.Fail(); + RejectEverything(); + return; + } + + _jumpItems = successList; + + // Raise the events for rejected and removed. + EventHandler rejectedHandler = JumpItemsRejected; + EventHandler removedHandler = JumpItemsRemovedByUser; + + if (rejectedList.Count > 0 && rejectedHandler != null) + { + var items = new List(rejectedList.Count); + var reasons = new List(rejectedList.Count); + + foreach (_RejectedJumpItemPair rejectionPair in rejectedList) + { + items.Add(rejectionPair.JumpItem); + reasons.Add(rejectionPair.Reason); + } + + rejectedHandler(this, new JumpItemsRejectedEventArgs(items, reasons)); + } + + if (removedList.Count > 0 && removedHandler != null) + { + var items = new List(removedList.Count); + foreach (_ShellObjectPair shellMap in removedList) + { + // It's possible that not every shell object could be converted to a JumpItem. + if (shellMap.JumpItem != null) + { + items.Add(shellMap.JumpItem); + } + } + + if (items.Count > 0) + { + removedHandler(this, new JumpItemsRemovedEventArgs(items)); + } + } + } + + private void _BuildShellLists(out List successList, out List<_RejectedJumpItemPair> rejectedList, out List<_ShellObjectPair> removedList) + { + // Declare these outside the try block so we can cleanup native resources in the _ShellObjectPairs. + List> categories = null; + removedList = null; + ICustomDestinationList destinationList = CLSID.CoCreateInstance(CLSID.DestinationList); + try + { + // Even though we're not exposing Shell's AppModelId concept, we'll still respect it + // since it's easy to clients to p/invoke to set it for Application and Window, but not for JumpLists + string appId = _RuntimeId; + if (!string.IsNullOrEmpty(appId)) + { + destinationList.SetAppID(appId); + } + + // The number ot items visible on a jump list is a user setting. Shell doesn't reject items based on overflow. + // We don't bother checking against it because the app can query the setting and manage overflow based on it + // if they really care. We'll happily add too many items with the hope that if the user changes the setting + // items will be recovered from the overflow. + uint slotsVisible; + Guid removedIid = new Guid(IID.ObjectArray); + var objectsRemoved = (IObjectArray)destinationList.BeginList(out slotsVisible, ref removedIid); + + // Keep track of the items that were previously removed by the user. + // We don't want to pend any items that are contained in this list. + // It's possible that this contains null JumpItems when we were unable to do the conversion. + removedList = GenerateJumpItems(objectsRemoved); + + // Keep track of the items that have been successfully pended. + // IMPORTANT: Ensure at the end of this that if the list is applied again that it would + // result in items being added to the JumpList in the same order. + // This doesn't mean that they'll be ordered the same as how the user added them + // (e.g. categories will be coalesced), but the categories should appear in the same order. + // Since when we call AddCategory we're doing it in reverse order, AddCategory augments + // the items in the list in reverse as well. At the end the final list is reversed. + successList = new List(JumpItems.Count); + + // Keep track of the items that we couldn't pend, and why. + rejectedList = new List<_RejectedJumpItemPair>(JumpItems.Count); + + // Need to group the JumpItems based on their categories. + // The special "Tasks" category doesn't actually have a name and should be first so it's unconditionally added. + categories = new List>() { new List<_ShellObjectPair>() }; + + // This is not thread-safe. + // We're traversing the original list so we're vulnerable to another thread modifying it during the enumeration. + foreach (var jumpItem in JumpItems) + { + if (jumpItem == null) + { + // App added a null jump item? Just go through the normal failure mechanisms. + rejectedList.Add(new _RejectedJumpItemPair { JumpItem = jumpItem, Reason = JumpItemRejectionReason.InvalidItem }); + continue; + } + + object shellObject = null; + try + { + shellObject = GetShellObjectForJumpItem(jumpItem); + // If for some reason we couldn't create the item add it to the rejected list. + if (shellObject == null) + { + rejectedList.Add(new _RejectedJumpItemPair { Reason = JumpItemRejectionReason.InvalidItem, JumpItem = jumpItem }); + continue; + } + + // Don't add this item if it's in the list of items previously removed by the user. + if (ListContainsShellObject(removedList, shellObject)) + { + rejectedList.Add(new _RejectedJumpItemPair { Reason = JumpItemRejectionReason.RemovedByUser, JumpItem = jumpItem }); + continue; + } + + var shellMap = new _ShellObjectPair { JumpItem = jumpItem, ShellObject = shellObject }; + if (string.IsNullOrEmpty(jumpItem.CustomCategory)) + { + // No custom category, so add to the Tasks list. + categories[0].Add(shellMap); + } + else + { + // Find the appropriate category and add to that list. + // If it doesn't exist, add a new category for it. + bool categoryExists = false; + foreach (var list in categories) + { + // The first item in the category list can be used to check the name. + if (list.Count > 0 && list[0].JumpItem.CustomCategory == jumpItem.CustomCategory) + { + list.Add(shellMap); + categoryExists = true; + break; + } + } + if (!categoryExists) + { + categories.Add(new List<_ShellObjectPair>() { shellMap }); + } + } + + // Shell interface is now owned by the category list. + shellObject = null; + } + finally + { + Utility.SafeRelease(ref shellObject); + } + } + + // Jump List categories get added top-down, except for "Tasks" which is special and always at the bottom. + // We want the Recent/Frequent to always be at the top so they get added first. + // Logically the categories are added bottom-up, but their contents are top-down, + // so we reverse the order we add the categories to the destinationList. + // To preserve the item ordering AddCategory also adds items in reverse. + // We need to reverse the final list when everything is done. + categories.Reverse(); + + if (ShowFrequentCategory) + { + destinationList.AppendKnownCategory(KDC.FREQUENT); + } + + if (ShowRecentCategory) + { + destinationList.AppendKnownCategory(KDC.RECENT); + } + + // Now that all the JumpItems are grouped add them to the custom destinations list. + foreach (List<_ShellObjectPair> categoryList in categories) + { + if (categoryList.Count > 0) + { + string categoryHeader = categoryList[0].JumpItem.CustomCategory; + AddCategory(destinationList, categoryHeader, categoryList, successList, rejectedList); + } + } + + destinationList.CommitList(); + + // Swap the current list with what we were able to successfully place into the JumpList. + // Reverse it first to ensure that the items are in a repeatable order. + successList.Reverse(); + } + finally + { + // Deterministically release native resources. + + Utility.SafeRelease(ref destinationList); + + if (categories != null) + { + foreach (List<_ShellObjectPair> list in categories) + { + _ShellObjectPair.ReleaseShellObjects(list); + } + } + + // Note that this only clears the ShellObjects, not the JumpItems. + // We still need the JumpItems out of this list for the JumpItemsRemovedByUser event. + _ShellObjectPair.ReleaseShellObjects(removedList); + } + } + + private static bool ListContainsShellObject(List<_ShellObjectPair> removedList, object shellObject) + { + Debug.Assert(removedList != null); + Debug.Assert(shellObject != null); + + if (removedList.Count == 0) + { + return false; + } + + // Casts in .Net don't AddRef. Don't need to release these. + var shellItem = shellObject as IShellItem; + if (shellItem != null) + { + foreach (var shellMap in removedList) + { + var removedItem = shellMap.ShellObject as IShellItem; + if (removedItem != null) + { + if (0 == shellItem.Compare(removedItem, SICHINT.CANONICAL | SICHINT.TEST_FILESYSPATH_IF_NOT_EQUAL)) + { + return true; + } + } + } + return false; + } + + var shellLink = shellObject as IShellLinkW; + if (shellLink != null) + { + foreach (var shellMap in removedList) + { + var removedLink = shellMap.ShellObject as IShellLinkW; + if (removedLink != null) + { + // There's no intrinsic comparison function for ShellLinks. + // Talking to the Shell guys, the way they compare these is to catenate a string with + // a normalized version of the app path and the unmodified args. + // If the two strings ordinally compare, they're the same. + string removedLinkString = ShellLinkToString(removedLink); + string linkString = ShellLinkToString(shellLink); + + if (removedLinkString == linkString) + { + return true; + } + } + } + return false; + } + + // Unlikely. It's not a supported shell interface? + return false; + } + + /// + /// + /// + /// This returns a native COM object that should be deterministically released by the caller, when possible. + /// + private static object GetShellObjectForJumpItem(JumpItem jumpItem) + { + var jumpPath = jumpItem as JumpPath; + var jumpTask = jumpItem as JumpTask; + + // Either of these create functions could return null if the item is invalid but they shouldn't throw. + if (jumpPath != null) + { + return CreateItemFromJumpPath(jumpPath); + } + else if (jumpTask != null) + { + return CreateLinkFromJumpTask(jumpTask, true); + } + + // Unsupported type? + Debug.Assert(false); + return null; + } + + private static List<_ShellObjectPair> GenerateJumpItems(IObjectArray shellObjects) + { + Debug.Assert(shellObjects != null); + + var retList = new List<_ShellObjectPair>(); + + Guid unknownIid = new Guid(IID.Unknown); + uint count = shellObjects.GetCount(); + for (uint i = 0; i < count; ++i) + { + // This is potentially a heterogenous list, so get as an IUnknown and QI afterwards. + object unk = shellObjects.GetAt(i, ref unknownIid); + JumpItem item = null; + try + { + item = GetJumpItemForShellObject(unk); + } + catch (Exception e) + { + if (e is NullReferenceException || e is System.Runtime.InteropServices.SEHException) + { + throw; + } + // If we failed the conversion we still want to keep the shell interface for comparision. + // Just leave the JumpItem property as null. + } + retList.Add(new _ShellObjectPair { ShellObject = unk, JumpItem = item }); + } + + return retList; + } + + private static void AddCategory(ICustomDestinationList cdl, string category, List<_ShellObjectPair> jumpItems, List successList, List<_RejectedJumpItemPair> rejectionList) + { + AddCategory(cdl, category, jumpItems, successList, rejectionList, true); + } + + private static void AddCategory(ICustomDestinationList cdl, string category, List<_ShellObjectPair> jumpItems, List successList, List<_RejectedJumpItemPair> rejectionList, bool isHeterogenous) + { + Debug.Assert(jumpItems.Count != 0); + Debug.Assert(cdl != null); + + HRESULT hr; + var shellObjectCollection = (IObjectCollection)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid(CLSID.EnumerableObjectCollection))); + + foreach (var itemMap in jumpItems) + { + shellObjectCollection.AddObject(itemMap.ShellObject); + } + + if (string.IsNullOrEmpty(category)) + { + hr = cdl.AddUserTasks((IObjectArray)shellObjectCollection); + } + else + { + hr = cdl.AppendCategory(category, (IObjectArray)shellObjectCollection); + } + + if (hr.Succeeded) + { + // Woot! Add these items to the list. + // Do it in reverse order so Apply has the items in the correct order. + for (int i = jumpItems.Count; --i >= 0;) + { + successList.Add(jumpItems[i].JumpItem); + } + } + else + { + // If the list contained items that could not be added because this object isn't a handler + // then drop all ShellItems and retry without them. + if (isHeterogenous && hr == HRESULT.DESTS_E_NO_MATCHING_ASSOC_HANDLER) + { + Utility.SafeRelease(ref shellObjectCollection); + var linksOnlyList = new List<_ShellObjectPair>(); + foreach (var itemMap in jumpItems) + { + if (itemMap.JumpItem is JumpPath) + { + rejectionList.Add(new _RejectedJumpItemPair { JumpItem = itemMap.JumpItem, Reason = JumpItemRejectionReason.NoRegisteredHandler }); + } + else + { + linksOnlyList.Add(itemMap); + } + } + if (linksOnlyList.Count > 0) + { + // There's not a reason I know of that we should reject a list of only links... + Debug.Assert(jumpItems.Count != linksOnlyList.Count); + AddCategory(cdl, category, linksOnlyList, successList, rejectionList, false); + } + } + else + { + Debug.Assert(HRESULT.DESTS_E_NO_MATCHING_ASSOC_HANDLER != hr); + // If we failed for some other reason, just reject everything. + foreach (var item in jumpItems) + { + rejectionList.Add(new _RejectedJumpItemPair { JumpItem = item.JumpItem, Reason = JumpItemRejectionReason.InvalidItem }); + } + } + } + } + + private static readonly string _FullName; + + #region Converter methods + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + private static IShellLinkW CreateLinkFromJumpTask(JumpTask jumpTask, bool allowSeparators) + { + Debug.Assert(jumpTask != null); + + // Title is generally required. If it's missing we need to treat this like a separator. + // Everything else can still appear on separator elements, + // but separators can only exist in the Tasks category. + if (string.IsNullOrEmpty(jumpTask.Title)) + { + if (!allowSeparators || !string.IsNullOrEmpty(jumpTask.CustomCategory)) + { + // Just treat this situation as an InvalidItem. + return null; + } + } + + var link = (IShellLinkW)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid(CLSID.ShellLink))); + try + { + string appPath = _FullName; + if (!string.IsNullOrEmpty(jumpTask.ApplicationPath)) + { + appPath = jumpTask.ApplicationPath; + } + + link.SetPath(appPath); + + // This is optional. Don't set it if the app hasn't explicitly requested it. + if (!string.IsNullOrEmpty(jumpTask.WorkingDirectory)) + { + // Don't verify this. It's possible that the directory doesn't exist now, but it will later. + // Shell handles this fine when we try to set an improperly formatted path. + link.SetWorkingDirectory(jumpTask.WorkingDirectory); + } + + if (!string.IsNullOrEmpty(jumpTask.Arguments)) + { + link.SetArguments(jumpTask.Arguments); + } + + // -1 is a sentinel value indicating not to use the icon. + if (jumpTask.IconResourceIndex != -1) + { + string resourcePath = _FullName; + if (!string.IsNullOrEmpty(jumpTask.IconResourcePath)) + { + // Shell bug (Windows 7 595770): IShellLink doesn't correctly limit icon location path to MAX_PATH. + // It's really too bad we have to enforce this here. When the shortcut gets + // serialized it streams the full string. On deserialization it only retrieves + // MAX_PATH for this field leaving junk behind for subsequent gets, leading to data corruption. + // Because we don't want to allow the app to do create something that we know may + // be corrupt we have to enforce this ourselves. If Shell fixes this later then + // we need to remove this check to let them handle this as they see fit. + // If they fix it by supporting longer paths, then we're artificially constraining this value... + if (jumpTask.IconResourcePath.Length >= Win32Value.MAX_PATH) + { + // we could throw the exception here, but we're already globally catching everything. + return null; + } + resourcePath = jumpTask.IconResourcePath; + } + link.SetIconLocation(resourcePath, jumpTask.IconResourceIndex); + } + + if (!string.IsNullOrEmpty(jumpTask.Description)) + { + link.SetDescription(jumpTask.Description); + } + + IPropertyStore propStore = (IPropertyStore)link; + using (var pv = new PROPVARIANT()) + { + PKEY pkey = default(PKEY); + + if (!string.IsNullOrEmpty(jumpTask.Title)) + { + pv.SetValue(jumpTask.Title); + pkey = PKEY.Title; + } + else + { + pv.SetValue(true); + pkey = PKEY.AppUserModel_IsDestListSeparator; + } + + propStore.SetValue(ref pkey, pv); + } + + propStore.Commit(); + + IShellLinkW retLink = link; + link = null; + return retLink; + } + catch (Exception) + { + // IShellLinkW::Set* methods tend to return E_FAIL when trying to set invalid data. + // The create methods don't explicitly check for these kinds of errors. + + // If we aren't able to create the item for any reason just return null to indicate an invalid item. + return null; + } + finally + { + Utility.SafeRelease(ref link); + } + } + + private static IShellItem2 GetShellItemForPath(string path) + { + if (string.IsNullOrEmpty(path)) + { + // Internal function. Should have verified this before calling if we cared. + return null; + } + + Guid iidShellItem2 = new Guid(IID.ShellItem2); + object unk; + HRESULT hr = NativeMethods.SHCreateItemFromParsingName(path, null, ref iidShellItem2, out unk); + + // Silently absorb errors such as ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND. + // Let others pass through + if (hr == (HRESULT)Win32Error.ERROR_FILE_NOT_FOUND || hr == (HRESULT)Win32Error.ERROR_PATH_NOT_FOUND) + { + hr = HRESULT.S_OK; + unk = null; + } + + hr.ThrowIfFailed(); + + return (IShellItem2)unk; + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + private static IShellItem2 CreateItemFromJumpPath(JumpPath jumpPath) + { + Debug.Assert(jumpPath != null); + + try + { + // This will return null if the path doesn't exist. + return GetShellItemForPath(Path.GetFullPath(jumpPath.Path)); + } + catch (Exception) + { + // Don't propagate exceptions here. If we couldn't create the item, it's just invalid. + } + + return null; + } + + private static JumpItem GetJumpItemForShellObject(object shellObject) + { + var shellItem = shellObject as IShellItem2; + var shellLink = shellObject as IShellLinkW; + + if (shellItem != null) + { + JumpPath path = new JumpPath + { + Path = shellItem.GetDisplayName(SIGDN.DESKTOPABSOLUTEPARSING), + }; + return path; + } + + if (shellLink != null) + { + var pathBuilder = new StringBuilder((int)Win32Value.MAX_PATH); + shellLink.GetPath(pathBuilder, pathBuilder.Capacity, null, SLGP.RAWPATH); + var argsBuilder = new StringBuilder((int)Win32Value.INFOTIPSIZE); + shellLink.GetArguments(argsBuilder, argsBuilder.Capacity); + var descBuilder = new StringBuilder((int)Win32Value.INFOTIPSIZE); + shellLink.GetDescription(descBuilder, descBuilder.Capacity); + var iconBuilder = new StringBuilder((int)Win32Value.MAX_PATH); + int iconIndex; + shellLink.GetIconLocation(iconBuilder, iconBuilder.Capacity, out iconIndex); + var dirBuilder = new StringBuilder((int)Win32Value.MAX_PATH); + shellLink.GetWorkingDirectory(dirBuilder, dirBuilder.Capacity); + + JumpTask task = new JumpTask + { + // Set ApplicationPath and IconResources, even if they're from the current application. + // This means that equivalent JumpTasks won't necessarily compare property-for-property. + ApplicationPath = pathBuilder.ToString(), + Arguments = argsBuilder.ToString(), + Description = descBuilder.ToString(), + IconResourceIndex = iconIndex, + IconResourcePath = iconBuilder.ToString(), + WorkingDirectory = dirBuilder.ToString(), + }; + + using (PROPVARIANT pv = new PROPVARIANT()) + { + var propStore = (IPropertyStore)shellLink; + PKEY pkeyTitle = PKEY.Title; + + propStore.GetValue(ref pkeyTitle, pv); + + // PKEY_Title should be an LPWSTR if it's not empty. + task.Title = pv.GetValue() ?? ""; + } + + return task; + } + + // Unsupported type? + Debug.Assert(false); + return null; + } + + /// + /// Generate a unique string for the ShellLink that can be used for equality checks. + /// + private static string ShellLinkToString(IShellLinkW shellLink) + { + var pathBuilder = new StringBuilder((int)Win32Value.MAX_PATH); + shellLink.GetPath(pathBuilder, pathBuilder.Capacity, null, SLGP.RAWPATH); + + string title = null; + // Need to use the property store to get the title for the link. + using (PROPVARIANT pv = new PROPVARIANT()) + { + var propStore = (IPropertyStore)shellLink; + PKEY pkeyTitle = PKEY.Title; + + propStore.GetValue(ref pkeyTitle, pv); + + // PKEY_Title should be an LPWSTR if it's not empty. + title = pv.GetValue() ?? ""; + } + + var argsBuilder = new StringBuilder((int)Win32Value.INFOTIPSIZE); + shellLink.GetArguments(argsBuilder, argsBuilder.Capacity); + + // Path and title should be case insensitive. + // Shell treats arguments as case sensitive because apps can handle those differently. + return pathBuilder.ToString().ToUpperInvariant() + title.ToUpperInvariant() + argsBuilder.ToString(); + } + + #endregion + + private void RejectEverything() + { + EventHandler handler = JumpItemsRejected; + if (handler == null) + { + _jumpItems.Clear(); + return; + } + + if (_jumpItems.Count > 0) + { + var reasons = new List(JumpItems.Count); + for (int i = 0; i < JumpItems.Count; ++i) + { + reasons.Add(JumpItemRejectionReason.InvalidItem); + } + // We're rejecting everything, + // so create an event args with the original list and then clear it. + var args = new JumpItemsRejectedEventArgs(JumpItems, reasons); + _jumpItems.Clear(); + + handler(this, args); + } + } + + public event EventHandler JumpItemsRejected; + + public event EventHandler JumpItemsRemovedByUser; + } +} diff --git a/Microsoft.Windows.Shell/JumpPath.cs b/Microsoft.Windows.Shell/JumpPath.cs new file mode 100644 index 0000000..2a49461 --- /dev/null +++ b/Microsoft.Windows.Shell/JumpPath.cs @@ -0,0 +1,14 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Microsoft.Windows.Shell +{ + public class JumpPath : JumpItem + { + public JumpPath() + {} + + public string Path { get; set; } + } +} diff --git a/Microsoft.Windows.Shell/JumpTask.cs b/Microsoft.Windows.Shell/JumpTask.cs new file mode 100644 index 0000000..38c8e6f --- /dev/null +++ b/Microsoft.Windows.Shell/JumpTask.cs @@ -0,0 +1,26 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Microsoft.Windows.Shell +{ + public class JumpTask : JumpItem + { + public JumpTask() + {} + + public string Title { get; set; } + + public string Description { get; set; } + + public string ApplicationPath { get; set; } + + public string Arguments { get; set; } + + public string WorkingDirectory { get; set; } + + public string IconResourcePath { get; set; } + + public int IconResourceIndex { get; set; } + } +} diff --git a/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj b/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj new file mode 100644 index 0000000..dc2cde5 --- /dev/null +++ b/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj @@ -0,0 +1,165 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB} + Library + Properties + Microsoft.Windows.Shell + Microsoft.Windows.Shell + v4.0 + 512 + + + + + + + + + false + + + true + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + + + AllRules.ruleset + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + AllRules.ruleset + false + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + false + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + false + + + + 3.0 + + + 3.0 + + + + + 3.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/Microsoft.Windows.Shell/Properties/AssemblyInfo.cs b/Microsoft.Windows.Shell/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..096773e --- /dev/null +++ b/Microsoft.Windows.Shell/Properties/AssemblyInfo.cs @@ -0,0 +1,31 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows.Markup; + +[assembly: AssemblyTitle("Microsoft.Windows.Shell")] +[assembly: AssemblyDescription("Windows 7 shell integration library for WPF")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("Microsoft.Windows.Shell")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] +[assembly: Guid("573618e1-4f3f-4395-a3bf-ffebfb342917")] +[assembly: CLSCompliant(true)] + +[assembly: AssemblyVersion("3.0.1.0")] +[assembly: AssemblyFileVersion("3.0.1.0")] + +[assembly: XmlnsDefinition("http://schemas.microsoft.com/winfx/2006/xaml/presentation/shell", "Microsoft.Windows.Shell")] + +// Code analysis suppressions: +[assembly: SuppressMessage("Microsoft.Design", "CA1020:AvoidNamespacesWithFewTypes", Scope = "namespace", Target = "Standard", Justification="Internal-only namespace")] +[assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames", Justification="Assembly has strong name when published")] diff --git a/Microsoft.Windows.Shell/Standard/ComGuids.cs b/Microsoft.Windows.Shell/Standard/ComGuids.cs new file mode 100644 index 0000000..7a3b522 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/ComGuids.cs @@ -0,0 +1,95 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Standard +{ + internal static partial class IID + { + /// IID_IEnumIDList + public const string EnumIdList = "000214F2-0000-0000-C000-000000000046"; + /// IID_IEnumObjects + public const string EnumObjects = "2c1c7e2e-2d0e-4059-831e-1e6f82335c2e"; + /// IID_IHTMLDocument2 + public const string HtmlDocument2 = "332C4425-26CB-11D0-B483-00C04FD90119"; + /// IID_IModalWindow + public const string ModalWindow = "b4db1657-70d7-485e-8e3e-6fcb5a5c1802"; + /// IID_IObjectArray + public const string ObjectArray = "92CA9DCD-5622-4bba-A805-5E9F541BD8C9"; + /// IID_IObjectCollection + public const string ObjectCollection = "5632b1a4-e38a-400a-928a-d4cd63230295"; + /// IID_IPropertyNotifySink + public const string PropertyNotifySink = "9BFBBC02-EFF1-101A-84ED-00AA00341D07"; + /// IID_IPropertyStore + public const string PropertyStore = "886d8eeb-8cf2-4446-8d02-cdba1dbdcf99"; + /// IID_IServiceProvider + public const string ServiceProvider = "6d5140c1-7436-11ce-8034-00aa006009fa"; + /// IID_IShellFolder + public const string ShellFolder = "000214E6-0000-0000-C000-000000000046"; + /// IID_IShellLink + public const string ShellLink = "000214F9-0000-0000-C000-000000000046"; + /// IID_IShellItem + public const string ShellItem = "43826d1e-e718-42ee-bc55-a1e261c37bfe"; + /// IID_IShellItem2 + public const string ShellItem2 = "7e9fb0d3-919f-4307-ab2e-9b1860310c93"; + /// IID_IShellItemArray + public const string ShellItemArray = "B63EA76D-1F85-456F-A19C-48159EFA858B"; + /// IID_ITaskbarList + public const string TaskbarList = "56FDF342-FD6D-11d0-958A-006097C9A090"; + /// IID_ITaskbarList2 + public const string TaskbarList2 = "602D4995-B13A-429b-A66E-1935E44F4317"; + /// IID_IUnknown + public const string Unknown = "00000000-0000-0000-C000-000000000046"; + + #region Win7 IIDs + + /// IID_IApplicationDestinations + public const string ApplicationDestinations = "12337d35-94c6-48a0-bce7-6a9c69d4d600"; + /// IID_IApplicationDocumentLists + public const string ApplicationDocumentLists = "3c594f9f-9f30-47a1-979a-c9e83d3d0a06"; + /// IID_ICustomDestinationList + public const string CustomDestinationList = "6332debf-87b5-4670-90c0-5e57b408a49e"; + /// IID_IObjectWithAppUserModelID + public const string ObjectWithAppUserModelId = "36db0196-9665-46d1-9ba7-d3709eecf9ed"; + /// IID_IObjectWithProgID + public const string ObjectWithProgId = "71e806fb-8dee-46fc-bf8c-7748a8a1ae13"; + /// IID_ITaskbarList3 + public const string TaskbarList3 = "ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf"; + /// IID_ITaskbarList4 + public const string TaskbarList4 = "c43dc798-95d1-4bea-9030-bb99e2983a1a"; + + #endregion + } + + internal static partial class CLSID + { + public static T CoCreateInstance(string clsid) + { + return (T)System.Activator.CreateInstance(System.Type.GetTypeFromCLSID(new System.Guid(clsid))); + } + + /// CLSID_TaskbarList + /// IID_ITaskbarList + public const string TaskbarList = "56FDF344-FD6D-11d0-958A-006097C9A090"; + /// CLSID_EnumerableObjectCollection + /// IID_IEnumObjects. + public const string EnumerableObjectCollection = "2d3468c1-36a7-43b6-ac24-d3f02fd9607a"; + /// CLSID_ShellLink + /// IID_IShellLink + public const string ShellLink = "00021401-0000-0000-C000-000000000046"; + + #region Win7 CLSIDs + + /// CLSID_DestinationList + /// IID_ICustomDestinationList + public const string DestinationList = "77f10cf0-3db5-4966-b520-b7c54fd35ed6"; + /// CLSID_ApplicationDestinations + /// IID_IApplicationDestinations + public const string ApplicationDestinations = "86c14003-4d6b-4ef3-a7b4-0506663b2e68"; + /// CLSID_ApplicationDocumentLists + /// IID_IApplicationDocumentLists + public const string ApplicationDocumentLists = "86bec222-30f2-47e0-9f25-60d11cd75c28"; + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/Standard/Debug.cs b/Microsoft.Windows.Shell/Standard/Debug.cs new file mode 100644 index 0000000..97d86f0 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/Debug.cs @@ -0,0 +1,373 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +// Conditional to use more aggressive fail-fast behaviors when debugging. +#define DEV_DEBUG + +// This file contains general utilities to aid in development. +// It is distinct from unit test Assert classes. +// Classes here generally shouldn't be exposed publicly since +// they're not particular to any library functionality. +// Because the classes here are internal, it's likely this file +// might be included in multiple assemblies. +namespace Standard +{ + using System; + using System.Diagnostics; + using System.Threading; + + /// A static class for verifying assumptions. + internal static class Assert + { + private static void _Break() + { +#if DEV_DEBUG + Debugger.Break(); +#else + Debug.Assert(false); +#endif + } + + /// A function signature for Assert.Evaluate. + public delegate void EvaluateFunction(); + + /// A function signature for Assert.Implies. + /// Returns the truth of a predicate. + public delegate bool ImplicationFunction(); + + /// + /// Executes the specified argument. + /// + /// The function to execute. + [Conditional("DEBUG")] + public static void Evaluate(EvaluateFunction argument) + { + IsNotNull(argument); + argument(); + } + + /// Obsolete: Use Standard.Assert.AreEqual instead of Assert.Equals + /// The generic type to compare for equality. + /// The first generic type data to compare. This is is the expected value. + /// The second generic type data to compare. This is the actual value. + [ + Obsolete("Use Assert.AreEqual instead of Assert.Equals", false), + Conditional("DEBUG") + ] + public static void Equals(T expected, T actual) + { + AreEqual(expected, actual); + } + + /// + /// Verifies that two generic type data are equal. The assertion fails if they are not. + /// + /// The generic type to compare for equality. + /// The first generic type data to compare. This is is the expected value. + /// The second generic type data to compare. This is the actual value. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void AreEqual(T expected, T actual) + { + if (null == expected) + { + // Two nulls are considered equal, regardless of type semantics. + if (null != actual && !actual.Equals(expected)) + { + _Break(); + } + } + else if (!expected.Equals(actual)) + { + _Break(); + } + } + + /// + /// Verifies that two generic type data are not equal. The assertion fails if they are. + /// + /// The generic type to compare for inequality. + /// The first generic type data to compare. This is is the value that's not expected. + /// The second generic type data to compare. This is the actual value. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void AreNotEqual(T notExpected, T actual) + { + if (null == notExpected) + { + // Two nulls are considered equal, regardless of type semantics. + if (null == actual || actual.Equals(notExpected)) + { + _Break(); + } + } + else if (notExpected.Equals(actual)) + { + _Break(); + } + } + + /// + /// Verifies that if the specified condition is true, then so is the result. + /// The assertion fails if the condition is true but the result is false. + /// + /// if set to true [condition]. + /// + /// A second Boolean statement. If the first was true then so must this be. + /// If the first statement was false then the value of this is ignored. + /// + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void Implies(bool condition, bool result) + { + if (condition && !result) + { + _Break(); + } + } + + /// + /// Lazy evaluation overload. Verifies that if a condition is true, then so is a secondary value. + /// + /// The conditional value. + /// A function to be evaluated for truth if the condition argument is true. + /// + /// This overload only evaluates the result if the first condition is true. + /// + [Conditional("DEBUG")] + public static void Implies(bool condition, ImplicationFunction result) + { + if (condition && !result()) + { + _Break(); + } + } + + /// + /// Verifies that a string has content. I.e. it is not null and it is not empty. + /// + /// The string to verify. + [Conditional("DEBUG")] + public static void IsNeitherNullNorEmpty(string value) + { + IsFalse(string.IsNullOrEmpty(value)); + } + + /// + /// Verifies that a string has content. I.e. it is not null and it is not purely whitespace. + /// + /// The string to verify. + [Conditional("DEBUG")] + public static void IsNeitherNullNorWhitespace(string value) + { + if (string.IsNullOrEmpty(value)) + { + _Break(); + } + + if (value.Trim().Length == 0) + { + _Break(); + } + } + + /// + /// Verifies the specified value is not null. The assertion fails if it is. + /// + /// The generic reference type. + /// The value to check for nullness. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsNotNull(T value) where T : class + { + if (null == value) + { + _Break(); + } + } + + [Conditional("DEBUG")] + public static void IsDefault(T value) where T : struct + { + if (!value.Equals(default(T))) + { + Assert.Fail(); + } + } + + [Conditional("DEBUG")] + public static void IsNotDefault(T value) where T : struct + { + if (value.Equals(default(T))) + { + Assert.Fail(); + } + } + + /// + /// Verifies that the specified condition is false. The assertion fails if it is true. + /// + /// The expression that should be false. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsFalse(bool condition) + { + if (condition) + { + _Break(); + } + } + + /// + /// Verifies that the specified condition is false. The assertion fails if it is true. + /// + /// The expression that should be false. + /// The message to display if the condition is true. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsFalse(bool condition, string message) + { + if (condition) + { + _Break(); + } + } + + /// + /// Verifies that the specified condition is true. The assertion fails if it is not. + /// + /// A condition that is expected to be true. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsTrue(bool condition) + { + if (!condition) + { + _Break(); + } + } + + /// + /// Verifies that the specified condition is true. The assertion fails if it is not. + /// + /// A condition that is expected to be true. + /// The message to write in case the condition is false. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsTrue(bool condition, string message) + { + if (!condition) + { + _Break(); + } + } + + /// + /// This line should never be executed. The assertion always fails. + /// + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void Fail() + { + _Break(); + } + + /// + /// This line should never be executed. The assertion always fails. + /// + /// The message to display if this function is executed. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void Fail(string message) + { + _Break(); + } + + /// + /// Verifies that the specified object is null. The assertion fails if it is not. + /// + /// The item to verify is null. + [Conditional("DEBUG")] + public static void IsNull(T item) where T : class + { + if (null != item) + { + _Break(); + } + } + + /// + /// Verifies that the specified value is within the expected range. The assertion fails if it isn't. + /// + /// The lower bound inclusive value. + /// The value to verify. + /// The upper bound inclusive value. + [Conditional("DEBUG")] + public static void BoundedDoubleInc(double lowerBoundInclusive, double value, double upperBoundInclusive) + { + if (value < lowerBoundInclusive || value > upperBoundInclusive) + { + _Break(); + } + } + + /// + /// Verifies that the specified value is within the expected range. The assertion fails if it isn't. + /// + /// The lower bound inclusive value. + /// The value to verify. + /// The upper bound exclusive value. + [Conditional("DEBUG")] + public static void BoundedInteger(int lowerBoundInclusive, int value, int upperBoundExclusive) + { + if (value < lowerBoundInclusive || value >= upperBoundExclusive) + { + _Break(); + } + } + + /// + /// Verify the current thread's apartment state is what's expected. The assertion fails if it isn't + /// + /// + /// The expected apartment state for the current thread. + /// + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsApartmentState(ApartmentState expectedState) + { + if (Thread.CurrentThread.GetApartmentState() != expectedState) + { + _Break(); + } + } + + [Conditional("DEBUG")] + public static void NullableIsNotNull(T? value) where T : struct + { + if (null == value) + { + _Break(); + } + } + + [Conditional("DEBUG")] + public static void NullableIsNull(T? value) where T : struct + { + if (null != value) + { + _Break(); + } + } + + [Conditional("DEBUG")] + public static void IsNotOnMainThread() + { + if (System.Windows.Application.Current.Dispatcher.CheckAccess()) + { + _Break(); + } + } + } +} diff --git a/Microsoft.Windows.Shell/Standard/DoubleUtil.cs b/Microsoft.Windows.Shell/Standard/DoubleUtil.cs new file mode 100644 index 0000000..49d1c26 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/DoubleUtil.cs @@ -0,0 +1,132 @@ + +namespace Standard +{ + using System; + using System.Diagnostics.CodeAnalysis; + + /// + /// DoubleUtil uses fixed eps to provide fuzzy comparison functionality for doubles. + /// Note that FP noise is a big problem and using any of these compare + /// methods is not a complete solution, but rather the way to reduce + /// the probability of repeating unnecessary work. + /// + internal static class DoubleUtilities + { + /// + /// Epsilon - more or less random, more or less small number. + /// + private const double Epsilon = 0.00000153; + + /// + /// AreClose returns whether or not two doubles are "close". That is, whether or + /// not they are within epsilon of each other. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the AreClose comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool AreClose(double value1, double value2) + { + if (value1 == value2) + { + return true; + } + + double delta = value1 - value2; + return (delta < Epsilon) && (delta > -Epsilon); + } + + /// + /// LessThan returns whether or not the first double is less than the second double. + /// That is, whether or not the first is strictly less than *and* not within epsilon of + /// the other number. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the LessThan comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool LessThan(double value1, double value2) + { + return (value1 < value2) && !AreClose(value1, value2); + } + + /// + /// GreaterThan returns whether or not the first double is greater than the second double. + /// That is, whether or not the first is strictly greater than *and* not within epsilon of + /// the other number. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the GreaterThan comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool GreaterThan(double value1, double value2) + { + return (value1 > value2) && !AreClose(value1, value2); + } + + /// + /// LessThanOrClose returns whether or not the first double is less than or close to + /// the second double. That is, whether or not the first is strictly less than or within + /// epsilon of the other number. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the LessThanOrClose comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool LessThanOrClose(double value1, double value2) + { + return (value1 < value2) || AreClose(value1, value2); + } + + /// + /// GreaterThanOrClose returns whether or not the first double is greater than or close to + /// the second double. That is, whether or not the first is strictly greater than or within + /// epsilon of the other number. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the GreaterThanOrClose comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool GreaterThanOrClose(double value1, double value2) + { + return (value1 > value2) || AreClose(value1, value2); + } + + /// + /// Test to see if a double is a finite number (is not NaN or Infinity). + /// + /// The value to test. + /// Whether or not the value is a finite number. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFinite(double value) + { + return !double.IsNaN(value) && !double.IsInfinity(value); + } + + /// + /// Test to see if a double a valid size value (is finite and > 0). + /// + /// The value to test. + /// Whether or not the value is a valid size value. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsValidSize(double value) + { + return IsFinite(value) && GreaterThanOrClose(value, 0); + } + } +} diff --git a/Microsoft.Windows.Shell/Standard/DpiHelper.cs b/Microsoft.Windows.Shell/Standard/DpiHelper.cs new file mode 100644 index 0000000..693bd6f --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/DpiHelper.cs @@ -0,0 +1,86 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Standard +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Windows; + using System.Windows.Media; + + internal static class DpiHelper + { + private static Matrix _transformToDevice; + private static Matrix _transformToDip; + + [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] + static DpiHelper() + { + using (SafeDC desktop = SafeDC.GetDesktop()) + { + // Can get these in the static constructor. They shouldn't vary window to window, + // and changing the system DPI requires a restart. + int pixelsPerInchX = NativeMethods.GetDeviceCaps(desktop, DeviceCap.LOGPIXELSX); + int pixelsPerInchY = NativeMethods.GetDeviceCaps(desktop, DeviceCap.LOGPIXELSY); + + _transformToDip = Matrix.Identity; + _transformToDip.Scale(96d / (double)pixelsPerInchX, 96d / (double)pixelsPerInchY); + _transformToDevice = Matrix.Identity; + _transformToDevice.Scale((double)pixelsPerInchX / 96d, (double)pixelsPerInchY / 96d); + } + } + + /// + /// Convert a point in device independent pixels (1/96") to a point in the system coordinates. + /// + /// A point in the logical coordinate system. + /// Returns the parameter converted to the system's coordinates. + public static Point LogicalPixelsToDevice(Point logicalPoint) + { + return _transformToDevice.Transform(logicalPoint); + } + + /// + /// Convert a point in system coordinates to a point in device independent pixels (1/96"). + /// + /// A point in the physical coordinate system. + /// Returns the parameter converted to the device independent coordinate system. + public static Point DevicePixelsToLogical(Point devicePoint) + { + return _transformToDip.Transform(devicePoint); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Rect LogicalRectToDevice(Rect logicalRectangle) + { + Point topLeft = LogicalPixelsToDevice(new Point(logicalRectangle.Left, logicalRectangle.Top)); + Point bottomRight = LogicalPixelsToDevice(new Point(logicalRectangle.Right, logicalRectangle.Bottom)); + + return new Rect(topLeft, bottomRight); + } + + public static Rect DeviceRectToLogical(Rect deviceRectangle) + { + Point topLeft = DevicePixelsToLogical(new Point(deviceRectangle.Left, deviceRectangle.Top)); + Point bottomRight = DevicePixelsToLogical(new Point(deviceRectangle.Right, deviceRectangle.Bottom)); + + return new Rect(topLeft, bottomRight); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Size LogicalSizeToDevice(Size logicalSize) + { + Point pt = LogicalPixelsToDevice(new Point(logicalSize.Width, logicalSize.Height)); + + return new Size { Width = pt.X, Height = pt.Y }; + } + + public static Size DeviceSizeToLogical(Size deviceSize) + { + Point pt = DevicePixelsToLogical(new Point(deviceSize.Width, deviceSize.Height)); + + return new Size(pt.X, pt.Y); + } + } +} diff --git a/Microsoft.Windows.Shell/Standard/ErrorCodes.cs b/Microsoft.Windows.Shell/Standard/ErrorCodes.cs new file mode 100644 index 0000000..5adb444 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/ErrorCodes.cs @@ -0,0 +1,508 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Standard +{ + using System; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.Reflection; + using System.Runtime.InteropServices; + + /// + /// Wrapper for common Win32 status codes. + /// + [StructLayout(LayoutKind.Explicit)] + internal struct Win32Error + { + [FieldOffset(0)] + private readonly int _value; + + // NOTE: These public static field declarations are automatically + // picked up by (HRESULT's) ToString through reflection. + + /// The operation completed successfully. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_SUCCESS = new Win32Error(0); + /// Incorrect function. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INVALID_FUNCTION = new Win32Error(1); + /// The system cannot find the file specified. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_FILE_NOT_FOUND = new Win32Error(2); + /// The system cannot find the path specified. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_PATH_NOT_FOUND = new Win32Error(3); + /// The system cannot open the file. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_TOO_MANY_OPEN_FILES = new Win32Error(4); + /// Access is denied. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_ACCESS_DENIED = new Win32Error(5); + /// The handle is invalid. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INVALID_HANDLE = new Win32Error(6); + /// Not enough storage is available to complete this operation. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_OUTOFMEMORY = new Win32Error(14); + /// There are no more files. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_NO_MORE_FILES = new Win32Error(18); + /// The process cannot access the file because it is being used by another process. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_SHARING_VIOLATION = new Win32Error(32); + /// The parameter is incorrect. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INVALID_PARAMETER = new Win32Error(87); + /// The data area passed to a system call is too small. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INSUFFICIENT_BUFFER = new Win32Error(122); + /// Cannot nest calls to LoadModule. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_NESTING_NOT_ALLOWED = new Win32Error(215); + /// Illegal operation attempted on a registry key that has been marked for deletion. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_KEY_DELETED = new Win32Error(1018); + /// Element not found. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_NOT_FOUND = new Win32Error(1168); + /// There was no match for the specified key in the index. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_NO_MATCH = new Win32Error(1169); + /// An invalid device was specified. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_BAD_DEVICE = new Win32Error(1200); + /// The operation was canceled by the user. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_CANCELLED = new Win32Error(1223); + /// The window class was already registered. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_CLASS_ALREADY_EXISTS = new Win32Error(1410); + /// The specified datatype is invalid. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INVALID_DATATYPE = new Win32Error(1804); + + /// + /// Create a new Win32 error. + /// + /// The integer value of the error. + public Win32Error(int i) + { + _value = i; + } + + /// Performs HRESULT_FROM_WIN32 conversion. + /// The Win32 error being converted to an HRESULT. + /// The equivilent HRESULT value. + public static explicit operator HRESULT(Win32Error error) + { + // #define __HRESULT_FROM_WIN32(x) + // ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000))) + if (error._value <= 0) + { + return new HRESULT((uint)error._value); + } + return HRESULT.Make(true, Facility.Win32, error._value & 0x0000FFFF); + } + + // Method version of the cast operation + /// Performs HRESULT_FROM_WIN32 conversion. + /// The Win32 error being converted to an HRESULT. + /// The equivilent HRESULT value. + public HRESULT ToHRESULT() + { + return (HRESULT)this; + } + + /// Performs the equivalent of Win32's GetLastError() + /// A Win32Error instance with the result of the native GetLastError + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static Win32Error GetLastError() + { + return new Win32Error(Marshal.GetLastWin32Error()); + } + + public override bool Equals(object obj) + { + try + { + return ((Win32Error)obj)._value == _value; + } + catch (InvalidCastException) + { + return false; + } + } + + public override int GetHashCode() + { + return _value.GetHashCode(); + } + + /// + /// Compare two Win32 error codes for equality. + /// + /// The first error code to compare. + /// The second error code to compare. + /// Whether the two error codes are the same. + public static bool operator ==(Win32Error errLeft, Win32Error errRight) + { + return errLeft._value == errRight._value; + } + + /// + /// Compare two Win32 error codes for inequality. + /// + /// The first error code to compare. + /// The second error code to compare. + /// Whether the two error codes are not the same. + public static bool operator !=(Win32Error errLeft, Win32Error errRight) + { + return !(errLeft == errRight); + } + } + + internal enum Facility + { + /// FACILITY_NULL + Null = 0, + /// FACILITY_RPC + Rpc = 1, + /// FACILITY_DISPATCH + Dispatch = 2, + /// FACILITY_STORAGE + Storage = 3, + /// FACILITY_ITF + Itf = 4, + /// FACILITY_WIN32 + Win32 = 7, + /// FACILITY_WINDOWS + Windows = 8, + /// FACILITY_CONTROL + Control = 10, + /// MSDN doced facility code for ESE errors. + Ese = 0xE5E, + /// FACILITY_WINCODEC (WIC) + WinCodec = 0x898, + } + + /// Wrapper for HRESULT status codes. + [StructLayout(LayoutKind.Explicit)] + internal struct HRESULT + { + [FieldOffset(0)] + private readonly uint _value; + + // NOTE: These public static field declarations are automatically + // picked up by ToString through reflection. + /// S_OK + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT S_OK = new HRESULT(0x00000000); + /// S_FALSE + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT S_FALSE = new HRESULT(0x00000001); + /// E_PENDING + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_PENDING = new HRESULT(0x8000000A); + /// E_NOTIMPL + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_NOTIMPL = new HRESULT(0x80004001); + /// E_NOINTERFACE + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_NOINTERFACE = new HRESULT(0x80004002); + /// E_POINTER + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_POINTER = new HRESULT(0x80004003); + /// E_ABORT + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_ABORT = new HRESULT(0x80004004); + /// E_FAIL + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_FAIL = new HRESULT(0x80004005); + /// E_UNEXPECTED + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_UNEXPECTED = new HRESULT(0x8000FFFF); + /// STG_E_INVALIDFUNCTION + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT STG_E_INVALIDFUNCTION = new HRESULT(0x80030001); + /// REGDB_E_CLASSNOTREG + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT REGDB_E_CLASSNOTREG = new HRESULT(0x80040154); + + /// DESTS_E_NO_MATCHING_ASSOC_HANDLER. Win7 internal error code for Jump Lists. + /// There is no Assoc Handler for the given item registered by the specified application. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DESTS_E_NO_MATCHING_ASSOC_HANDLER = new HRESULT(0x80040F03); + /// DESTS_E_NORECDOCS. Win7 internal error code for Jump Lists. + /// The given item is excluded from the recent docs folder by the NoRecDocs bit on its registration. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DESTS_E_NORECDOCS = new HRESULT(0x80040F04); + /// DESTS_E_NOTALLCLEARED. Win7 internal error code for Jump Lists. + /// Not all of the items were successfully cleared + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DESTS_E_NOTALLCLEARED = new HRESULT(0x80040F05); + + /// E_ACCESSDENIED + /// Win32Error ERROR_ACCESS_DENIED. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_ACCESSDENIED = new HRESULT(0x80070005); + /// E_OUTOFMEMORY + /// Win32Error ERROR_OUTOFMEMORY. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_OUTOFMEMORY = new HRESULT(0x8007000E); + /// E_INVALIDARG + /// Win32Error ERROR_INVALID_PARAMETER. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_INVALIDARG = new HRESULT(0x80070057); + /// INTSAFE_E_ARITHMETIC_OVERFLOW + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT INTSAFE_E_ARITHMETIC_OVERFLOW = new HRESULT(0x80070216); + /// COR_E_OBJECTDISPOSED + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT COR_E_OBJECTDISPOSED = new HRESULT(0x80131622); + /// WC_E_GREATERTHAN + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WC_E_GREATERTHAN = new HRESULT(0xC00CEE23); + /// WC_E_SYNTAX + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WC_E_SYNTAX = new HRESULT(0xC00CEE2D); + + /// + /// Create an HRESULT from an integer value. + /// + /// + public HRESULT(uint i) + { + _value = i; + } + + public static HRESULT Make(bool severe, Facility facility, int code) + { + //#define MAKE_HRESULT(sev,fac,code) \ + // ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) + + // Severity has 1 bit reserved. + // bitness is enforced by the boolean parameter. + + // Facility has 11 bits reserved (different than SCODES, which have 4 bits reserved) + // MSDN documentation incorrectly uses 12 bits for the ESE facility (e5e), so go ahead and let that one slide. + // And WIC also ignores it the documented size... + Assert.Implies((int)facility != (int)((int)facility & 0x1FF), facility == Facility.Ese || facility == Facility.WinCodec); + // Code has 4 bits reserved. + Assert.AreEqual(code, code & 0xFFFF); + + return new HRESULT((uint)((severe ? (1 << 31) : 0) | ((int)facility << 16) | code)); + } + + /// + /// retrieve HRESULT_FACILITY + /// + public Facility Facility + { + get + { + return GetFacility((int)_value); + } + } + + public static Facility GetFacility(int errorCode) + { + // #define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) + return (Facility)((errorCode >> 16) & 0x1fff); + } + + /// + /// retrieve HRESULT_CODE + /// + public int Code + { + get + { + return GetCode((int)_value); + } + } + + public static int GetCode(int error) + { + // #define HRESULT_CODE(hr) ((hr) & 0xFFFF) + return (int)(error & 0xFFFF); + } + + #region Object class override members + + /// + /// Get a string representation of this HRESULT. + /// + /// + public override string ToString() + { + // Use reflection to try to name this HRESULT. + // This is expensive, but if someone's ever printing HRESULT strings then + // I think it's a fair guess that they're not in a performance critical area + // (e.g. printing exception strings). + // This is less error prone than trying to keep the list in the function. + // To properly add an HRESULT's name to the ToString table, just add the HRESULT + // like all the others above. + // + // CONSIDER: This data is static. It could be cached + // after first usage for fast lookup since the keys are unique. + // + foreach (FieldInfo publicStaticField in typeof(HRESULT).GetFields(BindingFlags.Static | BindingFlags.Public)) + { + if (publicStaticField.FieldType == typeof(HRESULT)) + { + var hr = (HRESULT)publicStaticField.GetValue(null); + if (hr == this) + { + return publicStaticField.Name; + } + } + } + + // Try Win32 error codes also + if (Facility == Facility.Win32) + { + foreach (FieldInfo publicStaticField in typeof(Win32Error).GetFields(BindingFlags.Static | BindingFlags.Public)) + { + if (publicStaticField.FieldType == typeof(Win32Error)) + { + var error = (Win32Error)publicStaticField.GetValue(null); + if ((HRESULT)error == this) + { + return "HRESULT_FROM_WIN32(" + publicStaticField.Name + ")"; + } + } + } + } + + // If there's no good name for this HRESULT, + // return the string as readable hex (0x########) format. + return string.Format(CultureInfo.InvariantCulture, "0x{0:X8}", _value); + } + + public override bool Equals(object obj) + { + try + { + return ((HRESULT)obj)._value == _value; + } + catch (InvalidCastException) + { + return false; + } + } + + public override int GetHashCode() + { + return _value.GetHashCode(); + } + + #endregion + + public static bool operator ==(HRESULT hrLeft, HRESULT hrRight) + { + return hrLeft._value == hrRight._value; + } + + public static bool operator !=(HRESULT hrLeft, HRESULT hrRight) + { + return !(hrLeft == hrRight); + } + + public bool Succeeded + { + get { return (int)_value >= 0; } + } + + public bool Failed + { + get { return (int)_value < 0; } + } + + public void ThrowIfFailed() + { + ThrowIfFailed(null); + } + + [ + SuppressMessage( + "Microsoft.Usage", + "CA2201:DoNotRaiseReservedExceptionTypes", + Justification="Only recreating Exceptions that were already raised."), + SuppressMessage( + "Microsoft.Security", + "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands") + ] + public void ThrowIfFailed(string message) + { + if (Failed) + { + if (string.IsNullOrEmpty(message)) + { + message = ToString(); + } +#if DEBUG + else + { + message += " (" + ToString() + ")"; + } +#endif + // Wow. Reflection in a throw call. Later on this may turn out to have been a bad idea. + // If you're throwing an exception I assume it's OK for me to take some time to give it back. + // I want to convert the HRESULT to a more appropriate exception type than COMException. + // Marshal.ThrowExceptionForHR does this for me, but the general call uses GetErrorInfo + // if it's set, and then ignores the HRESULT that I've provided. This makes it so this + // call works the first time but you get burned on the second. To avoid this, I use + // the overload that explicitly ignores the IErrorInfo. + // In addition, the function doesn't allow me to set the Message unless I go through + // the process of implementing an IErrorInfo and then use that. There's no stock + // implementations of IErrorInfo available and I don't think it's worth the maintenance + // overhead of doing it, nor would it have significant value over this approach. + Exception e = Marshal.GetExceptionForHR((int)_value, new IntPtr(-1)); + Assert.IsNotNull(e); + // ArgumentNullException doesn't have the right constructor parameters, + // (nor does Win32Exception...) + // but E_POINTER gets mapped to NullReferenceException, + // so I don't think it will ever matter. + Assert.IsFalse(e is ArgumentNullException); + + // If we're not getting anything better than a COMException from Marshal, + // then at least check the facility and attempt to do better ourselves. + if (e.GetType() == typeof(COMException)) + { + switch (Facility) + { + case Facility.Win32: + e = new Win32Exception(Code, message); + break; + default: + e = new COMException(message, (int)_value); + break; + } + } + else + { + ConstructorInfo cons = e.GetType().GetConstructor(new[] { typeof(string) }); + if (null != cons) + { + e = cons.Invoke(new object[] { message }) as Exception; + Assert.IsNotNull(e); + } + } + throw e; + } + } + + /// + /// Convert the result of Win32 GetLastError() into a raised exception. + /// + public static void ThrowLastError() + { + ((HRESULT)Win32Error.GetLastError()).ThrowIfFailed(); + // Only expecting to call this when we're expecting a failed GetLastError() + Assert.Fail(); + } + } +} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/Standard/MessageWindow.cs b/Microsoft.Windows.Shell/Standard/MessageWindow.cs new file mode 100644 index 0000000..a0eac02 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/MessageWindow.cs @@ -0,0 +1,169 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Standard +{ + using System; + using System.Runtime.InteropServices; + using System.Windows; + using System.Windows.Threading; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + + internal sealed class MessageWindow : DispatcherObject, IDisposable + { + // Alias this to a static so the wrapper doesn't get GC'd + private static readonly WndProc s_WndProc = new WndProc(_WndProc); + private static readonly Dictionary s_windowLookup = new Dictionary(); + + private WndProc _wndProcCallback; + private string _className; + private bool _isDisposed; + + public IntPtr Handle { get; private set; } + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public MessageWindow(CS classStyle, WS style, WS_EX exStyle, Rect location, string name, WndProc callback) + { + // A null callback means just use DefWindowProc. + _wndProcCallback = callback; + _className = "MessageWindowClass+" + Guid.NewGuid().ToString(); + + var wc = new WNDCLASSEX + { + cbSize = Marshal.SizeOf(typeof(WNDCLASSEX)), + style = classStyle, + lpfnWndProc = s_WndProc, + hInstance = NativeMethods.GetModuleHandle(null), + hbrBackground = NativeMethods.GetStockObject(StockObject.NULL_BRUSH), + lpszMenuName = "", + lpszClassName = _className, + }; + + NativeMethods.RegisterClassEx(ref wc); + + GCHandle gcHandle = default(GCHandle); + try + { + gcHandle = GCHandle.Alloc(this); + IntPtr pinnedThisPtr = (IntPtr)gcHandle; + + Handle = NativeMethods.CreateWindowEx( + exStyle, + _className, + name, + style, + (int)location.X, + (int)location.Y, + (int)location.Width, + (int)location.Height, + IntPtr.Zero, + IntPtr.Zero, + IntPtr.Zero, + pinnedThisPtr); + } + finally + { + gcHandle.Free(); + } + } + + ~MessageWindow() + { + _Dispose(false, false); + } + + public void Dispose() + { + _Dispose(true, false); + GC.SuppressFinalize(this); + } + + // This isn't right if the Dispatcher has already started shutting down. + // It will wind up leaking the class ATOM... + [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disposing")] + private void _Dispose(bool disposing, bool isHwndBeingDestroyed) + { + if (_isDisposed) + { + // Block against reentrancy. + return; + } + + _isDisposed = true; + + IntPtr hwnd = Handle; + string className = _className; + + if (isHwndBeingDestroyed) + { + Dispatcher.BeginInvoke(DispatcherPriority.Normal, (DispatcherOperationCallback)(arg => _DestroyWindow(IntPtr.Zero, className))); + } + else if (Handle != IntPtr.Zero) + { + if (CheckAccess()) + { + _DestroyWindow(hwnd, className); + } + else + { + Dispatcher.BeginInvoke(DispatcherPriority.Normal, (DispatcherOperationCallback)(arg => _DestroyWindow(hwnd, className))); + } + } + + s_windowLookup.Remove(hwnd); + + _className = null; + Handle = IntPtr.Zero; + } + + [SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly")] + private static IntPtr _WndProc(IntPtr hwnd, WM msg, IntPtr wParam, IntPtr lParam) + { + IntPtr ret = IntPtr.Zero; + MessageWindow hwndWrapper = null; + + if (msg == WM.CREATE) + { + var createStruct = (CREATESTRUCT)Marshal.PtrToStructure(lParam, typeof(CREATESTRUCT)); + GCHandle gcHandle = GCHandle.FromIntPtr(createStruct.lpCreateParams); + hwndWrapper = (MessageWindow)gcHandle.Target; + s_windowLookup.Add(hwnd, hwndWrapper); + } + else + { + if (!s_windowLookup.TryGetValue(hwnd, out hwndWrapper)) + { + return NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam); + } + } + Assert.IsNotNull(hwndWrapper); + + WndProc callback = hwndWrapper._wndProcCallback; + if (callback != null) + { + ret = callback(hwnd, msg, wParam, lParam); + } + else + { + ret = NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam); + } + + if (msg == WM.NCDESTROY) + { + hwndWrapper._Dispose(true, true); + GC.SuppressFinalize(hwndWrapper); + } + + return ret; + } + + private static object _DestroyWindow(IntPtr hwnd, string className) + { + Utility.SafeDestroyWindow(ref hwnd); + NativeMethods.UnregisterClass(className, NativeMethods.GetModuleHandle(null)); + return null; + } + } +} diff --git a/Microsoft.Windows.Shell/Standard/NativeMethods.cs b/Microsoft.Windows.Shell/Standard/NativeMethods.cs new file mode 100644 index 0000000..980a77a --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/NativeMethods.cs @@ -0,0 +1,3458 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Standard +{ + using System; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Runtime.ConstrainedExecution; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.ComTypes; + using System.Security.Permissions; + using System.Text; + using Microsoft.Win32.SafeHandles; + + // Some COM interfaces and Win32 structures are already declared in the framework. + // Interesting ones to remember in System.Runtime.InteropServices.ComTypes are: + using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; + using IPersistFile = System.Runtime.InteropServices.ComTypes.IPersistFile; + using IStream = System.Runtime.InteropServices.ComTypes.IStream; + + #region Native Values + + internal static class Win32Value + { + public const uint MAX_PATH = 260; + public const uint INFOTIPSIZE = 1024; + public const uint TRUE = 1; + public const uint FALSE = 0; + public const uint sizeof_WCHAR = 2; + public const uint sizeof_CHAR = 1; + public const uint sizeof_BOOL = 4; + } + + /// + /// HIGHCONTRAST flags + /// + [Flags] + internal enum HCF + { + HIGHCONTRASTON = 0x00000001, + AVAILABLE = 0x00000002, + HOTKEYACTIVE = 0x00000004, + CONFIRMHOTKEY = 0x00000008, + HOTKEYSOUND = 0x00000010, + INDICATOR = 0x00000020, + HOTKEYAVAILABLE = 0x00000040, + } + + /// + /// BITMAPINFOHEADER Compression type. BI_*. + /// + internal enum BI + { + RGB = 0, + } + + /// + /// CombingRgn flags. RGN_* + /// + internal enum RGN + { + /// + /// Creates the intersection of the two combined regions. + /// + AND = 1, + /// + /// Creates the union of two combined regions. + /// + OR = 2, + /// + /// Creates the union of two combined regions except for any overlapping areas. + /// + XOR = 3, + /// + /// Combines the parts of hrgnSrc1 that are not part of hrgnSrc2. + /// + DIFF = 4, + /// + /// Creates a copy of the region identified by hrgnSrc1. + /// + COPY = 5, + } + + internal enum CombineRgnResult + { + ERROR = 0, + NULLREGION = 1, + SIMPLEREGION = 2, + COMPLEXREGION = 3, + } + + /// + /// For IWebBrowser2. OLECMDEXECOPT_* + /// + internal enum OLECMDEXECOPT + { + DODEFAULT = 0, + PROMPTUSER = 1, + DONTPROMPTUSER = 2, + SHOWHELP = 3 + } + + /// + /// For IWebBrowser2. OLECMDF_* + /// + internal enum OLECMDF + { + SUPPORTED = 1, + ENABLED = 2, + LATCHED = 4, + NINCHED = 8, + INVISIBLE = 16, + DEFHIDEONCTXTMENU = 32 + } + + /// + /// For IWebBrowser2. OLECMDID_* + /// + internal enum OLECMDID + { + OPEN = 1, + NEW = 2, + SAVE = 3, + SAVEAS = 4, + SAVECOPYAS = 5, + PRINT = 6, + PRINTPREVIEW = 7, + PAGESETUP = 8, + SPELL = 9, + PROPERTIES = 10, + CUT = 11, + COPY = 12, + PASTE = 13, + PASTESPECIAL = 14, + UNDO = 15, + REDO = 16, + SELECTALL = 17, + CLEARSELECTION = 18, + ZOOM = 19, + GETZOOMRANGE = 20, + UPDATECOMMANDS = 21, + REFRESH = 22, + STOP = 23, + HIDETOOLBARS = 24, + SETPROGRESSMAX = 25, + SETPROGRESSPOS = 26, + SETPROGRESSTEXT = 27, + SETTITLE = 28, + SETDOWNLOADSTATE = 29, + STOPDOWNLOAD = 30, + ONTOOLBARACTIVATED = 31, + FIND = 32, + DELETE = 33, + HTTPEQUIV = 34, + HTTPEQUIV_DONE = 35, + ENABLE_INTERACTION = 36, + ONUNLOAD = 37, + PROPERTYBAG2 = 38, + PREREFRESH = 39, + SHOWSCRIPTERROR = 40, + SHOWMESSAGE = 41, + SHOWFIND = 42, + SHOWPAGESETUP = 43, + SHOWPRINT = 44, + CLOSE = 45, + ALLOWUILESSSAVEAS = 46, + DONTDOWNLOADCSS = 47, + UPDATEPAGESTATUS = 48, + PRINT2 = 49, + PRINTPREVIEW2 = 50, + SETPRINTTEMPLATE = 51, + GETPRINTTEMPLATE = 52, + PAGEACTIONBLOCKED = 55, + PAGEACTIONUIQUERY = 56, + FOCUSVIEWCONTROLS = 57, + FOCUSVIEWCONTROLSQUERY = 58, + SHOWPAGEACTIONMENU = 59 + } + + /// + /// For IWebBrowser2. READYSTATE_* + /// + enum READYSTATE + { + UNINITIALIZED = 0, + LOADING = 1, + LOADED = 2, + INTERACTIVE = 3, + COMPLETE = 4 + } + + /// + /// DATAOBJ_GET_ITEM_FLAGS. DOGIF_*. + /// + internal enum DOGIF + { + DEFAULT = 0x0000, + TRAVERSE_LINK = 0x0001, // if the item is a link get the target + NO_HDROP = 0x0002, // don't fallback and use CF_HDROP clipboard format + NO_URL = 0x0004, // don't fallback and use URL clipboard format + ONLY_IF_ONE = 0x0008, // only return the item if there is one item in the array + } + + internal enum DWM_SIT + { + None, + DISPLAYFRAME = 1, + } + + [Flags] + internal enum ErrorModes + { + /// Use the system default, which is to display all error dialog boxes. + Default = 0x0, + /// + /// The system does not display the critical-error-handler message box. + /// Instead, the system sends the error to the calling process. + /// + FailCriticalErrors = 0x1, + /// + /// 64-bit Windows: The system automatically fixes memory alignment faults and makes them + /// invisible to the application. It does this for the calling process and any descendant processes. + /// After this value is set for a process, subsequent attempts to clear the value are ignored. + /// + NoGpFaultErrorBox = 0x2, + /// + /// The system does not display the general-protection-fault message box. + /// This flag should only be set by debugging applications that handle general + /// protection (GP) faults themselves with an exception handler. + /// + NoAlignmentFaultExcept = 0x4, + /// + /// The system does not display a message box when it fails to find a file. + /// Instead, the error is returned to the calling process. + /// + NoOpenFileErrorBox = 0x8000 + } + + /// + /// Non-client hit test values, HT* + /// + internal enum HT + { + ERROR = -2, + TRANSPARENT = -1, + NOWHERE = 0, + CLIENT = 1, + CAPTION = 2, + SYSMENU = 3, + GROWBOX = 4, + SIZE = GROWBOX, + MENU = 5, + HSCROLL = 6, + VSCROLL = 7, + MINBUTTON = 8, + MAXBUTTON = 9, + LEFT = 10, + RIGHT = 11, + TOP = 12, + TOPLEFT = 13, + TOPRIGHT = 14, + BOTTOM = 15, + BOTTOMLEFT = 16, + BOTTOMRIGHT = 17, + BORDER = 18, + REDUCE = MINBUTTON, + ZOOM = MAXBUTTON, + SIZEFIRST = LEFT, + SIZELAST = BOTTOMRIGHT, + OBJECT = 19, + CLOSE = 20, + HELP = 21 + } + + /// + /// GetClassLongPtr values, GCLP_* + /// + internal enum GCLP + { + HBRBACKGROUND = -10, + } + + /// + /// GetWindowLongPtr values, GWL_* + /// + internal enum GWL + { + WNDPROC = (-4), + HINSTANCE = (-6), + HWNDPARENT = (-8), + STYLE = (-16), + EXSTYLE = (-20), + USERDATA = (-21), + ID = (-12) + } + + /// + /// SystemMetrics. SM_* + /// + 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, + } + + /// + /// SystemParameterInfo values, SPI_* + /// + internal enum SPI + { + GETBEEP = 0x0001, + SETBEEP = 0x0002, + GETMOUSE = 0x0003, + SETMOUSE = 0x0004, + GETBORDER = 0x0005, + SETBORDER = 0x0006, + GETKEYBOARDSPEED = 0x000A, + SETKEYBOARDSPEED = 0x000B, + LANGDRIVER = 0x000C, + ICONHORIZONTALSPACING = 0x000D, + GETSCREENSAVETIMEOUT = 0x000E, + SETSCREENSAVETIMEOUT = 0x000F, + GETSCREENSAVEACTIVE = 0x0010, + SETSCREENSAVEACTIVE = 0x0011, + GETGRIDGRANULARITY = 0x0012, + SETGRIDGRANULARITY = 0x0013, + SETDESKWALLPAPER = 0x0014, + SETDESKPATTERN = 0x0015, + GETKEYBOARDDELAY = 0x0016, + SETKEYBOARDDELAY = 0x0017, + ICONVERTICALSPACING = 0x0018, + GETICONTITLEWRAP = 0x0019, + SETICONTITLEWRAP = 0x001A, + GETMENUDROPALIGNMENT = 0x001B, + SETMENUDROPALIGNMENT = 0x001C, + SETDOUBLECLKWIDTH = 0x001D, + SETDOUBLECLKHEIGHT = 0x001E, + GETICONTITLELOGFONT = 0x001F, + SETDOUBLECLICKTIME = 0x0020, + SETMOUSEBUTTONSWAP = 0x0021, + SETICONTITLELOGFONT = 0x0022, + GETFASTTASKSWITCH = 0x0023, + SETFASTTASKSWITCH = 0x0024, + + SETDRAGFULLWINDOWS = 0x0025, + GETDRAGFULLWINDOWS = 0x0026, + GETNONCLIENTMETRICS = 0x0029, + SETNONCLIENTMETRICS = 0x002A, + GETMINIMIZEDMETRICS = 0x002B, + SETMINIMIZEDMETRICS = 0x002C, + GETICONMETRICS = 0x002D, + SETICONMETRICS = 0x002E, + SETWORKAREA = 0x002F, + GETWORKAREA = 0x0030, + SETPENWINDOWS = 0x0031, + GETHIGHCONTRAST = 0x0042, + SETHIGHCONTRAST = 0x0043, + GETKEYBOARDPREF = 0x0044, + SETKEYBOARDPREF = 0x0045, + GETSCREENREADER = 0x0046, + SETSCREENREADER = 0x0047, + GETANIMATION = 0x0048, + SETANIMATION = 0x0049, + GETFONTSMOOTHING = 0x004A, + SETFONTSMOOTHING = 0x004B, + SETDRAGWIDTH = 0x004C, + SETDRAGHEIGHT = 0x004D, + SETHANDHELD = 0x004E, + GETLOWPOWERTIMEOUT = 0x004F, + GETPOWEROFFTIMEOUT = 0x0050, + SETLOWPOWERTIMEOUT = 0x0051, + SETPOWEROFFTIMEOUT = 0x0052, + GETLOWPOWERACTIVE = 0x0053, + GETPOWEROFFACTIVE = 0x0054, + SETLOWPOWERACTIVE = 0x0055, + SETPOWEROFFACTIVE = 0x0056, + SETCURSORS = 0x0057, + SETICONS = 0x0058, + GETDEFAULTINPUTLANG = 0x0059, + SETDEFAULTINPUTLANG = 0x005A, + SETLANGTOGGLE = 0x005B, + GETWINDOWSEXTENSION = 0x005C, + SETMOUSETRAILS = 0x005D, + GETMOUSETRAILS = 0x005E, + SETSCREENSAVERRUNNING = 0x0061, + SCREENSAVERRUNNING = SETSCREENSAVERRUNNING, + GETFILTERKEYS = 0x0032, + SETFILTERKEYS = 0x0033, + GETTOGGLEKEYS = 0x0034, + SETTOGGLEKEYS = 0x0035, + GETMOUSEKEYS = 0x0036, + SETMOUSEKEYS = 0x0037, + GETSHOWSOUNDS = 0x0038, + SETSHOWSOUNDS = 0x0039, + GETSTICKYKEYS = 0x003A, + SETSTICKYKEYS = 0x003B, + GETACCESSTIMEOUT = 0x003C, + SETACCESSTIMEOUT = 0x003D, + + GETSERIALKEYS = 0x003E, + SETSERIALKEYS = 0x003F, + GETSOUNDSENTRY = 0x0040, + SETSOUNDSENTRY = 0x0041, + GETSNAPTODEFBUTTON = 0x005F, + SETSNAPTODEFBUTTON = 0x0060, + GETMOUSEHOVERWIDTH = 0x0062, + SETMOUSEHOVERWIDTH = 0x0063, + GETMOUSEHOVERHEIGHT = 0x0064, + SETMOUSEHOVERHEIGHT = 0x0065, + GETMOUSEHOVERTIME = 0x0066, + SETMOUSEHOVERTIME = 0x0067, + GETWHEELSCROLLLINES = 0x0068, + SETWHEELSCROLLLINES = 0x0069, + GETMENUSHOWDELAY = 0x006A, + SETMENUSHOWDELAY = 0x006B, + + GETWHEELSCROLLCHARS = 0x006C, + SETWHEELSCROLLCHARS = 0x006D, + + GETSHOWIMEUI = 0x006E, + SETSHOWIMEUI = 0x006F, + + GETMOUSESPEED = 0x0070, + SETMOUSESPEED = 0x0071, + GETSCREENSAVERRUNNING = 0x0072, + GETDESKWALLPAPER = 0x0073, + + GETAUDIODESCRIPTION = 0x0074, + SETAUDIODESCRIPTION = 0x0075, + + GETSCREENSAVESECURE = 0x0076, + SETSCREENSAVESECURE = 0x0077, + + GETHUNGAPPTIMEOUT = 0x0078, + SETHUNGAPPTIMEOUT = 0x0079, + GETWAITTOKILLTIMEOUT = 0x007A, + SETWAITTOKILLTIMEOUT = 0x007B, + GETWAITTOKILLSERVICETIMEOUT = 0x007C, + SETWAITTOKILLSERVICETIMEOUT = 0x007D, + GETMOUSEDOCKTHRESHOLD = 0x007E, + SETMOUSEDOCKTHRESHOLD = 0x007F, + GETPENDOCKTHRESHOLD = 0x0080, + SETPENDOCKTHRESHOLD = 0x0081, + GETWINARRANGING = 0x0082, + SETWINARRANGING = 0x0083, + GETMOUSEDRAGOUTTHRESHOLD = 0x0084, + SETMOUSEDRAGOUTTHRESHOLD = 0x0085, + GETPENDRAGOUTTHRESHOLD = 0x0086, + SETPENDRAGOUTTHRESHOLD = 0x0087, + GETMOUSESIDEMOVETHRESHOLD = 0x0088, + SETMOUSESIDEMOVETHRESHOLD = 0x0089, + GETPENSIDEMOVETHRESHOLD = 0x008A, + SETPENSIDEMOVETHRESHOLD = 0x008B, + GETDRAGFROMMAXIMIZE = 0x008C, + SETDRAGFROMMAXIMIZE = 0x008D, + GETSNAPSIZING = 0x008E, + SETSNAPSIZING = 0x008F, + GETDOCKMOVING = 0x0090, + SETDOCKMOVING = 0x0091, + + GETACTIVEWINDOWTRACKING = 0x1000, + SETACTIVEWINDOWTRACKING = 0x1001, + GETMENUANIMATION = 0x1002, + SETMENUANIMATION = 0x1003, + GETCOMBOBOXANIMATION = 0x1004, + SETCOMBOBOXANIMATION = 0x1005, + GETLISTBOXSMOOTHSCROLLING = 0x1006, + SETLISTBOXSMOOTHSCROLLING = 0x1007, + GETGRADIENTCAPTIONS = 0x1008, + SETGRADIENTCAPTIONS = 0x1009, + GETKEYBOARDCUES = 0x100A, + SETKEYBOARDCUES = 0x100B, + GETMENUUNDERLINES = GETKEYBOARDCUES, + SETMENUUNDERLINES = SETKEYBOARDCUES, + GETACTIVEWNDTRKZORDER = 0x100C, + SETACTIVEWNDTRKZORDER = 0x100D, + GETHOTTRACKING = 0x100E, + SETHOTTRACKING = 0x100F, + GETMENUFADE = 0x1012, + SETMENUFADE = 0x1013, + GETSELECTIONFADE = 0x1014, + SETSELECTIONFADE = 0x1015, + GETTOOLTIPANIMATION = 0x1016, + SETTOOLTIPANIMATION = 0x1017, + GETTOOLTIPFADE = 0x1018, + SETTOOLTIPFADE = 0x1019, + GETCURSORSHADOW = 0x101A, + SETCURSORSHADOW = 0x101B, + GETMOUSESONAR = 0x101C, + SETMOUSESONAR = 0x101D, + GETMOUSECLICKLOCK = 0x101E, + SETMOUSECLICKLOCK = 0x101F, + GETMOUSEVANISH = 0x1020, + SETMOUSEVANISH = 0x1021, + GETFLATMENU = 0x1022, + SETFLATMENU = 0x1023, + GETDROPSHADOW = 0x1024, + SETDROPSHADOW = 0x1025, + GETBLOCKSENDINPUTRESETS = 0x1026, + SETBLOCKSENDINPUTRESETS = 0x1027, + + GETUIEFFECTS = 0x103E, + SETUIEFFECTS = 0x103F, + + GETDISABLEOVERLAPPEDCONTENT = 0x1040, + SETDISABLEOVERLAPPEDCONTENT = 0x1041, + GETCLIENTAREAANIMATION = 0x1042, + SETCLIENTAREAANIMATION = 0x1043, + GETCLEARTYPE = 0x1048, + SETCLEARTYPE = 0x1049, + GETSPEECHRECOGNITION = 0x104A, + SETSPEECHRECOGNITION = 0x104B, + + GETFOREGROUNDLOCKTIMEOUT = 0x2000, + SETFOREGROUNDLOCKTIMEOUT = 0x2001, + GETACTIVEWNDTRKTIMEOUT = 0x2002, + SETACTIVEWNDTRKTIMEOUT = 0x2003, + GETFOREGROUNDFLASHCOUNT = 0x2004, + SETFOREGROUNDFLASHCOUNT = 0x2005, + GETCARETWIDTH = 0x2006, + SETCARETWIDTH = 0x2007, + + GETMOUSECLICKLOCKTIME = 0x2008, + SETMOUSECLICKLOCKTIME = 0x2009, + GETFONTSMOOTHINGTYPE = 0x200A, + SETFONTSMOOTHINGTYPE = 0x200B, + + GETFONTSMOOTHINGCONTRAST = 0x200C, + SETFONTSMOOTHINGCONTRAST = 0x200D, + + GETFOCUSBORDERWIDTH = 0x200E, + SETFOCUSBORDERWIDTH = 0x200F, + GETFOCUSBORDERHEIGHT = 0x2010, + SETFOCUSBORDERHEIGHT = 0x2011, + + GETFONTSMOOTHINGORIENTATION = 0x2012, + SETFONTSMOOTHINGORIENTATION = 0x2013, + + GETMINIMUMHITRADIUS = 0x2014, + SETMINIMUMHITRADIUS = 0x2015, + GETMESSAGEDURATION = 0x2016, + SETMESSAGEDURATION = 0x2017, + } + + /// + /// SystemParameterInfo flag values, SPIF_* + /// + [Flags] + internal enum SPIF + { + None = 0, + UPDATEINIFILE = 0x01, + SENDCHANGE = 0x02, + SENDWININICHANGE = SENDCHANGE, + } + + [Flags] + internal enum STATE_SYSTEM + { + UNAVAILABLE = 0x00000001, // Disabled + SELECTED = 0x00000002, + FOCUSED = 0x00000004, + PRESSED = 0x00000008, + CHECKED = 0x00000010, + MIXED = 0x00000020, // 3-state checkbox or toolbar button + INDETERMINATE = MIXED, + READONLY = 0x00000040, + HOTTRACKED = 0x00000080, + DEFAULT = 0x00000100, + EXPANDED = 0x00000200, + COLLAPSED = 0x00000400, + BUSY = 0x00000800, + FLOATING = 0x00001000, // Children "owned" not "contained" by parent + MARQUEED = 0x00002000, + ANIMATED = 0x00004000, + INVISIBLE = 0x00008000, + OFFSCREEN = 0x00010000, + SIZEABLE = 0x00020000, + MOVEABLE = 0x00040000, + SELFVOICING = 0x00080000, + FOCUSABLE = 0x00100000, + SELECTABLE = 0x00200000, + LINKED = 0x00400000, + TRAVERSED = 0x00800000, + MULTISELECTABLE = 0x01000000, // Supports multiple selection + EXTSELECTABLE = 0x02000000, // Supports extended selection + ALERT_LOW = 0x04000000, // This information is of low priority + ALERT_MEDIUM = 0x08000000, // This information is of medium priority + ALERT_HIGH = 0x10000000, // This information is of high priority + PROTECTED = 0x20000000, // access to this is restricted + VALID = 0x3FFFFFFF, + } + + internal enum StockObject : int + { + WHITE_BRUSH = 0, + LTGRAY_BRUSH = 1, + GRAY_BRUSH = 2, + DKGRAY_BRUSH = 3, + BLACK_BRUSH = 4, + NULL_BRUSH = 5, + HOLLOW_BRUSH = NULL_BRUSH, + WHITE_PEN = 6, + BLACK_PEN = 7, + NULL_PEN = 8, + SYSTEM_FONT = 13, + DEFAULT_PALETTE = 15, + } + + /// + /// CS_* + /// + [Flags] + internal enum CS : uint + { + VREDRAW = 0x0001, + HREDRAW = 0x0002, + DBLCLKS = 0x0008, + OWNDC = 0x0020, + CLASSDC = 0x0040, + PARENTDC = 0x0080, + NOCLOSE = 0x0200, + SAVEBITS = 0x0800, + BYTEALIGNCLIENT = 0x1000, + BYTEALIGNWINDOW = 0x2000, + GLOBALCLASS = 0x4000, + IME = 0x00010000, + DROPSHADOW = 0x00020000 + } + + /// + /// WindowStyle values, WS_* + /// + [Flags] + internal enum WS : uint + { + OVERLAPPED = 0x00000000, + POPUP = 0x80000000, + CHILD = 0x40000000, + MINIMIZE = 0x20000000, + VISIBLE = 0x10000000, + DISABLED = 0x08000000, + CLIPSIBLINGS = 0x04000000, + CLIPCHILDREN = 0x02000000, + MAXIMIZE = 0x01000000, + BORDER = 0x00800000, + DLGFRAME = 0x00400000, + VSCROLL = 0x00200000, + HSCROLL = 0x00100000, + SYSMENU = 0x00080000, + THICKFRAME = 0x00040000, + GROUP = 0x00020000, + TABSTOP = 0x00010000, + + MINIMIZEBOX = 0x00020000, + MAXIMIZEBOX = 0x00010000, + + CAPTION = BORDER | DLGFRAME, + TILED = OVERLAPPED, + ICONIC = MINIMIZE, + SIZEBOX = THICKFRAME, + TILEDWINDOW = OVERLAPPEDWINDOW, + + OVERLAPPEDWINDOW = OVERLAPPED | CAPTION | SYSMENU | THICKFRAME | MINIMIZEBOX | MAXIMIZEBOX, + POPUPWINDOW = POPUP | BORDER | SYSMENU, + CHILDWINDOW = CHILD, + } + + /// + /// Window message values, WM_* + /// + internal enum WM + { + NULL = 0x0000, + CREATE = 0x0001, + DESTROY = 0x0002, + MOVE = 0x0003, + SIZE = 0x0005, + ACTIVATE = 0x0006, + SETFOCUS = 0x0007, + KILLFOCUS = 0x0008, + ENABLE = 0x000A, + SETREDRAW = 0x000B, + SETTEXT = 0x000C, + GETTEXT = 0x000D, + GETTEXTLENGTH = 0x000E, + PAINT = 0x000F, + CLOSE = 0x0010, + QUERYENDSESSION = 0x0011, + QUIT = 0x0012, + QUERYOPEN = 0x0013, + ERASEBKGND = 0x0014, + SYSCOLORCHANGE = 0x0015, + SHOWWINDOW = 0x0018, + CTLCOLOR = 0x0019, + WININICHANGE = 0x001A, + SETTINGCHANGE = 0x001A, + ACTIVATEAPP = 0x001C, + SETCURSOR = 0x0020, + MOUSEACTIVATE = 0x0021, + CHILDACTIVATE = 0x0022, + QUEUESYNC = 0x0023, + GETMINMAXINFO = 0x0024, + + WINDOWPOSCHANGING = 0x0046, + WINDOWPOSCHANGED = 0x0047, + + CONTEXTMENU = 0x007B, + STYLECHANGING = 0x007C, + STYLECHANGED = 0x007D, + DISPLAYCHANGE = 0x007E, + GETICON = 0x007F, + SETICON = 0x0080, + NCCREATE = 0x0081, + NCDESTROY = 0x0082, + NCCALCSIZE = 0x0083, + NCHITTEST = 0x0084, + NCPAINT = 0x0085, + NCACTIVATE = 0x0086, + GETDLGCODE = 0x0087, + SYNCPAINT = 0x0088, + NCMOUSEMOVE = 0x00A0, + NCLBUTTONDOWN = 0x00A1, + NCLBUTTONUP = 0x00A2, + NCLBUTTONDBLCLK = 0x00A3, + NCRBUTTONDOWN = 0x00A4, + NCRBUTTONUP = 0x00A5, + NCRBUTTONDBLCLK = 0x00A6, + NCMBUTTONDOWN = 0x00A7, + NCMBUTTONUP = 0x00A8, + NCMBUTTONDBLCLK = 0x00A9, + + SYSKEYDOWN = 0x0104, + SYSKEYUP = 0x0105, + SYSCHAR = 0x0106, + SYSDEADCHAR = 0x0107, + COMMAND = 0x0111, + SYSCOMMAND = 0x0112, + + MOUSEMOVE = 0x0200, + LBUTTONDOWN = 0x0201, + LBUTTONUP = 0x0202, + LBUTTONDBLCLK = 0x0203, + RBUTTONDOWN = 0x0204, + RBUTTONUP = 0x0205, + RBUTTONDBLCLK = 0x0206, + MBUTTONDOWN = 0x0207, + MBUTTONUP = 0x0208, + MBUTTONDBLCLK = 0x0209, + MOUSEWHEEL = 0x020A, + XBUTTONDOWN = 0x020B, + XBUTTONUP = 0x020C, + XBUTTONDBLCLK = 0x020D, + MOUSEHWHEEL = 0x020E, + PARENTNOTIFY = 0x0210, + + CAPTURECHANGED = 0x0215, + POWERBROADCAST = 0x0218, + DEVICECHANGE = 0x0219, + + ENTERSIZEMOVE = 0x0231, + EXITSIZEMOVE = 0x0232, + + IME_SETCONTEXT = 0x0281, + IME_NOTIFY = 0x0282, + IME_CONTROL = 0x0283, + IME_COMPOSITIONFULL = 0x0284, + IME_SELECT = 0x0285, + IME_CHAR = 0x0286, + IME_REQUEST = 0x0288, + IME_KEYDOWN = 0x0290, + IME_KEYUP = 0x0291, + + NCMOUSELEAVE = 0x02A2, + + TABLET_DEFBASE = 0x02C0, + //WM_TABLET_MAXOFFSET = 0x20, + + TABLET_ADDED = TABLET_DEFBASE + 8, + TABLET_DELETED = TABLET_DEFBASE + 9, + TABLET_FLICK = TABLET_DEFBASE + 11, + TABLET_QUERYSYSTEMGESTURESTATUS = TABLET_DEFBASE + 12, + + CUT = 0x0300, + COPY = 0x0301, + PASTE = 0x0302, + CLEAR = 0x0303, + UNDO = 0x0304, + RENDERFORMAT = 0x0305, + RENDERALLFORMATS = 0x0306, + DESTROYCLIPBOARD = 0x0307, + DRAWCLIPBOARD = 0x0308, + PAINTCLIPBOARD = 0x0309, + VSCROLLCLIPBOARD = 0x030A, + SIZECLIPBOARD = 0x030B, + ASKCBFORMATNAME = 0x030C, + CHANGECBCHAIN = 0x030D, + HSCROLLCLIPBOARD = 0x030E, + QUERYNEWPALETTE = 0x030F, + PALETTEISCHANGING = 0x0310, + PALETTECHANGED = 0x0311, + HOTKEY = 0x0312, + PRINT = 0x0317, + PRINTCLIENT = 0x0318, + APPCOMMAND = 0x0319, + THEMECHANGED = 0x031A, + + DWMCOMPOSITIONCHANGED = 0x031E, + DWMNCRENDERINGCHANGED = 0x031F, + DWMCOLORIZATIONCOLORCHANGED = 0x0320, + DWMWINDOWMAXIMIZEDCHANGE = 0x0321, + + GETTITLEBARINFOEX = 0x033F, + #region Windows 7 + DWMSENDICONICTHUMBNAIL = 0x0323, + DWMSENDICONICLIVEPREVIEWBITMAP = 0x0326, + #endregion + + USER = 0x0400, + + // This is the hard-coded message value used by WinForms for Shell_NotifyIcon. + // It's relatively safe to reuse. + TRAYMOUSEMESSAGE = 0x800, //WM_USER + 1024 + APP = 0x8000, + } + + /// + /// Window style extended values, WS_EX_* + /// + [Flags] + internal enum WS_EX : uint + { + None = 0, + DLGMODALFRAME = 0x00000001, + NOPARENTNOTIFY = 0x00000004, + TOPMOST = 0x00000008, + ACCEPTFILES = 0x00000010, + TRANSPARENT = 0x00000020, + MDICHILD = 0x00000040, + TOOLWINDOW = 0x00000080, + WINDOWEDGE = 0x00000100, + CLIENTEDGE = 0x00000200, + CONTEXTHELP = 0x00000400, + RIGHT = 0x00001000, + LEFT = 0x00000000, + RTLREADING = 0x00002000, + LTRREADING = 0x00000000, + LEFTSCROLLBAR = 0x00004000, + RIGHTSCROLLBAR = 0x00000000, + CONTROLPARENT = 0x00010000, + STATICEDGE = 0x00020000, + APPWINDOW = 0x00040000, + LAYERED = 0x00080000, + NOINHERITLAYOUT = 0x00100000, // Disable inheritence of mirroring by children + LAYOUTRTL = 0x00400000, // Right to left mirroring + COMPOSITED = 0x02000000, + NOACTIVATE = 0x08000000, + OVERLAPPEDWINDOW = (WINDOWEDGE | CLIENTEDGE), + PALETTEWINDOW = (WINDOWEDGE | TOOLWINDOW | TOPMOST), + } + + /// + /// GetDeviceCaps nIndex values. + /// + internal enum DeviceCap + { + /// Number of bits per pixel + /// + BITSPIXEL = 12, + /// + /// Number of planes + /// + PLANES = 14, + /// + /// Logical pixels inch in X + /// + LOGPIXELSX = 88, + /// + /// Logical pixels inch in Y + /// + LOGPIXELSY = 90, + } + + internal enum FO : int + { + MOVE = 0x0001, + COPY = 0x0002, + DELETE = 0x0003, + RENAME = 0x0004, + } + + /// + /// "FILEOP_FLAGS", FOF_*. + /// + internal enum FOF : ushort + { + MULTIDESTFILES = 0x0001, + CONFIRMMOUSE = 0x0002, + SILENT = 0x0004, + RENAMEONCOLLISION = 0x0008, + NOCONFIRMATION = 0x0010, + WANTMAPPINGHANDLE = 0x0020, + ALLOWUNDO = 0x0040, + FILESONLY = 0x0080, + SIMPLEPROGRESS = 0x0100, + NOCONFIRMMKDIR = 0x0200, + NOERRORUI = 0x0400, + NOCOPYSECURITYATTRIBS = 0x0800, + NORECURSION = 0x1000, + NO_CONNECTED_ELEMENTS = 0x2000, + WANTNUKEWARNING = 0x4000, + NORECURSEREPARSE = 0x8000, + } + + /// + /// EnableMenuItem uEnable values, MF_* + /// + [Flags] + internal enum MF : uint + { + /// + /// Possible return value for EnableMenuItem + /// + DOES_NOT_EXIST = unchecked((uint)-1), + ENABLED = 0, + BYCOMMAND = 0, + GRAYED = 1, + DISABLED = 2, + } + + /// Specifies the type of visual style attribute to set on a window. + internal enum WINDOWTHEMEATTRIBUTETYPE : uint + { + /// Non-client area window attributes will be set. + WTA_NONCLIENT = 1, + } + + /// + /// DWMFLIP3DWINDOWPOLICY. DWMFLIP3D_* + /// + internal enum DWMFLIP3D + { + DEFAULT, + EXCLUDEBELOW, + EXCLUDEABOVE, + //LAST + } + + /// + /// DWMNCRENDERINGPOLICY. DWMNCRP_* + /// + internal enum DWMNCRP + { + USEWINDOWSTYLE, + DISABLED, + ENABLED, + //LAST + } + + /// + /// DWMWINDOWATTRIBUTE. DWMWA_* + /// + internal enum DWMWA + { + NCRENDERING_ENABLED = 1, + NCRENDERING_POLICY, + TRANSITIONS_FORCEDISABLED, + ALLOW_NCPAINT, + CAPTION_BUTTON_BOUNDS, + NONCLIENT_RTL_LAYOUT, + FORCE_ICONIC_REPRESENTATION, + FLIP3D_POLICY, + EXTENDED_FRAME_BOUNDS, + + // New to Windows 7: + + HAS_ICONIC_BITMAP, + DISALLOW_PEEK, + EXCLUDED_FROM_PEEK, + + // LAST + } + + /// + /// WindowThemeNonClientAttributes + /// + [Flags] + internal enum WTNCA : uint + { + /// Prevents the window caption from being drawn. + NODRAWCAPTION = 0x00000001, + /// Prevents the system icon from being drawn. + NODRAWICON = 0x00000002, + /// Prevents the system icon menu from appearing. + NOSYSMENU = 0x00000004, + /// Prevents mirroring of the question mark, even in right-to-left (RTL) layout. + NOMIRRORHELP = 0x00000008, + /// A mask that contains all the valid bits. + VALIDBITS = NODRAWCAPTION | NODRAWICON | NOMIRRORHELP | NOSYSMENU, + } + + /// + /// SetWindowPos options + /// + [Flags] + internal enum SWP + { + ASYNCWINDOWPOS = 0x4000, + DEFERERASE = 0x2000, + DRAWFRAME = 0x0020, + FRAMECHANGED = 0x0020, + HIDEWINDOW = 0x0080, + NOACTIVATE = 0x0010, + NOCOPYBITS = 0x0100, + NOMOVE = 0x0002, + NOOWNERZORDER = 0x0200, + NOREDRAW = 0x0008, + NOREPOSITION = 0x0200, + NOSENDCHANGING = 0x0400, + NOSIZE = 0x0001, + NOZORDER = 0x0004, + SHOWWINDOW = 0x0040, + } + + /// + /// ShowWindow options + /// + internal enum SW + { + HIDE = 0, + SHOWNORMAL = 1, + NORMAL = 1, + SHOWMINIMIZED = 2, + SHOWMAXIMIZED = 3, + MAXIMIZE = 3, + SHOWNOACTIVATE = 4, + SHOW = 5, + MINIMIZE = 6, + SHOWMINNOACTIVE = 7, + SHOWNA = 8, + RESTORE = 9, + SHOWDEFAULT = 10, + FORCEMINIMIZE = 11, + } + + internal enum SC + { + SIZE = 0xF000, + MOVE = 0xF010, + MINIMIZE = 0xF020, + MAXIMIZE = 0xF030, + NEXTWINDOW = 0xF040, + PREVWINDOW = 0xF050, + CLOSE = 0xF060, + VSCROLL = 0xF070, + HSCROLL = 0xF080, + MOUSEMENU = 0xF090, + KEYMENU = 0xF100, + ARRANGE = 0xF110, + RESTORE = 0xF120, + TASKLIST = 0xF130, + SCREENSAVE = 0xF140, + HOTKEY = 0xF150, + DEFAULT = 0xF160, + MONITORPOWER = 0xF170, + CONTEXTHELP = 0xF180, + SEPARATOR = 0xF00F, + /// + /// SCF_ISSECURE + /// + F_ISSECURE = 0x00000001, + ICON = MINIMIZE, + ZOOM = MAXIMIZE, + } + + /// + /// GDI+ Status codes + /// + internal enum Status + { + 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, + ProfileNotFound = 21, + } + + internal enum MOUSEEVENTF : int + { + //mouse event constants + LEFTDOWN = 2, + LEFTUP = 4 + } + + /// + /// MSGFLT_*. New in Vista. Realiased in Windows 7. + /// + internal enum MSGFLT + { + // Win7 versions of this enum: + RESET = 0, + ALLOW = 1, + DISALLOW = 2, + + // Vista versions of this enum: + // ADD = 1, + // REMOVE = 2, + } + + internal enum MSGFLTINFO + { + NONE = 0, + ALREADYALLOWED_FORWND = 1, + ALREADYDISALLOWED_FORWND = 2, + ALLOWED_HIGHER = 3, + } + + internal enum INPUT_TYPE : uint + { + MOUSE = 0, + } + + /// + /// Shell_NotifyIcon messages. NIM_* + /// + internal enum NIM : uint + { + ADD = 0, + MODIFY = 1, + DELETE = 2, + SETFOCUS = 3, + SETVERSION = 4, + } + + /// + /// SHAddToRecentDocuments flags. SHARD_* + /// + internal enum SHARD + { + PIDL = 0x00000001, + PATHA = 0x00000002, + PATHW = 0x00000003, + APPIDINFO = 0x00000004, // indicates the data type is a pointer to a SHARDAPPIDINFO structure + APPIDINFOIDLIST = 0x00000005, // indicates the data type is a pointer to a SHARDAPPIDINFOIDLIST structure + LINK = 0x00000006, // indicates the data type is a pointer to an IShellLink instance + APPIDINFOLINK = 0x00000007, // indicates the data type is a pointer to a SHARDAPPIDINFOLINK structure + } + + [Flags] + enum SLGP + { + SHORTPATH = 0x1, + UNCPRIORITY = 0x2, + RAWPATH = 0x4 + } + + /// + /// Shell_NotifyIcon flags. NIF_* + /// + [Flags] + internal enum NIF : uint + { + MESSAGE = 0x0001, + ICON = 0x0002, + TIP = 0x0004, + STATE = 0x0008, + INFO = 0x0010, + GUID = 0x0020, + + /// + /// Vista only. + /// + REALTIME = 0x0040, + /// + /// Vista only. + /// + SHOWTIP = 0x0080, + + XP_MASK = MESSAGE | ICON | STATE | INFO | GUID, + VISTA_MASK = XP_MASK | REALTIME | SHOWTIP, + } + + /// + /// Shell_NotifyIcon info flags. NIIF_* + /// + internal enum NIIF + { + NONE = 0x00000000, + INFO = 0x00000001, + WARNING = 0x00000002, + ERROR = 0x00000003, + /// XP SP2 and later. + USER = 0x00000004, + /// XP and later. + NOSOUND = 0x00000010, + /// Vista and later. + LARGE_ICON = 0x00000020, + /// Windows 7 and later + NIIF_RESPECT_QUIET_TIME = 0x00000080, + /// XP and later. Native version called NIIF_ICON_MASK. + XP_ICON_MASK = 0x0000000F, + } + + /// + /// AC_* + /// + internal enum AC : byte + { + SRC_OVER = 0, + SRC_ALPHA = 1, + } + + internal enum ULW + { + ALPHA = 2, + COLORKEY = 1, + OPAQUE = 4, + } + + internal enum WVR + { + ALIGNTOP = 0x0010, + ALIGNLEFT = 0x0020, + ALIGNBOTTOM = 0x0040, + ALIGNRIGHT = 0x0080, + HREDRAW = 0x0100, + VREDRAW = 0x0200, + VALIDRECTS = 0x0400, + REDRAW = HREDRAW | VREDRAW, + } + + #endregion + + #region SafeHandles + + internal sealed class SafeFindHandle : SafeHandleZeroOrMinusOneIsInvalid + { + [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] + private SafeFindHandle() : base(true) { } + + protected override bool ReleaseHandle() + { + return NativeMethods.FindClose(handle); + } + } + + internal sealed class SafeDC : SafeHandleZeroOrMinusOneIsInvalid + { + private static class NativeMethods + { + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern SafeDC GetDC(IntPtr hwnd); + + // Weird legacy function, documentation is unclear about how to use it... + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", CharSet = CharSet.Unicode)] + public static extern SafeDC CreateDC([MarshalAs(UnmanagedType.LPWStr)] string lpszDriver, [MarshalAs(UnmanagedType.LPWStr)] string lpszDevice, IntPtr lpszOutput, IntPtr lpInitData); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern SafeDC CreateCompatibleDC(IntPtr hdc); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DeleteDC(IntPtr hdc); + } + + private IntPtr? _hwnd; + private bool _created; + + public IntPtr Hwnd + { + set + { + Assert.NullableIsNull(_hwnd); + _hwnd = value; + } + } + + private SafeDC() : base(true) { } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + if (_created) + { + return NativeMethods.DeleteDC(handle); + } + + if (!_hwnd.HasValue || _hwnd.Value == IntPtr.Zero) + { + return true; + } + + return NativeMethods.ReleaseDC(_hwnd.Value, handle) == 1; + } + + [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes"), SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static SafeDC CreateDC(string deviceName) + { + SafeDC dc = null; + try + { + // Should this really be on the driver parameter? + dc = NativeMethods.CreateDC(deviceName, null, IntPtr.Zero, IntPtr.Zero); + } + finally + { + if (dc != null) + { + dc._created = true; + } + } + + if (dc.IsInvalid) + { + dc.Dispose(); + throw new SystemException("Unable to create a device context from the specified device information."); + } + + return dc; + } + + [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes"), SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static SafeDC CreateCompatibleDC(SafeDC hdc) + { + SafeDC dc = null; + try + { + IntPtr hPtr = IntPtr.Zero; + if (hdc != null) + { + hPtr = hdc.handle; + } + dc = NativeMethods.CreateCompatibleDC(hPtr); + if (dc == null) + { + HRESULT.ThrowLastError(); + } + } + finally + { + if (dc != null) + { + dc._created = true; + } + } + + if (dc.IsInvalid) + { + dc.Dispose(); + throw new SystemException("Unable to create a device context from the specified device information."); + } + + return dc; + } + + public static SafeDC GetDC(IntPtr hwnd) + { + SafeDC dc = null; + try + { + dc = NativeMethods.GetDC(hwnd); + } + finally + { + if (dc != null) + { + dc.Hwnd = hwnd; + } + } + + if (dc.IsInvalid) + { + // GetDC does not set the last error... + HRESULT.E_FAIL.ThrowIfFailed(); + } + + return dc; + } + + public static SafeDC GetDesktop() + { + return GetDC(IntPtr.Zero); + } + + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static SafeDC WrapDC(IntPtr hdc) + { + // This won't actually get released by the class, but it allows an IntPtr to be converted for signatures. + return new SafeDC + { + handle = hdc, + _created = false, + _hwnd = IntPtr.Zero, + }; + } + } + + internal sealed class SafeHBITMAP : SafeHandleZeroOrMinusOneIsInvalid + { + private SafeHBITMAP() : base(true) { } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + return NativeMethods.DeleteObject(handle); + } + } + + internal sealed class SafeGdiplusStartupToken : SafeHandleZeroOrMinusOneIsInvalid + { + private SafeGdiplusStartupToken() : base(true) { } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + Status s = NativeMethods.GdiplusShutdown(this.handle); + return s == Status.Ok; + } + + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")] + public static SafeGdiplusStartupToken Startup() + { + SafeGdiplusStartupToken safeHandle = new SafeGdiplusStartupToken(); + IntPtr unsafeHandle; + StartupOutput output; + Status s = NativeMethods.GdiplusStartup(out unsafeHandle, new StartupInput(), out output); + if (s == Status.Ok) + { + safeHandle.handle = unsafeHandle; + return safeHandle; + } + safeHandle.Dispose(); + throw new Exception("Unable to initialize GDI+"); + } + } + + internal sealed class SafeConnectionPointCookie : SafeHandleZeroOrMinusOneIsInvalid + { + private IConnectionPoint _cp; + // handle holds the cookie value. + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "IConnectionPoint")] + public SafeConnectionPointCookie(IConnectionPointContainer target, object sink, Guid eventId) + : base(true) + { + Verify.IsNotNull(target, "target"); + Verify.IsNotNull(sink, "sink"); + Verify.IsNotDefault(eventId, "eventId"); + + handle = IntPtr.Zero; + + IConnectionPoint cp = null; + try + { + int dwCookie; + target.FindConnectionPoint(ref eventId, out cp); + cp.Advise(sink, out dwCookie); + if (dwCookie == 0) + { + throw new InvalidOperationException("IConnectionPoint::Advise returned an invalid cookie."); + } + handle = new IntPtr(dwCookie); + _cp = cp; + cp = null; + } + finally + { + Utility.SafeRelease(ref cp); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void Disconnect() + { + ReleaseHandle(); + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + try + { + if (!this.IsInvalid) + { + int dwCookie = handle.ToInt32(); + handle = IntPtr.Zero; + + Assert.IsNotNull(_cp); + try + { + _cp.Unadvise(dwCookie); + } + finally + { + Utility.SafeRelease(ref _cp); + } + } + return true; + } + catch + { + return false; + } + } + } + + #endregion + + #region Native Types + + [StructLayout(LayoutKind.Sequential)] + internal struct BLENDFUNCTION + { + // Must be AC_SRC_OVER + public AC BlendOp; + // Must be 0. + public byte BlendFlags; + // Alpha transparency between 0 (transparent) - 255 (opaque) + public byte SourceConstantAlpha; + // Must be AC_SRC_ALPHA + public AC AlphaFormat; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HIGHCONTRAST + { + public int cbSize; + public HCF dwFlags; + //[MarshalAs(UnmanagedType.LPWStr, SizeConst=80)] + //public String lpszDefaultScheme; + public IntPtr lpszDefaultScheme; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct RGBQUAD + { + public byte rgbBlue; + public byte rgbGreen; + public byte rgbRed; + public byte rgbReserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 2)] + internal struct BITMAPINFOHEADER + { + public int biSize; + public int biWidth; + public int biHeight; + public short biPlanes; + public short biBitCount; + public BI biCompression; + public int biSizeImage; + public int biXPelsPerMeter; + public int biYPelsPerMeter; + public int biClrUsed; + public int biClrImportant; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct BITMAPINFO + { + public BITMAPINFOHEADER bmiHeader; + public RGBQUAD bmiColors; + } + + // Win7 only. + [StructLayout(LayoutKind.Sequential)] + internal struct CHANGEFILTERSTRUCT + { + public uint cbSize; + public MSGFLTINFO ExtStatus; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct CREATESTRUCT + { + public IntPtr lpCreateParams; + public IntPtr hInstance; + public IntPtr hMenu; + public IntPtr hwndParent; + public int cy; + public int cx; + public int y; + public int x; + public WS style; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpszName; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpszClass; + public WS_EX dwExStyle; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] + internal struct SHFILEOPSTRUCT + { + public IntPtr hwnd; + [MarshalAs(UnmanagedType.U4)] + public FO wFunc; + // double-null terminated arrays of LPWSTRS + public string pFrom; + public string pTo; + [MarshalAs(UnmanagedType.U2)] + public FOF fFlags; + [MarshalAs(UnmanagedType.Bool)] + public int fAnyOperationsAborted; + public IntPtr hNameMappings; + public string lpszProgressTitle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct TITLEBARINFO + { + public int cbSize; + public RECT rcTitleBar; + public STATE_SYSTEM rgstate_TitleBar; + public STATE_SYSTEM rgstate_Reserved; + public STATE_SYSTEM rgstate_MinimizeButton; + public STATE_SYSTEM rgstate_MaximizeButton; + public STATE_SYSTEM rgstate_HelpButton; + public STATE_SYSTEM rgstate_CloseButton; + } + + // New to Vista. + [StructLayout(LayoutKind.Sequential)] + internal struct TITLEBARINFOEX + { + public int cbSize; + public RECT rcTitleBar; + public STATE_SYSTEM rgstate_TitleBar; + public STATE_SYSTEM rgstate_Reserved; + public STATE_SYSTEM rgstate_MinimizeButton; + public STATE_SYSTEM rgstate_MaximizeButton; + public STATE_SYSTEM rgstate_HelpButton; + public STATE_SYSTEM rgstate_CloseButton; + public RECT rgrect_TitleBar; + public RECT rgrect_Reserved; + public RECT rgrect_MinimizeButton; + public RECT rgrect_MaximizeButton; + public RECT rgrect_HelpButton; + public RECT rgrect_CloseButton; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential)] + internal class NOTIFYICONDATA + { + public int cbSize; + public IntPtr hWnd; + public int uID; + public NIF uFlags; + public int uCallbackMessage; + public IntPtr hIcon; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] + public char[] szTip = new char[128]; + /// + /// The state of the icon. There are two flags that can be set independently. + /// NIS_HIDDEN = 1. The icon is hidden. + /// NIS_SHAREDICON = 2. The icon is shared. + /// + public uint dwState; + public uint dwStateMask; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] + public char[] szInfo = new char[256]; + // Prior to Vista this was a union of uTimeout and uVersion. As of Vista, uTimeout has been deprecated. + public uint uVersion; // Used with Shell_NotifyIcon flag NIM_SETVERSION. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public char[] szInfoTitle = new char[64]; + public uint dwInfoFlags; + public Guid guidItem; + // Vista only + IntPtr hBalloonIcon; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Explicit)] + internal class PROPVARIANT : IDisposable + { + private static class NativeMethods + { + [DllImport("ole32.dll")] + internal static extern HRESULT PropVariantClear(PROPVARIANT pvar); + } + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(0)] + private ushort vt; + [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(8)] + private IntPtr pointerVal; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(8)] + private byte byteVal; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(8)] + private long longVal; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(8)] + private short boolVal; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public VarEnum VarType + { + get { return (VarEnum)vt; } + } + + // Right now only using this for strings. + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public string GetValue() + { + if (vt == (ushort)VarEnum.VT_LPWSTR) + { + return Marshal.PtrToStringUni(pointerVal); + } + + return null; + } + + public void SetValue(bool f) + { + Clear(); + vt = (ushort)VarEnum.VT_BOOL; + boolVal = (short)(f ? -1 : 0); + } + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void SetValue(string val) + { + Clear(); + vt = (ushort)VarEnum.VT_LPWSTR; + pointerVal = Marshal.StringToCoTaskMemUni(val); + } + + public void Clear() + { + HRESULT hr = NativeMethods.PropVariantClear(this); + Assert.IsTrue(hr.Succeeded); + } + + #region IDisposable Pattern + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + ~PROPVARIANT() + { + Dispose(false); + } + + [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disposing")] + private void Dispose(bool disposing) + { + Clear(); + } + + #endregion + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal class SHARDAPPIDINFO + { + [MarshalAs(UnmanagedType.Interface)] + object psi; // The namespace location of the the item that should be added to the recent docs folder. + [MarshalAs(UnmanagedType.LPWStr)] + string pszAppID; // The id of the application that should be associated with this recent doc. + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal class SHARDAPPIDINFOIDLIST + { + /// The idlist for the shell item that should be added to the recent docs folder. + IntPtr pidl; + /// The id of the application that should be associated with this recent doc. + [MarshalAs(UnmanagedType.LPWStr)] + string pszAppID; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal class SHARDAPPIDINFOLINK + { + IntPtr psl; // An IShellLink instance that when launched opens a recently used item in the specified + // application. This link is not added to the recent docs folder, but will be added to the + // specified application's destination list. + [MarshalAs(UnmanagedType.LPWStr)] + string pszAppID; // The id of the application that should be associated with this recent doc. + } + + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct LOGFONT + { + public int lfHeight; + public int lfWidth; + public int lfEscapement; + public int lfOrientation; + public int lfWeight; + public byte lfItalic; + public byte lfUnderline; + public byte lfStrikeOut; + public byte lfCharSet; + public byte lfOutPrecision; + public byte lfClipPrecision; + public byte lfQuality; + public byte lfPitchAndFamily; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string lfFaceName; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MINMAXINFO + { + public POINT ptReserved; + public POINT ptMaxSize; + public POINT ptMaxPosition; + public POINT ptMinTrackSize; + public POINT ptMaxTrackSize; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NONCLIENTMETRICS + { + public int cbSize; + public int iBorderWidth; + public int iScrollWidth; + public int iScrollHeight; + public int iCaptionWidth; + public int iCaptionHeight; + public LOGFONT lfCaptionFont; + public int iSmCaptionWidth; + public int iSmCaptionHeight; + public LOGFONT lfSmCaptionFont; + public int iMenuWidth; + public int iMenuHeight; + public LOGFONT lfMenuFont; + public LOGFONT lfStatusFont; + public LOGFONT lfMessageFont; + // Vista only + public int iPaddedBorderWidth; + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static NONCLIENTMETRICS VistaMetricsStruct + { + get + { + var ncm = new NONCLIENTMETRICS(); + ncm.cbSize = Marshal.SizeOf(typeof(NONCLIENTMETRICS)); + return ncm; + } + } + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static NONCLIENTMETRICS XPMetricsStruct + { + get + { + var ncm = new NONCLIENTMETRICS(); + // Account for the missing iPaddedBorderWidth + ncm.cbSize = Marshal.SizeOf(typeof(NONCLIENTMETRICS)) - sizeof(int); + return ncm; + } + } + } + + /// Defines options that are used to set window visual style attributes. + [StructLayout(LayoutKind.Explicit)] + internal struct WTA_OPTIONS + { + // public static readonly uint Size = (uint)Marshal.SizeOf(typeof(WTA_OPTIONS)); + public const uint Size = 8; + + /// + /// A combination of flags that modify window visual style attributes. + /// Can be a combination of the WTNCA constants. + /// + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Used by native code.")] + [FieldOffset(0)] + public WTNCA dwFlags; + + /// + /// A bitmask that describes how the values specified in dwFlags should be applied. + /// If the bit corresponding to a value in dwFlags is 0, that flag will be removed. + /// If the bit is 1, the flag will be added. + /// + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Used by native code.")] + [FieldOffset(4)] + public WTNCA dwMask; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MARGINS + { + /// Width of left border that retains its size. + public int cxLeftWidth; + /// Width of right border that retains its size. + public int cxRightWidth; + /// Height of top border that retains its size. + public int cyTopHeight; + /// Height of bottom border that retains its size. + public int cyBottomHeight; + }; + + [StructLayout(LayoutKind.Sequential)] + internal class MONITORINFO + { + public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); + public RECT rcMonitor; + public RECT rcWork; + public int dwFlags; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct POINT + { + public int x; + public int y; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential)] + internal class RefPOINT + { + public int x; + public int y; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct RECT + { + private int _left; + private int _top; + private int _right; + private int _bottom; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void Offset(int dx, int dy) + { + _left += dx; + _top += dy; + _right += dx; + _bottom += dy; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Left + { + get { return _left; } + set { _left = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Right + { + get { return _right; } + set { _right = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Top + { + get { return _top; } + set { _top = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Bottom + { + get { return _bottom; } + set { _bottom = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Width + { + get { return _right - _left; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Height + { + get { return _bottom - _top; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public POINT Position + { + get { return new POINT { x = _left, y = _top }; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public SIZE Size + { + get { return new SIZE { cx = Width, cy = Height }; } + } + + public static RECT Union(RECT rect1, RECT rect2) + { + return new RECT + { + Left = Math.Min(rect1.Left, rect2.Left), + Top = Math.Min(rect1.Top, rect2.Top), + Right = Math.Max(rect1.Right, rect2.Right), + Bottom = Math.Max(rect1.Bottom, rect2.Bottom), + }; + } + + public override bool Equals(object obj) + { + try + { + var rc = (RECT)obj; + return rc._bottom == _bottom + && rc._left == _left + && rc._right == _right + && rc._top == _top; + } + catch (InvalidCastException) + { + return false; + } + } + + public override int GetHashCode() + { + return (_left << 16 | Utility.LOWORD(_right)) ^ (_top << 16 | Utility.LOWORD(_bottom)); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential)] + internal class RefRECT + { + private int _left; + private int _top; + private int _right; + private int _bottom; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public RefRECT(int left, int top, int right, int bottom) + { + _left = left; + _top = top; + _right = right; + _bottom = bottom; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Width + { + get { return _right - _left; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Height + { + get { return _bottom - _top; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Left + { + get { return _left; } + set { _left = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Right + { + get { return _right; } + set { _right = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Top + { + get { return _top; } + set { _top = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Bottom + { + get { return _bottom; } + set { _bottom = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void Offset(int dx, int dy) + { + _left += dx; + _top += dy; + _right += dx; + _bottom += dy; + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SIZE + { + public int cx; + public int cy; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct StartupOutput + { + public IntPtr hook; + public IntPtr unhook; + } + + [StructLayout(LayoutKind.Sequential)] + internal class StartupInput + { + public int GdiplusVersion = 1; + public IntPtr DebugEventCallback; + public bool SuppressBackgroundThread; + public bool SuppressExternalCodecs; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [BestFitMapping(false)] + internal class WIN32_FIND_DATAW + { + public FileAttributes dwFileAttributes; + public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime; + public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime; + public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime; + public int nFileSizeHigh; + public int nFileSizeLow; + public int dwReserved0; + public int dwReserved1; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string cFileName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] + public string cAlternateFileName; + } + + [StructLayout(LayoutKind.Sequential)] + internal class WINDOWPLACEMENT + { + public int length = Marshal.SizeOf(typeof(WINDOWPLACEMENT)); + public int flags; + public SW showCmd; + public POINT ptMinPosition; + public POINT ptMaxPosition; + public RECT rcNormalPosition; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct WINDOWPOS + { + public IntPtr hwnd; + public IntPtr hwndInsertAfter; + public int x; + public int y; + public int cx; + public int cy; + public int flags; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct WNDCLASSEX + { + public int cbSize; + public CS style; + public WndProc lpfnWndProc; + public int cbClsExtra; + public int cbWndExtra; + public IntPtr hInstance; + public IntPtr hIcon; + public IntPtr hCursor; + public IntPtr hbrBackground; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpszMenuName; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpszClassName; + public IntPtr hIconSm; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MOUSEINPUT + { + public int dx; + public int dy; + public int mouseData; + public int dwFlags; + public int time; + public IntPtr dwExtraInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct INPUT + { + public uint type; + public MOUSEINPUT mi; + }; + + [StructLayout(LayoutKind.Sequential)] + internal struct UNSIGNED_RATIO + { + public uint uiNumerator; + public uint uiDenominator; + } + + [StructLayout(LayoutKind.Sequential, Pack=1)] + internal struct DWM_TIMING_INFO + { + public int cbSize; + public UNSIGNED_RATIO rateRefresh; + public ulong qpcRefreshPeriod; + public UNSIGNED_RATIO rateCompose; + public ulong qpcVBlank; + public ulong cRefresh; + public uint cDXRefresh; + public ulong qpcCompose; + public ulong cFrame; + public uint cDXPresent; + public ulong cRefreshFrame; + public ulong cFrameSubmitted; + public uint cDXPresentSubmitted; + public ulong cFrameConfirmed; + public uint cDXPresentConfirmed; + public ulong cRefreshConfirmed; + public uint cDXRefreshConfirmed; + public ulong cFramesLate; + public uint cFramesOutstanding; + public ulong cFrameDisplayed; + public ulong qpcFrameDisplayed; + public ulong cRefreshFrameDisplayed; + public ulong cFrameComplete; + public ulong qpcFrameComplete; + public ulong cFramePending; + public ulong qpcFramePending; + public ulong cFramesDisplayed; + public ulong cFramesComplete; + public ulong cFramesPending; + public ulong cFramesAvailable; + public ulong cFramesDropped; + public ulong cFramesMissed; + public ulong cRefreshNextDisplayed; + public ulong cRefreshNextPresented; + public ulong cRefreshesDisplayed; + public ulong cRefreshesPresented; + public ulong cRefreshStarted; + public ulong cPixelsReceived; + public ulong cPixelsDrawn; + public ulong cBuffersEmpty; + } + + #endregion + + /// Delegate declaration that matches native WndProc signatures. + internal delegate IntPtr WndProc(IntPtr hwnd, WM uMsg, IntPtr wParam, IntPtr lParam); + + /// Delegate declaration that matches native WndProc signatures. + internal delegate IntPtr WndProcHook(IntPtr hwnd, WM uMsg, IntPtr wParam, IntPtr lParam, ref bool handled); + + /// Delegate declaration that matches managed WndProc signatures. + internal delegate IntPtr MessageHandler(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled); + + // Some native methods are shimmed through public versions that handle converting failures into thrown exceptions. + internal static class NativeMethods + { + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "AdjustWindowRectEx", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _AdjustWindowRectEx(ref RECT lpRect, WS dwStyle, [MarshalAs(UnmanagedType.Bool)] bool bMenu, WS_EX dwExStyle); + + public static RECT AdjustWindowRectEx(RECT lpRect, WS dwStyle, bool bMenu, WS_EX dwExStyle) + { + // Native version modifies the parameter in place. + if (!_AdjustWindowRectEx(ref lpRect, dwStyle, bMenu, dwExStyle)) + { + HRESULT.ThrowLastError(); + } + + return lpRect; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "ChangeWindowMessageFilter", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _ChangeWindowMessageFilter(WM message, MSGFLT dwFlag); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "ChangeWindowMessageFilterEx", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _ChangeWindowMessageFilterEx(IntPtr hwnd, WM message, MSGFLT action, [In, Out, Optional] ref CHANGEFILTERSTRUCT pChangeFilterStruct); + + // Note that processes at or below SECURITY_MANDATORY_LOW_RID are not allowed to change the message filter. + // If those processes call this function, it will fail and generate the extended error code, ERROR_ACCESS_DENIED. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static HRESULT ChangeWindowMessageFilterEx(IntPtr hwnd, WM message, MSGFLT action, out MSGFLTINFO filterInfo) + { + filterInfo = MSGFLTINFO.NONE; + + bool ret; + + // This origins of this API were added for Vista. The Ex version was added for Windows 7. + // If we're not on either, then this message filter isolation doesn't exist. + if (!Utility.IsOSVistaOrNewer) + { + return HRESULT.S_FALSE; + } + + // If we're on Vista rather than Win7 then we can't use the Ex version of this function. + // The Ex version is preferred if possible because this results in process-wide modifications of the filter + // and is deprecated as of Win7. + if (!Utility.IsOSWindows7OrNewer) + { + // Note that the Win7 MSGFLT_ALLOW/DISALLOW enum values map to the Vista MSGFLT_ADD/REMOVE + ret = _ChangeWindowMessageFilter(message, action); + if (!ret) + { + return (HRESULT)Win32Error.GetLastError(); + } + return HRESULT.S_OK; + } + + var filterstruct = new CHANGEFILTERSTRUCT { cbSize = (uint)Marshal.SizeOf(typeof(CHANGEFILTERSTRUCT)) }; + ret = _ChangeWindowMessageFilterEx(hwnd, message, action, ref filterstruct); + if (!ret) + { + return (HRESULT)Win32Error.GetLastError(); + } + + filterInfo = filterstruct.ExtStatus; + return HRESULT.S_OK; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + public static extern CombineRgnResult CombineRgn(IntPtr hrgnDest, IntPtr hrgnSrc1, IntPtr hrgnSrc2, RGN fnCombineMode); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", EntryPoint = "CommandLineToArgvW", CharSet = CharSet.Unicode)] + private static extern IntPtr _CommandLineToArgvW([MarshalAs(UnmanagedType.LPWStr)] string cmdLine, out int numArgs); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string[] CommandLineToArgvW(string cmdLine) + { + IntPtr argv = IntPtr.Zero; + try + { + int numArgs = 0; + + argv = _CommandLineToArgvW(cmdLine, out numArgs); + if (argv == IntPtr.Zero) + { + throw new Win32Exception(); + } + var result = new string[numArgs]; + + for (int i = 0; i < numArgs; i++) + { + IntPtr currArg = Marshal.ReadIntPtr(argv, i * Marshal.SizeOf(typeof(IntPtr))); + result[i] = Marshal.PtrToStringUni(currArg); + } + + return result; + } + finally + { + + IntPtr p = _LocalFree(argv); + // Otherwise LocalFree failed. + Assert.AreEqual(IntPtr.Zero, p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateDIBSection", SetLastError = true)] + private static extern SafeHBITMAP _CreateDIBSection(SafeDC hdc, [In] ref BITMAPINFO bitmapInfo, int iUsage, [Out] out IntPtr ppvBits, IntPtr hSection, int dwOffset); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateDIBSection", SetLastError = true)] + private static extern SafeHBITMAP _CreateDIBSectionIntPtr(IntPtr hdc, [In] ref BITMAPINFO bitmapInfo, int iUsage, [Out] out IntPtr ppvBits, IntPtr hSection, int dwOffset); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static SafeHBITMAP CreateDIBSection(SafeDC hdc, ref BITMAPINFO bitmapInfo, out IntPtr ppvBits, IntPtr hSection, int dwOffset) + { + const int DIB_RGB_COLORS = 0; + SafeHBITMAP hBitmap = null; + if (hdc == null) + { + hBitmap = _CreateDIBSectionIntPtr(IntPtr.Zero, ref bitmapInfo, DIB_RGB_COLORS, out ppvBits, hSection, dwOffset); + } + else + { + hBitmap = _CreateDIBSection(hdc, ref bitmapInfo, DIB_RGB_COLORS, out ppvBits, hSection, dwOffset); + } + + if (hBitmap.IsInvalid) + { + HRESULT.ThrowLastError(); + } + + return hBitmap; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateRoundRectRgn", SetLastError = true)] + private static extern IntPtr _CreateRoundRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nWidthEllipse, int nHeightEllipse); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr CreateRoundRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nWidthEllipse, int nHeightEllipse) + { + IntPtr ret = _CreateRoundRectRgn(nLeftRect, nTopRect, nRightRect, nBottomRect, nWidthEllipse, nHeightEllipse); + if (IntPtr.Zero == ret) + { + throw new Win32Exception(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateRectRgn", SetLastError = true)] + private static extern IntPtr _CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect) + { + IntPtr ret = _CreateRectRgn(nLeftRect, nTopRect, nRightRect, nBottomRect); + if (IntPtr.Zero == ret) + { + throw new Win32Exception(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateRectRgnIndirect", SetLastError = true)] + private static extern IntPtr _CreateRectRgnIndirect([In] ref RECT lprc); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr CreateRectRgnIndirect(RECT lprc) + { + IntPtr ret = _CreateRectRgnIndirect(ref lprc); + if (IntPtr.Zero == ret) + { + throw new Win32Exception(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + public static extern IntPtr CreateSolidBrush(int crColor); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "CreateWindowExW")] + private static extern IntPtr _CreateWindowEx( + WS_EX dwExStyle, + [MarshalAs(UnmanagedType.LPWStr)] string lpClassName, + [MarshalAs(UnmanagedType.LPWStr)] string lpWindowName, + WS dwStyle, + int x, + int y, + int nWidth, + int nHeight, + IntPtr hWndParent, + IntPtr hMenu, + IntPtr hInstance, + IntPtr lpParam); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr CreateWindowEx( + WS_EX dwExStyle, + string lpClassName, + string lpWindowName, + WS dwStyle, + int x, + int y, + int nWidth, + int nHeight, + IntPtr hWndParent, + IntPtr hMenu, + IntPtr hInstance, + IntPtr lpParam) + { + IntPtr ret = _CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + if (IntPtr.Zero == ret) + { + HRESULT.ThrowLastError(); + } + + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "DefWindowProcW")] + public static extern IntPtr DefWindowProc(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DeleteObject(IntPtr hObject); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DestroyIcon(IntPtr handle); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DestroyWindow(IntPtr hwnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsWindow(IntPtr hwnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", PreserveSig = false)] + public static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS pMarInset); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", EntryPoint = "DwmIsCompositionEnabled", PreserveSig = false)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _DwmIsCompositionEnabled(); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", EntryPoint = "DwmGetColorizationColor", PreserveSig = true)] + private static extern HRESULT _DwmGetColorizationColor(out uint pcrColorization, [Out, MarshalAs(UnmanagedType.Bool)] out bool pfOpaqueBlend); + + public static bool DwmGetColorizationColor(out uint pcrColorization, out bool pfOpaqueBlend) + { + // Make this call safe to make on downlevel OSes... + if (Utility.IsOSVistaOrNewer && IsThemeActive()) + { + HRESULT hr = _DwmGetColorizationColor(out pcrColorization, out pfOpaqueBlend); + if (hr.Succeeded) + { + return true; + } + } + + // Default values. If for some reason the native DWM API fails it's never enough of a reason + // to bring down the app. Empirically it still sometimes returns errors even when the theme service is on. + // We'll still use the boolean return value to allow the caller to respond if they care. + pcrColorization = 0xFF000000; + pfOpaqueBlend = true; + + return false; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool DwmIsCompositionEnabled() + { + // Make this call safe to make on downlevel OSes... + if (!Utility.IsOSVistaOrNewer) + { + return false; + } + return _DwmIsCompositionEnabled(); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DwmDefWindowProc(IntPtr hwnd, WM msg, IntPtr wParam, IntPtr lParam, out IntPtr plResult); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", EntryPoint = "DwmSetWindowAttribute")] + private static extern void _DwmSetWindowAttribute(IntPtr hwnd, DWMWA dwAttribute, ref int pvAttribute, int cbAttribute); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void DwmSetWindowAttributeFlip3DPolicy(IntPtr hwnd, DWMFLIP3D flip3dPolicy) + { + Assert.IsTrue(Utility.IsOSVistaOrNewer); + var dwPolicy = (int)flip3dPolicy; + _DwmSetWindowAttribute(hwnd, DWMWA.FLIP3D_POLICY, ref dwPolicy, sizeof(int)); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void DwmSetWindowAttributeDisallowPeek(IntPtr hwnd, bool disallowPeek) + { + Assert.IsTrue(Utility.IsOSWindows7OrNewer); + int dwDisallow = (int)(disallowPeek ? Win32Value.TRUE : Win32Value.FALSE); + _DwmSetWindowAttribute(hwnd, DWMWA.DISALLOW_PEEK, ref dwDisallow, sizeof(int)); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "EnableMenuItem")] + private static extern int _EnableMenuItem(IntPtr hMenu, SC uIDEnableItem, MF uEnable); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static MF EnableMenuItem(IntPtr hMenu, SC uIDEnableItem, MF uEnable) + { + // Returns the previous state of the menu item, or -1 if the menu item does not exist. + int iRet = _EnableMenuItem(hMenu, uIDEnableItem, uEnable); + return (MF)iRet; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "RemoveMenu", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void RemoveMenu(IntPtr hMenu, SC uPosition, MF uFlags) + { + if (!_RemoveMenu(hMenu, (uint)uPosition, (uint)uFlags)) + { + throw new Win32Exception(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "DrawMenuBar", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _DrawMenuBar(IntPtr hWnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void DrawMenuBar(IntPtr hWnd) + { + if (!_DrawMenuBar(hWnd)) + { + throw new Win32Exception(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll")] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool FindClose(IntPtr handle); + + // Not shimming this SetLastError=true function because callers want to evaluate the reason for failure. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern SafeFindHandle FindFirstFileW(string lpFileName, [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_DATAW lpFindFileData); + + // Not shimming this SetLastError=true function because callers want to evaluate the reason for failure. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool FindNextFileW(SafeFindHandle hndFindFile, [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_DATAW lpFindFileData); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetClientRect", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _GetClientRect(IntPtr hwnd, [Out] out RECT lpRect); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static RECT GetClientRect(IntPtr hwnd) + { + RECT rc; + if (!_GetClientRect(hwnd, out rc)) + { + HRESULT.ThrowLastError(); + } + return rc; + } + + [DllImport("uxtheme.dll", EntryPoint="GetCurrentThemeName", CharSet = CharSet.Unicode)] + private static extern HRESULT _GetCurrentThemeName( + StringBuilder pszThemeFileName, + int dwMaxNameChars, + StringBuilder pszColorBuff, + int cchMaxColorChars, + StringBuilder pszSizeBuff, + int cchMaxSizeChars); + + public static void GetCurrentThemeName(out string themeFileName, out string color, out string size) + { + // Not expecting strings longer than MAX_PATH. We will return the error + var fileNameBuilder = new StringBuilder((int)Win32Value.MAX_PATH); + var colorBuilder = new StringBuilder((int)Win32Value.MAX_PATH); + var sizeBuilder = new StringBuilder((int)Win32Value.MAX_PATH); + + // This will throw if the theme service is not active (e.g. not UxTheme!IsThemeActive). + _GetCurrentThemeName(fileNameBuilder, fileNameBuilder.Capacity, + colorBuilder, colorBuilder.Capacity, + sizeBuilder, sizeBuilder.Capacity) + .ThrowIfFailed(); + + themeFileName = fileNameBuilder.ToString(); + color = colorBuilder.ToString(); + size = sizeBuilder.ToString(); + } + + [DllImport("uxtheme.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsThemeActive(); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [Obsolete("Use SafeDC.GetDC instead.", true)] + public static void GetDC() { } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + public static extern int GetDeviceCaps(SafeDC hdc, DeviceCap nIndex); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", EntryPoint = "GetModuleFileName", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern int _GetModuleFileName(IntPtr hModule, StringBuilder lpFilename, int nSize); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string GetModuleFileName(IntPtr hModule) + { + var buffer = new StringBuilder((int)Win32Value.MAX_PATH); + while (true) + { + int size = _GetModuleFileName(hModule, buffer, buffer.Capacity); + if (size == 0) + { + HRESULT.ThrowLastError(); + } + + // GetModuleFileName returns nSize when it's truncated but does NOT set the last error. + // MSDN documentation says this has changed in Windows 2000+. + if (size == buffer.Capacity) + { + // Enlarge the buffer and try again. + buffer.EnsureCapacity(buffer.Capacity * 2); + continue; + } + + return buffer.ToString(); + } + } + + [DllImport("kernel32.dll", EntryPoint = "GetModuleHandleW", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern IntPtr _GetModuleHandle([MarshalAs(UnmanagedType.LPWStr)] string lpModuleName); + + public static IntPtr GetModuleHandle(string lpModuleName) + { + IntPtr retPtr = _GetModuleHandle(lpModuleName); + if (retPtr == IntPtr.Zero) + { + HRESULT.ThrowLastError(); + } + return retPtr; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetMonitorInfo", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _GetMonitorInfo(IntPtr hMonitor, [In, Out] MONITORINFO lpmi); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static MONITORINFO GetMonitorInfo(IntPtr hMonitor) + { + var mi = new MONITORINFO(); + if (!_GetMonitorInfo(hMonitor, mi)) + { + throw new Win32Exception(); + } + return mi; + } + + [DllImport("gdi32.dll", EntryPoint = "GetStockObject", SetLastError = true)] + private static extern IntPtr _GetStockObject(StockObject fnObject); + + public static IntPtr GetStockObject(StockObject fnObject) + { + IntPtr retPtr = _GetStockObject(fnObject); + if (retPtr == null) + { + HRESULT.ThrowLastError(); + } + return retPtr; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern IntPtr GetSystemMenu(IntPtr hWnd, [MarshalAs(UnmanagedType.Bool)] bool bRevert); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern int GetSystemMetrics(SM nIndex); + + // This is aliased as a macro in 32bit Windows. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr GetWindowLongPtr(IntPtr hwnd, GWL nIndex) + { + IntPtr ret = IntPtr.Zero; + if (8 == IntPtr.Size) + { + ret = GetWindowLongPtr64(hwnd, nIndex); + } + else + { + ret = new IntPtr(GetWindowLongPtr32(hwnd, nIndex)); + } + if (IntPtr.Zero == ret) + { + throw new Win32Exception(); + } + return ret; + } + + /// + /// Sets attributes to control how visual styles are applied to a specified window. + /// + /// + /// Handle to a window to apply changes to. + /// + /// + /// Value of type WINDOWTHEMEATTRIBUTETYPE that specifies the type of attribute to set. + /// The value of this parameter determines the type of data that should be passed in the pvAttribute parameter. + /// Can be the following value: + /// WTA_NONCLIENT (Specifies non-client related attributes). + /// pvAttribute must be a pointer of type WTA_OPTIONS. + /// + /// + /// A pointer that specifies attributes to set. Type is determined by the value of the eAttribute value. + /// + /// + /// Specifies the size, in bytes, of the data pointed to by pvAttribute. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("uxtheme.dll", PreserveSig = false)] + public static extern void SetWindowThemeAttribute([In] IntPtr hwnd, [In] WINDOWTHEMEATTRIBUTETYPE eAttribute, [In] ref WTA_OPTIONS pvAttribute, [In] uint cbAttribute); + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetWindowLong", SetLastError = true)] + private static extern int GetWindowLongPtr32(IntPtr hWnd, GWL nIndex); + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", SetLastError = true)] + private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, GWL nIndex); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool GetWindowPlacement(IntPtr hwnd, WINDOWPLACEMENT lpwndpl); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static WINDOWPLACEMENT GetWindowPlacement(IntPtr hwnd) + { + WINDOWPLACEMENT wndpl = new WINDOWPLACEMENT(); + if (GetWindowPlacement(hwnd, wndpl)) + { + return wndpl; + } + throw new Win32Exception(); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetWindowRect", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _GetWindowRect(IntPtr hWnd, out RECT lpRect); + + public static RECT GetWindowRect(IntPtr hwnd) + { + RECT rc; + if (!_GetWindowRect(hwnd, out rc)) + { + HRESULT.ThrowLastError(); + } + return rc; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipCreateBitmapFromStream(IStream stream, out IntPtr bitmap); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipCreateHBITMAPFromBitmap(IntPtr bitmap, out IntPtr hbmReturn, Int32 background); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipCreateHICONFromBitmap(IntPtr bitmap, out IntPtr hbmReturn); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipDisposeImage(IntPtr image); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipImageForceValidation(IntPtr image); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdiplusStartup(out IntPtr token, StartupInput input, out StartupOutput output); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdiplusShutdown(IntPtr token); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsWindowVisible(IntPtr hwnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", EntryPoint = "LocalFree", SetLastError = true)] + private static extern IntPtr _LocalFree(IntPtr hMem); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "PostMessage", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _PostMessage(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void PostMessage(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam) + { + if (!_PostMessage(hWnd, Msg, wParam, lParam)) + { + throw new Win32Exception(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")] + private static extern short _RegisterClassEx([In] ref WNDCLASSEX lpwcx); + + // Note that this will throw HRESULT_FROM_WIN32(ERROR_CLASS_ALREADY_EXISTS) on duplicate registration. + // If needed, consider adding a Try* version of this function that returns the error code since that + // may be ignorable. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static short RegisterClassEx(ref WNDCLASSEX lpwcx) + { + short ret = _RegisterClassEx(ref lpwcx); + if (ret == 0) + { + HRESULT.ThrowLastError(); + } + + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "RegisterWindowMessage", SetLastError = true, CharSet = CharSet.Unicode)] + private static extern uint _RegisterWindowMessage([MarshalAs(UnmanagedType.LPWStr)] string lpString); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static WM RegisterWindowMessage(string lpString) + { + uint iRet = _RegisterWindowMessage(lpString); + if (iRet == 0) + { + HRESULT.ThrowLastError(); + } + return (WM)iRet; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetActiveWindow", SetLastError = true)] + private static extern IntPtr _SetActiveWindow(IntPtr hWnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SetActiveWindow(IntPtr hwnd) + { + Verify.IsNotDefault(hwnd, "hwnd"); + IntPtr ret = _SetActiveWindow(hwnd); + if (ret == IntPtr.Zero) + { + HRESULT.ThrowLastError(); + } + + return ret; + } + + // This is aliased as a macro in 32bit Windows. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SetClassLongPtr(IntPtr hwnd, GCLP nIndex, IntPtr dwNewLong) + { + if (8 == IntPtr.Size) + { + return SetClassLongPtr64(hwnd, nIndex, dwNewLong); + } + return new IntPtr(SetClassLongPtr32(hwnd, nIndex, dwNewLong.ToInt32())); + } + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetClassLong", SetLastError = true)] + private static extern int SetClassLongPtr32(IntPtr hWnd, GCLP nIndex, int dwNewLong); + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetClassLongPtr", SetLastError = true)] + private static extern IntPtr SetClassLongPtr64(IntPtr hWnd, GCLP nIndex, IntPtr dwNewLong); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", SetLastError = true)] + public static extern ErrorModes SetErrorMode(ErrorModes newMode); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "SetProcessWorkingSetSize")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SetProcessWorkingSetSize(IntPtr hProcess, IntPtr dwMinimiumWorkingSetSize, IntPtr dwMaximumWorkingSetSize); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SetProcessWorkingSetSize(IntPtr hProcess, int dwMinimumWorkingSetSize, int dwMaximumWorkingSetSize) + { + if (!_SetProcessWorkingSetSize(hProcess, new IntPtr(dwMinimumWorkingSetSize), new IntPtr(dwMaximumWorkingSetSize))) + { + throw new Win32Exception(); + } + } + + // This is aliased as a macro in 32bit Windows. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SetWindowLongPtr(IntPtr hwnd, GWL nIndex, IntPtr dwNewLong) + { + if (8 == IntPtr.Size) + { + return SetWindowLongPtr64(hwnd, nIndex, dwNewLong); + } + return new IntPtr(SetWindowLongPtr32(hwnd, nIndex, dwNewLong.ToInt32())); + } + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)] + private static extern int SetWindowLongPtr32(IntPtr hWnd, GWL nIndex, int dwNewLong); + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)] + private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, GWL nIndex, IntPtr dwNewLong); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetWindowRgn", SetLastError = true)] + private static extern int _SetWindowRgn(IntPtr hWnd, IntPtr hRgn, [MarshalAs(UnmanagedType.Bool)] bool bRedraw); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool bRedraw) + { + int err = _SetWindowRgn(hWnd, hRgn, bRedraw); + if (0 == err) + { + throw new Win32Exception(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetWindowPos", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags) + { + if (!_SetWindowPos(hWnd, hWndInsertAfter, x, y, cx, cy, uFlags)) + { + // If this fails it's never worth taking down the process. Let the caller deal with the error if they want. + return false; + } + + return true; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", SetLastError = false)] + public static extern Win32Error SHFileOperation(ref SHFILEOPSTRUCT lpFileOp); + + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ShowWindow(IntPtr hwnd, SW nCmdShow); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SystemParametersInfoW", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SystemParametersInfo_String(SPI uiAction, int uiParam, [MarshalAs(UnmanagedType.LPWStr)] string pvParam, SPIF fWinIni); + + /// Overload of SystemParametersInfo for getting and setting NONCLIENTMETRICS. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SystemParametersInfoW", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SystemParametersInfo_NONCLIENTMETRICS(SPI uiAction, int uiParam, [In, Out] ref NONCLIENTMETRICS pvParam, SPIF fWinIni); + + /// Overload of SystemParametersInfo for getting and setting HIGHCONTRAST. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SystemParametersInfoW", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SystemParametersInfo_HIGHCONTRAST(SPI uiAction, int uiParam, [In, Out] ref HIGHCONTRAST pvParam, SPIF fWinIni); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SystemParametersInfo(SPI uiAction, int uiParam, string pvParam, SPIF fWinIni) + { + if (!_SystemParametersInfo_String(uiAction, uiParam, pvParam, fWinIni)) + { + HRESULT.ThrowLastError(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static NONCLIENTMETRICS SystemParameterInfo_GetNONCLIENTMETRICS() + { + var metrics = Utility.IsOSVistaOrNewer + ? NONCLIENTMETRICS.VistaMetricsStruct + : NONCLIENTMETRICS.XPMetricsStruct; + + if (!_SystemParametersInfo_NONCLIENTMETRICS(SPI.GETNONCLIENTMETRICS, metrics.cbSize, ref metrics, SPIF.None)) + { + HRESULT.ThrowLastError(); + } + + return metrics; + } + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static HIGHCONTRAST SystemParameterInfo_GetHIGHCONTRAST() + { + var hc = new HIGHCONTRAST { cbSize = Marshal.SizeOf(typeof(HIGHCONTRAST)) }; + + if (!_SystemParametersInfo_HIGHCONTRAST(SPI.GETHIGHCONTRAST, hc.cbSize, ref hc, SPIF.None)) + { + HRESULT.ThrowLastError(); + } + + return hc; + } + + // This function is strange in that it returns a BOOL if TPM_RETURNCMD isn't specified, but otherwise the command Id. + // Currently it's only used with TPM_RETURNCMD, so making the signature match that. + [DllImport("user32.dll")] + public static extern uint TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "SelectObject", SetLastError = true)] + private static extern IntPtr _SelectObject(SafeDC hdc, IntPtr hgdiobj); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SelectObject(SafeDC hdc, IntPtr hgdiobj) + { + IntPtr ret = _SelectObject(hdc, hgdiobj); + if (ret == IntPtr.Zero) + { + HRESULT.ThrowLastError(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "SelectObject", SetLastError = true)] + private static extern IntPtr _SelectObjectSafeHBITMAP(SafeDC hdc, SafeHBITMAP hgdiobj); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SelectObject(SafeDC hdc, SafeHBITMAP hgdiobj) + { + IntPtr ret = _SelectObjectSafeHBITMAP(hdc, hgdiobj); + if (ret == IntPtr.Zero) + { + HRESULT.ThrowLastError(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true)] + public static extern int SendInput(int nInputs, ref INPUT pInputs, int cbSize); + + // Depending on the message, callers may want to call GetLastError based on the return value. + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr SendMessage(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "UnregisterClass", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _UnregisterClassAtom(IntPtr lpClassName, IntPtr hInstance); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "UnregisterClass", CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _UnregisterClassName(string lpClassName, IntPtr hInstance); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void UnregisterClass(short atom, IntPtr hinstance) + { + if (!_UnregisterClassAtom(new IntPtr(atom), hinstance)) + { + HRESULT.ThrowLastError(); + } + } + + public static void UnregisterClass(string lpClassName, IntPtr hInstance) + { + if (!_UnregisterClassName(lpClassName, hInstance)) + { + HRESULT.ThrowLastError(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "UpdateLayeredWindow")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _UpdateLayeredWindow( + IntPtr hwnd, + SafeDC hdcDst, + [In] ref POINT pptDst, + [In] ref SIZE psize, + SafeDC hdcSrc, + [In] ref POINT pptSrc, + int crKey, + ref BLENDFUNCTION pblend, + ULW dwFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "UpdateLayeredWindow")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _UpdateLayeredWindowIntPtr( + IntPtr hwnd, + IntPtr hdcDst, + IntPtr pptDst, + IntPtr psize, + IntPtr hdcSrc, + IntPtr pptSrc, + int crKey, + ref BLENDFUNCTION pblend, + ULW dwFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void UpdateLayeredWindow( + IntPtr hwnd, + SafeDC hdcDst, + ref POINT pptDst, + ref SIZE psize, + SafeDC hdcSrc, + ref POINT pptSrc, + int crKey, + ref BLENDFUNCTION pblend, + ULW dwFlags) + { + if (!_UpdateLayeredWindow(hwnd, hdcDst, ref pptDst, ref psize, hdcSrc, ref pptSrc, crKey, ref pblend, dwFlags)) + { + HRESULT.ThrowLastError(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void UpdateLayeredWindow( + IntPtr hwnd, + int crKey, + ref BLENDFUNCTION pblend, + ULW dwFlags) + { + if (!_UpdateLayeredWindowIntPtr(hwnd, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, crKey, ref pblend, dwFlags)) + { + HRESULT.ThrowLastError(); + } + } + + #region Win7 declarations + + [DllImport("shell32.dll", EntryPoint = "SHAddToRecentDocs")] + private static extern void _SHAddToRecentDocs_String(SHARD uFlags, [MarshalAs(UnmanagedType.LPWStr)] string pv); + + // This overload is required. There's a cast in the Shell code that causes the wrong vtbl to be used + // if we let the marshaller convert the parameter to an IUnknown. + [DllImport("shell32.dll", EntryPoint = "SHAddToRecentDocs")] + private static extern void _SHAddToRecentDocs_ShellLink(SHARD uFlags, IShellLinkW pv); + + public static void SHAddToRecentDocs(string path) + { + _SHAddToRecentDocs_String(SHARD.PATHW, path); + } + + // Win7 only. + public static void SHAddToRecentDocs(IShellLinkW shellLink) + { + _SHAddToRecentDocs_ShellLink(SHARD.LINK, shellLink); + } + + + //#define DWM_SIT_DISPLAYFRAME 0x00000001 // Display a window frame around the provided bitmap + + [DllImport("dwmapi.dll", EntryPoint="DwmGetCompositionTimingInfo")] + private static extern HRESULT _DwmGetCompositionTimingInfo(IntPtr hwnd, ref DWM_TIMING_INFO pTimingInfo); + + public static DWM_TIMING_INFO? DwmGetCompositionTimingInfo(IntPtr hwnd) + { + if (!Utility.IsOSVistaOrNewer) + { + // API was new to Vista. + return null; + } + + var dti = new DWM_TIMING_INFO { cbSize = Marshal.SizeOf(typeof(DWM_TIMING_INFO)) }; + HRESULT hr = _DwmGetCompositionTimingInfo(hwnd, ref dti); + if (hr == HRESULT.E_PENDING) + { + // The system isn't yet ready to respond. Return null rather than throw. + return null; + } + hr.ThrowIfFailed(); + + return dti; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", PreserveSig = false)] + public static extern void DwmInvalidateIconicBitmaps(IntPtr hwnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", PreserveSig = false)] + public static extern void DwmSetIconicThumbnail(IntPtr hwnd, IntPtr hbmp, DWM_SIT dwSITFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", PreserveSig = false)] + public static extern void DwmSetIconicLivePreviewBitmap(IntPtr hwnd, IntPtr hbmp, RefPOINT pptClient, DWM_SIT dwSITFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", PreserveSig = false)] + public static extern void SHGetItemFromDataObject(IDataObject pdtobj, DOGIF dwFlags, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object ppv); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", PreserveSig = false)] + public static extern HRESULT SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IBindCtx pbc, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object ppv); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool Shell_NotifyIcon(NIM dwMessage, [In] NOTIFYICONDATA lpdata); + + /// + /// Sets the User Model AppID for the current process, enabling Windows to retrieve this ID + /// + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", PreserveSig = false)] + public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID); + + /// + /// Retrieves the User Model AppID that has been explicitly set for the current process via SetCurrentProcessExplicitAppUserModelID + /// + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll")] + public static extern HRESULT GetCurrentProcessExplicitAppUserModelID([Out, MarshalAs(UnmanagedType.LPWStr)] out string AppID); + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/Standard/ShellProvider.cs b/Microsoft.Windows.Shell/Standard/ShellProvider.cs new file mode 100644 index 0000000..9738615 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/ShellProvider.cs @@ -0,0 +1,967 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Standard +{ + using System; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.ComTypes; + using System.Text; + + using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; + + #region Enums and Static Property Classes + + /// ShellItem attribute flags. SIATTRIBFLAGS_* + internal enum SIATTRIBFLAGS + { + AND = 0x00000001, + OR = 0x00000002, + APPCOMPAT = 0x00000003, + } + + internal enum APPDOCLISTTYPE + { + ADLT_RECENT = 0, // The recently used documents list + ADLT_FREQUENT, // The frequently used documents list + } + + /// + /// Flags for SetTabProperties. STPF_* + /// + /// The native enum was called STPFLAG. + [Flags] + internal enum STPF + { + NONE = 0x00000000, + USEAPPTHUMBNAILALWAYS = 0x00000001, + USEAPPTHUMBNAILWHENACTIVE = 0x00000002, + USEAPPPEEKALWAYS = 0x00000004, + USEAPPPEEKWHENACTIVE = 0x00000008, + } + + /// + /// Flags for Setting Taskbar Progress state. TBPF_* + /// + /// + /// The native enum was called TBPFLAG. + /// + internal enum TBPF + { + NOPROGRESS = 0x00000000, + INDETERMINATE = 0x00000001, + NORMAL = 0x00000002, + ERROR = 0x00000004, + PAUSED = 0x00000008, + } + + /// + /// THUMBBUTTON mask. THB_* + /// + [Flags] + internal enum THB : uint + { + BITMAP = 0x0001, + ICON = 0x0002, + TOOLTIP = 0x0004, + FLAGS = 0x0008, + } + + /// + /// THUMBBUTTON flags. THBF_* + /// + [Flags] + internal enum THBF : uint + { + ENABLED = 0x0000, + DISABLED = 0x0001, + DISMISSONCLICK = 0x0002, + NOBACKGROUND = 0x0004, + HIDDEN = 0x0008, + // Added post-beta + NONINTERACTIVE = 0x0010, + } + + /// + /// GetPropertyStoreFlags. GPS_*. + /// + /// + /// These are new for Vista, but are used in downlevel components + /// + internal enum GPS + { + // If no flags are specified (GPS_DEFAULT), a read-only property store is returned that includes properties for the file or item. + // In the case that the shell item is a file, the property store contains: + // 1. properties about the file from the file system + // 2. properties from the file itself provided by the file's property handler, unless that file is offline, + // see GPS_OPENSLOWITEM + // 3. if requested by the file's property handler and supported by the file system, properties stored in the + // alternate property store. + // + // Non-file shell items should return a similar read-only store + // + // Specifying other GPS_ flags modifies the store that is returned + DEFAULT = 0x00000000, + HANDLERPROPERTIESONLY = 0x00000001, // only include properties directly from the file's property handler + READWRITE = 0x00000002, // Writable stores will only include handler properties + TEMPORARY = 0x00000004, // A read/write store that only holds properties for the lifetime of the IShellItem object + FASTPROPERTIESONLY = 0x00000008, // do not include any properties from the file's property handler (because the file's property handler will hit the disk) + OPENSLOWITEM = 0x00000010, // include properties from a file's property handler, even if it means retrieving the file from offline storage. + DELAYCREATION = 0x00000020, // delay the creation of the file's property handler until those properties are read, written, or enumerated + BESTEFFORT = 0x00000040, // For readonly stores, succeed and return all available properties, even if one or more sources of properties fails. Not valid with GPS_READWRITE. + NO_OPLOCK = 0x00000080, // some data sources protect the read property store with an oplock, this disables that + MASK_VALID = 0x000000FF, + } + + /// + /// KNOWNDESTCATEGORY. KDC_* + /// + internal enum KDC + { + FREQUENT = 1, + RECENT, + } + + // IShellFolder::GetAttributesOf flags + [Flags] + internal enum SFGAO : uint + { + /// Objects can be copied + /// DROPEFFECT_COPY + CANCOPY = 0x1, + /// Objects can be moved + /// DROPEFFECT_MOVE + CANMOVE = 0x2, + /// Objects can be linked + /// + /// DROPEFFECT_LINK. + /// + /// If this bit is set on an item in the shell folder, a + /// 'Create Shortcut' menu item will be added to the File + /// menu and context menus for the item. If the user selects + /// that command, your IContextMenu::InvokeCommand() will be called + /// with 'link'. + /// That flag will also be used to determine if 'Create Shortcut' + /// should be added when the item in your folder is dragged to another + /// folder. + /// + CANLINK = 0x4, + /// supports BindToObject(IID_IStorage) + STORAGE = 0x00000008, + /// Objects can be renamed + CANRENAME = 0x00000010, + /// Objects can be deleted + CANDELETE = 0x00000020, + /// Objects have property sheets + HASPROPSHEET = 0x00000040, + + // unused = 0x00000080, + + /// Objects are drop target + DROPTARGET = 0x00000100, + CAPABILITYMASK = 0x00000177, + // unused = 0x00000200, + // unused = 0x00000400, + // unused = 0x00000800, + // unused = 0x00001000, + /// Object is encrypted (use alt color) + ENCRYPTED = 0x00002000, + /// 'Slow' object + ISSLOW = 0x00004000, + /// Ghosted icon + GHOSTED = 0x00008000, + /// Shortcut (link) + LINK = 0x00010000, + /// Shared + SHARE = 0x00020000, + /// Read-only + READONLY = 0x00040000, + /// Hidden object + HIDDEN = 0x00080000, + DISPLAYATTRMASK = 0x000FC000, + /// May contain children with SFGAO_FILESYSTEM + FILESYSANCESTOR = 0x10000000, + /// Support BindToObject(IID_IShellFolder) + FOLDER = 0x20000000, + /// Is a win32 file system object (file/folder/root) + FILESYSTEM = 0x40000000, + /// May contain children with SFGAO_FOLDER (may be slow) + HASSUBFOLDER = 0x80000000, + CONTENTSMASK = 0x80000000, + /// Invalidate cached information (may be slow) + VALIDATE = 0x01000000, + /// Is this removeable media? + REMOVABLE = 0x02000000, + /// Object is compressed (use alt color) + COMPRESSED = 0x04000000, + /// Supports IShellFolder, but only implements CreateViewObject() (non-folder view) + BROWSABLE = 0x08000000, + /// Is a non-enumerated object (should be hidden) + NONENUMERATED = 0x00100000, + /// Should show bold in explorer tree + NEWCONTENT = 0x00200000, + /// Obsolete + CANMONIKER = 0x00400000, + /// Obsolete + HASSTORAGE = 0x00400000, + /// Supports BindToObject(IID_IStream) + STREAM = 0x00400000, + /// May contain children with SFGAO_STORAGE or SFGAO_STREAM + STORAGEANCESTOR = 0x00800000, + /// For determining storage capabilities, ie for open/save semantics + STORAGECAPMASK = 0x70C50008, + /// + /// Attributes that are masked out for PKEY_SFGAOFlags because they are considered + /// to cause slow calculations or lack context + /// (SFGAO_VALIDATE | SFGAO_ISSLOW | SFGAO_HASSUBFOLDER and others) + /// + PKEYSFGAOMASK = 0x81044000, + } + + /// + /// IShellFolder::EnumObjects grfFlags bits. Also called SHCONT + /// + internal enum SHCONTF + { + CHECKING_FOR_CHILDREN = 0x0010, // hint that client is checking if (what) child items the folder contains - not all details (e.g. short file name) are needed + FOLDERS = 0x0020, // only want folders enumerated (SFGAO_FOLDER) + NONFOLDERS = 0x0040, // include non folders (items without SFGAO_FOLDER) + INCLUDEHIDDEN = 0x0080, // show items normally hidden (items with SFGAO_HIDDEN) + INIT_ON_FIRST_NEXT = 0x0100, // DEFUNCT - this is always assumed + NETPRINTERSRCH = 0x0200, // hint that client is looking for printers + SHAREABLE = 0x0400, // hint that client is looking sharable resources (local drives or hidden root shares) + STORAGE = 0x0800, // include all items with accessible storage and their ancestors + NAVIGATION_ENUM = 0x1000, // mark child folders to indicate that they should provide a "navigation" enumeration by default + FASTITEMS = 0x2000, // hint that client is only interested in items that can be enumerated quickly + FLATLIST = 0x4000, // enumerate items as flat list even if folder is stacked + ENABLE_ASYNC = 0x8000, // inform enumerator that client is listening for change notifications so enumerator does not need to be complete, items can be reported via change notifications + } + + /// + /// IShellFolder::GetDisplayNameOf/SetNameOf uFlags. Also called SHGDNF. + /// + /// + /// For compatibility with SIGDN, these bits must all sit in the LOW word. + /// + [Flags] + internal enum SHGDN + { + SHGDN_NORMAL = 0x0000, // default (display purpose) + SHGDN_INFOLDER = 0x0001, // displayed under a folder (relative) + SHGDN_FOREDITING = 0x1000, // for in-place editing + SHGDN_FORADDRESSBAR = 0x4000, // UI friendly parsing name (remove ugly stuff) + SHGDN_FORPARSING = 0x8000, // parsing name for ParseDisplayName() + } + + /// + /// SHELLITEMCOMPAREHINTF. SICHINT_*. + /// + internal enum SICHINT : uint + { + /// iOrder based on display in a folder view + DISPLAY = 0x00000000, + /// exact instance compare + ALLFIELDS = 0x80000000, + /// iOrder based on canonical name (better performance) + CANONICAL = 0x10000000, + TEST_FILESYSPATH_IF_NOT_EQUAL = 0x20000000, + }; + + /// + /// ShellItem enum. SIGDN_*. + /// + internal enum SIGDN : uint + { // lower word (& with 0xFFFF) + NORMALDISPLAY = 0x00000000, // SHGDN_NORMAL + PARENTRELATIVEPARSING = 0x80018001, // SHGDN_INFOLDER | SHGDN_FORPARSING + DESKTOPABSOLUTEPARSING = 0x80028000, // SHGDN_FORPARSING + PARENTRELATIVEEDITING = 0x80031001, // SHGDN_INFOLDER | SHGDN_FOREDITING + DESKTOPABSOLUTEEDITING = 0x8004c000, // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + FILESYSPATH = 0x80058000, // SHGDN_FORPARSING + URL = 0x80068000, // SHGDN_FORPARSING + PARENTRELATIVEFORADDRESSBAR = 0x8007c001, // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + PARENTRELATIVE = 0x80080001, // SHGDN_INFOLDER + } + + /// + /// STR_GPS_* + /// + /// + /// When requesting a property store through IShellFolder, you can specify the equivalent of + /// GPS_DEFAULT by passing in a null IBindCtx parameter. + /// + /// You can specify the equivalent of GPS_READWRITE by passing a mode of STGM_READWRITE | STGM_EXCLUSIVE + /// in the bind context + /// + /// Here are the string versions of GPS_ flags, passed to IShellFolder::BindToObject() via IBindCtx::RegisterObjectParam() + /// These flags are valid when requesting an IPropertySetStorage or IPropertyStore handler + /// + /// The meaning of these flags are described above. + /// + /// There is no STR_ equivalent for GPS_TEMPORARY because temporary property stores + /// are provided by IShellItem2 only -- not by the underlying IShellFolder. + /// + internal static class STR_GPS + { + public const string HANDLERPROPERTIESONLY = "GPS_HANDLERPROPERTIESONLY"; + public const string FASTPROPERTIESONLY = "GPS_FASTPROPERTIESONLY"; + public const string OPENSLOWITEM = "GPS_OPENSLOWITEM"; + public const string DELAYCREATION = "GPS_DELAYCREATION"; + public const string BESTEFFORT = "GPS_BESTEFFORT"; + public const string NO_OPLOCK = "GPS_NO_OPLOCK"; + } + + #endregion + + #region Structs + + [StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)] + internal struct THUMBBUTTON + { + /// + /// WPARAM value for a THUMBBUTTON being clicked. + /// + public const int THBN_CLICKED = 0x1800; + + public THB dwMask; + public uint iId; + public uint iBitmap; + public IntPtr hIcon; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string szTip; + public THBF dwFlags; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal struct PKEY + { + /// fmtid + private readonly Guid _fmtid; + /// pid + private readonly uint _pid; + + public PKEY(Guid fmtid, uint pid) + { + _fmtid = fmtid; + _pid = pid; + } + + /// PKEY_Title + public static readonly PKEY Title = new PKEY(new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9"), 2); + /// PKEY_AppUserModel_ID + public static readonly PKEY AppUserModel_ID = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 5); + /// PKEY_AppUserModel_IsDestListSeparator + public static readonly PKEY AppUserModel_IsDestListSeparator = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 6); + /// PKEY_AppUserModel_RelaunchCommand + public static readonly PKEY AppUserModel_RelaunchCommand = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 2); + /// PKEY_AppUserModel_RelaunchDisplayNameResource + public static readonly PKEY AppUserModel_RelaunchDisplayNameResource = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 4); + /// PKEY_AppUserModel_RelaunchIconResource + public static readonly PKEY AppUserModel_RelaunchIconResource = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 3); + } + + #endregion + + #region Interfaces + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.EnumIdList), + ] + internal interface IEnumIDList + { + [PreserveSig()] + HRESULT Next(uint celt, out IntPtr rgelt, out int pceltFetched); + [PreserveSig()] + HRESULT Skip(uint celt); + void Reset(); + void Clone([Out, MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenum); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.EnumObjects), + ] + internal interface IEnumObjects + { + //[local] + // This signature might not work... Hopefully don't need this interface though. + void Next(uint celt, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.IUnknown, IidParameterIndex = 1, SizeParamIndex = 0)] object[] rgelt, [Out] out uint pceltFetched); + + /* + [call_as(Next)] HRESULT RemoteNext( + [in] ULONG celt, + [in] REFIID riid, + [out, size_is(celt), length_is(*pceltFetched), iid_is(riid)] void **rgelt, + [out] ULONG *pceltFetched); + */ + + void Skip(uint celt); + + void Reset(); + + IEnumObjects Clone(); + } + + /// Unknown Object Array + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ObjectArray), + ] + internal interface IObjectArray + { + uint GetCount(); + [return: MarshalAs(UnmanagedType.IUnknown)] + object GetAt([In] uint uiIndex, [In] ref Guid riid); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ObjectArray), + ] + interface IObjectCollection : IObjectArray + { + #region IObjectArray redeclarations + new uint GetCount(); + [return: MarshalAs(UnmanagedType.IUnknown)] + new object GetAt([In] uint uiIndex, [In] ref Guid riid); + #endregion + + void AddObject([MarshalAs(UnmanagedType.IUnknown)] object punk); + void AddFromArray(IObjectArray poaSource); + void RemoveObjectAt(uint uiIndex); + void Clear(); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.PropertyStore) + ] + internal interface IPropertyStore + { + uint GetCount(); + PKEY GetAt(uint iProp); + void GetValue([In] ref PKEY pkey, [In, Out] PROPVARIANT pv); + void SetValue([In] ref PKEY pkey, PROPVARIANT pv); + void Commit(); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellFolder), + ] + internal interface IShellFolder + { + void ParseDisplayName( + [In] IntPtr hwnd, + [In] IBindCtx pbc, + [In, MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, + [In, Out] ref int pchEaten, + [Out] out IntPtr ppidl, + [In, Out] ref uint pdwAttributes); + + IEnumIDList EnumObjects( + [In] IntPtr hwnd, + [In] SHCONTF grfFlags); + + // returns an instance of a sub-folder which is specified by the IDList (pidl). + // IShellFolder or derived interfaces + [return: MarshalAs(UnmanagedType.Interface)] + object BindToObject( + [In] IntPtr pidl, + [In] IBindCtx pbc, + [In] ref Guid riid); + + // produces the same result as BindToObject() + [return: MarshalAs(UnmanagedType.Interface)] + object BindToStorage([In] IntPtr pidl, [In] IBindCtx pbc, [In] ref Guid riid); + + // compares two IDLists and returns the result. The shell + // explorer always passes 0 as lParam, which indicates 'sort by name'. + // It should return 0 (as CODE of the scode), if two id indicates the + // same object; negative value if pidl1 should be placed before pidl2; + // positive value if pidl2 should be placed before pidl1. + // use the macro ResultFromShort() to extract the result comparison + // it deals with the casting and type conversion issues for you + [PreserveSig] + HRESULT CompareIDs([In] IntPtr lParam, [In] IntPtr pidl1, [In] IntPtr pidl2); + + // creates a view object of the folder itself. The view + // object is a difference instance from the shell folder object. + // 'hwndOwner' can be used as the owner window of its dialog box or + // menu during the lifetime of the view object. + // This member function should always create a new + // instance which has only one reference count. The explorer may create + // more than one instances of view object from one shell folder object + // and treat them as separate instances. + // returns IShellView derived interface + [return: MarshalAs(UnmanagedType.Interface)] + object CreateViewObject([In] IntPtr hwndOwner, [In] ref Guid riid); + + // returns the attributes of specified objects in that + // folder. 'cidl' and 'apidl' specifies objects. 'apidl' contains only + // simple IDLists. The explorer initializes *prgfInOut with a set of + // flags to be evaluated. The shell folder may optimize the operation + // by not returning unspecified flags. + void GetAttributesOf( + [In] uint cidl, + [In] IntPtr apidl, + [In, Out] ref SFGAO rgfInOut); + + // creates a UI object to be used for specified objects. + // The shell explorer passes either IID_IDataObject (for transfer operation) + // or IID_IContextMenu (for context menu operation) as riid + // and many other interfaces + [return: MarshalAs(UnmanagedType.Interface)] + object GetUIObjectOf( + [In] IntPtr hwndOwner, + [In] uint cidl, + [In, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.SysInt, SizeParamIndex = 2)] IntPtr apidl, + [In] ref Guid riid, + [In, Out] ref uint rgfReserved); + + // returns the display name of the specified object. + // If the ID contains the display name (in the locale character set), + // it returns the offset to the name. Otherwise, it returns a pointer + // to the display name string (UNICODE), which is allocated by the + // task allocator, or fills in a buffer. + // use the helper APIS StrRetToStr() or StrRetToBuf() to deal with the different + // forms of the STRRET structure + void GetDisplayNameOf([In] IntPtr pidl, [In] SHGDN uFlags, [Out] out IntPtr pName); + + // sets the display name of the specified object. + // If it changes the ID as well, it returns the new ID which is + // alocated by the task allocator. + void SetNameOf([In] IntPtr hwnd, + [In] IntPtr pidl, + [In, MarshalAs(UnmanagedType.LPWStr)] string pszName, + [In] SHGDN uFlags, + [Out] out IntPtr ppidlOut); + } + + /// + /// Shell Namespace helper + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellItem), + ] + internal interface IShellItem + { + [return: MarshalAs(UnmanagedType.Interface)] + object BindToHandler(IBindCtx pbc, [In] ref Guid bhid, [In] ref Guid riid); + + IShellItem GetParent(); + + [return: MarshalAs(UnmanagedType.LPWStr)] + string GetDisplayName(SIGDN sigdnName); + + SFGAO GetAttributes(SFGAO sfgaoMask); + + int Compare(IShellItem psi, SICHINT hint); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellItemArray), + ] + internal interface IShellItemArray + { + [return: MarshalAs(UnmanagedType.Interface)] + object BindToHandler(IBindCtx pbc, [In] ref Guid rbhid, [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyStore(int flags, [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyDescriptionList([In] ref PKEY keyType, [In] ref Guid riid); + + uint GetAttributes(SIATTRIBFLAGS dwAttribFlags, uint sfgaoMask); + + uint GetCount(); + + IShellItem GetItemAt(uint dwIndex); + + [return: MarshalAs(UnmanagedType.Interface)] + object EnumItems(); + } + + /// + /// Shell Namespace helper 2 + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellItem2), + ] + interface IShellItem2 : IShellItem + { + #region IShellItem redeclarations + [return: MarshalAs(UnmanagedType.Interface)] + new object BindToHandler([In] IBindCtx pbc, [In] ref Guid bhid, [In] ref Guid riid); + new IShellItem GetParent(); + [return: MarshalAs(UnmanagedType.LPWStr)] + new string GetDisplayName(SIGDN sigdnName); + new SFGAO GetAttributes(SFGAO sfgaoMask); + new int Compare(IShellItem psi, SICHINT hint); + #endregion + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyStore( + GPS flags, + [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyStoreWithCreateObject( + GPS flags, + [MarshalAs(UnmanagedType.IUnknown)] object punkCreateObject, // factory for low-rights creation of type ICreateObject + [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyStoreForKeys( + IntPtr rgKeys, + uint cKeys, + GPS flags, + [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyDescriptionList( + IntPtr keyType, + [In] ref Guid riid); + + // Ensures any cached information in this item is up to date, or returns __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) if the item does not exist. + void Update(IBindCtx pbc); + + PROPVARIANT GetProperty(IntPtr key); + + Guid GetCLSID(IntPtr key); + + FILETIME GetFileTime(IntPtr key); + + int GetInt32(IntPtr key); + + [return: MarshalAs(UnmanagedType.LPWStr)] + string GetString(IntPtr key); + + uint GetUInt32(IntPtr key); + + ulong GetUInt64(IntPtr key); + + [return: MarshalAs(UnmanagedType.Bool)] + void GetBool(IntPtr key); + } + + [ + ComImport, + InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellLink), + ] + internal interface IShellLinkW + { + void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, [In, Out] WIN32_FIND_DATAW pfd, SLGP fFlags); + void GetIDList(out IntPtr ppidl); + void SetIDList(IntPtr pidl); + void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxName); + void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); + void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); + void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); + void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); + void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); + short GetHotKey(); + void SetHotKey(short wHotKey); + uint GetShowCmd(); + void SetShowCmd(uint iShowCmd); + void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon); + void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); + void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved); + void Resolve(IntPtr hwnd, uint fFlags); + void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.TaskbarList), + ] + internal interface ITaskbarList + { + /// + /// This function must be called first to validate use of other members. + /// + void HrInit(); + + /// + /// This function adds a tab for hwnd to the taskbar. + /// + /// The HWND for which to add the tab. + void AddTab(IntPtr hwnd); + + /// + /// This function deletes a tab for hwnd from the taskbar. + /// + /// The HWND for which the tab is to be deleted. + void DeleteTab(IntPtr hwnd); + + /// + /// This function activates the tab associated with hwnd on the taskbar. + /// + /// The HWND for which the tab is to be actuvated. + void ActivateTab(IntPtr hwnd); + + /// + /// This function marks hwnd in the taskbar as the active tab. + /// + /// The HWND to activate. + void SetActiveAlt(IntPtr hwnd); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.TaskbarList2), + ] + internal interface ITaskbarList2 : ITaskbarList + { + #region ITaskbarList redeclaration + new void HrInit(); + new void AddTab(IntPtr hwnd); + new void DeleteTab(IntPtr hwnd); + new void ActivateTab(IntPtr hwnd); + new void SetActiveAlt(IntPtr hwnd); + #endregion + + /// + /// Marks a window as full-screen. + /// + /// The handle of the window to be marked. + /// A Boolean value marking the desired full-screen status of the window. + /// + /// Setting the value of fFullscreen to true, the Shell treats this window as a full-screen window, and the taskbar + /// is moved to the bottom of the z-order when this window is active. Setting the value of fFullscreen to false + /// removes the full-screen marking, but does not cause the Shell to treat the window as though it were + /// definitely not full-screen. With a false fFullscreen value, the Shell depends on its automatic detection facility + /// to specify how the window should be treated, possibly still flagging the window as full-screen. + /// + void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); + } + + // Used to remove items from the automatic destination lists created when apps or the system call SHAddToRecentDocs to report usage of a document. + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ApplicationDestinations) + ] + internal interface IApplicationDestinations + { + // Set the App User Model ID for the application removing destinations from its list. If an AppID is not provided + // via this method, the system will use a heuristically determined ID. This method must be called before + // RemoveDestination or RemoveAllDestinations. + void SetAppID([In, MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + + // Remove an IShellItem or an IShellLink from the automatic destination list + void RemoveDestination([MarshalAs(UnmanagedType.IUnknown)] object punk); + + // Clear the frequent and recent destination lists for this application. + void RemoveAllDestinations(); + } + + /// + /// Allows an application to retrieve the most recent and frequent documents opened in that app, as reported via SHAddToRecentDocs + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ApplicationDocumentLists) + ] + internal interface IApplicationDocumentLists + { + /// + /// Set the App User Model ID for the application retrieving this list. If an AppID is not provided via this method, + /// the system will use a heuristically determined ID. This method must be called before GetList. + /// + /// App Id. + void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + + /// + /// Retrieve an IEnumObjects or IObjectArray for IShellItems and/or IShellLinks. + /// Items may appear in both the frequent and recent lists. + /// + /// + /// + [return: MarshalAs(UnmanagedType.IUnknown)] + object GetList([In] APPDOCLISTTYPE listtype, [In] uint cItemsDesired, [In] ref Guid riid); + } + + // Custom Destination List + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.CustomDestinationList) + ] + internal interface ICustomDestinationList + { + void SetAppID([In, MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + + // Retrieve IObjectArray of IShellItems or IShellLinks that represent removed destinations + [return: MarshalAs(UnmanagedType.Interface)] + object BeginList(out uint pcMaxSlots, [In] ref Guid riid); + + // PreserveSig because this will return custom errors when attempting to add unregistered ShellItems. + // Can't readily detect that case without just trying to append it. + [PreserveSig] + HRESULT AppendCategory([MarshalAs(UnmanagedType.LPWStr)] string pszCategory, IObjectArray poa); + void AppendKnownCategory(KDC category); + [PreserveSig] + HRESULT AddUserTasks(IObjectArray poa); + void CommitList(); + + // Retrieve IObjectCollection of IShellItems + [return: MarshalAs(UnmanagedType.Interface)] + object GetRemovedDestinations([In] ref Guid riid); + void DeleteList([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + void AbortList(); + } + + /// + /// Provides access to the App User Model ID on objects supporting this value. + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ObjectWithAppUserModelId) + ] + internal interface IObjectWithAppUserModelId + { + void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + [return: MarshalAs(UnmanagedType.LPWStr)] + string GetAppID(); + }; + + /// + /// Provides access to the ProgID associated with an object + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ObjectWithProgId) + ] + internal interface IObjectWithProgId + { + void SetProgID([MarshalAs(UnmanagedType.LPWStr)] string pszProgID); + [return: MarshalAs(UnmanagedType.LPWStr)] + string GetProgID(); + }; + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.TaskbarList3), + ] + internal interface ITaskbarList3 : ITaskbarList2 + { + #region ITaskbarList2 redeclaration + + #region ITaskbarList redeclaration + new void HrInit(); + new void AddTab(IntPtr hwnd); + new void DeleteTab(IntPtr hwnd); + new void ActivateTab(IntPtr hwnd); + new void SetActiveAlt(IntPtr hwnd); + #endregion + + new void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); + + #endregion + + [PreserveSig] + HRESULT SetProgressValue(IntPtr hwnd, ulong ullCompleted, ulong ullTotal); + + [PreserveSig] + HRESULT SetProgressState(IntPtr hwnd, TBPF tbpFlags); + + [PreserveSig] + HRESULT RegisterTab(IntPtr hwndTab, IntPtr hwndMDI); + + [PreserveSig] + HRESULT UnregisterTab(IntPtr hwndTab); + + [PreserveSig] + HRESULT SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore); + + [PreserveSig] + HRESULT SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, uint dwReserved); + + [PreserveSig] + HRESULT ThumbBarAddButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); + + [PreserveSig] + HRESULT ThumbBarUpdateButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); + + [PreserveSig] + HRESULT ThumbBarSetImageList(IntPtr hwnd, [MarshalAs(UnmanagedType.IUnknown)] object himl); + + [PreserveSig] + HRESULT SetOverlayIcon(IntPtr hwnd, IntPtr hIcon, [MarshalAs(UnmanagedType.LPWStr)] string pszDescription); + + [PreserveSig] + HRESULT SetThumbnailTooltip(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszTip); + + // Using RefRECT to making passing NULL possible. Removes clipping from the HWND. + [PreserveSig] + HRESULT SetThumbnailClip(IntPtr hwnd, RefRECT prcClip); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.TaskbarList3), + ] + internal interface ITaskbarList4 : ITaskbarList3 + { + #region ITaskbarList3 redeclaration + + #region ITaskbarList2 redeclaration + + #region ITaskbarList redeclaration + new void HrInit(); + new void AddTab(IntPtr hwnd); + new void DeleteTab(IntPtr hwnd); + new void ActivateTab(IntPtr hwnd); + new void SetActiveAlt(IntPtr hwnd); + #endregion + + new void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); + + #endregion + + [PreserveSig] new HRESULT SetProgressValue(IntPtr hwnd, ulong ullCompleted, ulong ullTotal); + [PreserveSig] new HRESULT SetProgressState(IntPtr hwnd, TBPF tbpFlags); + [PreserveSig] new HRESULT RegisterTab(IntPtr hwndTab, IntPtr hwndMDI); + [PreserveSig] new HRESULT UnregisterTab(IntPtr hwndTab); + [PreserveSig] new HRESULT SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore); + [PreserveSig] new HRESULT SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, uint dwReserved); + [PreserveSig] new HRESULT ThumbBarAddButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); + [PreserveSig] new HRESULT ThumbBarUpdateButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); + [PreserveSig] new HRESULT ThumbBarSetImageList(IntPtr hwnd, [MarshalAs(UnmanagedType.IUnknown)] object himl); + [PreserveSig] new HRESULT SetOverlayIcon(IntPtr hwnd, IntPtr hIcon, [MarshalAs(UnmanagedType.LPWStr)] string pszDescription); + [PreserveSig] new HRESULT SetThumbnailTooltip(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszTip); + // Using RefRECT to making passing NULL possible. Removes clipping from the HWND. + [PreserveSig] new HRESULT SetThumbnailClip(IntPtr hwnd, RefRECT prcClip); + + #endregion + + void SetTabProperties(IntPtr hwndTab, STPF stpFlags); + } + + #endregion +} diff --git a/Microsoft.Windows.Shell/Standard/StreamHelper.cs b/Microsoft.Windows.Shell/Standard/StreamHelper.cs new file mode 100644 index 0000000..a5d0355 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/StreamHelper.cs @@ -0,0 +1,341 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Standard +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.ComTypes; + + // disambiguate with System.Runtime.InteropServices.STATSTG + using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG; + + // All these methods return void. Does the standard marshaller convert them to HRESULTs? + /// + /// Wraps a managed stream instance into an interface pointer consumable by COM. + /// + internal sealed class ManagedIStream : IStream, IDisposable + { + private const int STGTY_STREAM = 2; + private const int STGM_READWRITE = 2; + private const int LOCK_EXCLUSIVE = 2; + + private Stream _source; + + /// + /// Initializes a new instance of the ManagedIStream class with the specified managed Stream object. + /// + /// + /// The stream that this IStream reference is wrapping. + /// + public ManagedIStream(Stream source) + { + Verify.IsNotNull(source, "source"); + _source = source; + } + + private void _Validate() + { + if (null == _source) + { + throw new ObjectDisposedException("this"); + } + } + + // Comments are taken from MSDN IStream documentation. + #region IStream Members + + /// + /// Creates a new stream object with its own seek pointer that + /// references the same bytes as the original stream. + /// + /// + /// When this method returns, contains the new stream object. This parameter is passed uninitialized. + /// + /// + /// For more information, see the existing documentation for IStream::Clone in the MSDN library. + /// This class doesn't implement Clone. A COMException is thrown if it is used. + /// + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)")] + [Obsolete("The method is not implemented", true)] + public void Clone(out IStream ppstm) + { + ppstm = null; + HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); + } + + /// + /// Ensures that any changes made to a stream object that is open in transacted + /// mode are reflected in the parent storage. + /// + /// + /// A value that controls how the changes for the stream object are committed. + /// + /// + /// For more information, see the existing documentation for IStream::Commit in the MSDN library. + /// + public void Commit(int grfCommitFlags) + { + _Validate(); + _source.Flush(); + } + + /// + /// Copies a specified number of bytes from the current seek pointer in the + /// stream to the current seek pointer in another stream. + /// + /// + /// A reference to the destination stream. + /// + /// + /// The number of bytes to copy from the source stream. + /// + /// + /// On successful return, contains the actual number of bytes read from the source. + /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written + /// to this parameter on success.) + /// + /// + /// On successful return, contains the actual number of bytes written to the destination. + /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written + /// to this parameter on success.) + /// + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten) + { + Verify.IsNotNull(pstm, "pstm"); + + _Validate(); + + // Reasonbly sized buffer, don't try to copy large streams in bulk. + var buffer = new byte[4096]; + long cbWritten = 0; + + while (cbWritten < cb) + { + int cbRead = _source.Read(buffer, 0, buffer.Length); + if (0 == cbRead) + { + break; + } + + // COM documentation is a bit vague here whether NULL is valid for the third parameter. + // Going to assume it is, as most implementations I've seen treat it as optional. + // It's possible this will break on some IStream implementations. + pstm.Write(buffer, cbRead, IntPtr.Zero); + cbWritten += cbRead; + } + + if (IntPtr.Zero != pcbRead) + { + Marshal.WriteInt64(pcbRead, cbWritten); + } + + if (IntPtr.Zero != pcbWritten) + { + Marshal.WriteInt64(pcbWritten, cbWritten); + } + } + + /// + /// Restricts access to a specified range of bytes in the stream. + /// + /// + /// The byte offset for the beginning of the range. + /// + /// + /// The length of the range, in bytes, to restrict. + /// + /// + /// The requested restrictions on accessing the range. + /// + /// + /// For more information, see the existing documentation for IStream::LockRegion in the MSDN library. + /// This class doesn't implement LockRegion. A COMException is thrown if it is used. + /// + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)"), Obsolete("The method is not implemented", true)] + public void LockRegion(long libOffset, long cb, int dwLockType) + { + HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); + } + + /// + /// Reads a specified number of bytes from the stream object into memory starting at the current seek pointer. + /// + /// + /// When this method returns, contains the data read from the stream. This parameter is passed uninitialized. + /// + /// + /// The number of bytes to read from the stream object. + /// + /// + /// A pointer to a ULONG variable that receives the actual number of bytes read from the stream object. + /// + /// + /// For more information, see the existing documentation for ISequentialStream::Read in the MSDN library. + /// + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void Read(byte[] pv, int cb, IntPtr pcbRead) + { + _Validate(); + + int cbRead = _source.Read(pv, 0, cb); + + if (IntPtr.Zero != pcbRead) + { + Marshal.WriteInt32(pcbRead, cbRead); + } + } + + + /// + /// Discards all changes that have been made to a transacted stream since the last Commit call. + /// + /// + /// This class doesn't implement Revert. A COMException is thrown if it is used. + /// + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)"), Obsolete("The method is not implemented", true)] + public void Revert() + { + HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); + } + + /// + /// Changes the seek pointer to a new location relative to the beginning of the + /// stream, to the end of the stream, or to the current seek pointer. + /// + /// + /// The displacement to add to dwOrigin. + /// + /// + /// The origin of the seek. The origin can be the beginning of the file, the current seek pointer, or the end of the file. + /// + /// + /// On successful return, contains the offset of the seek pointer from the beginning of the stream. + /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written + /// to this parameter on success.) + /// + /// + /// For more information, see the existing documentation for IStream::Seek in the MSDN library. + /// + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition) + { + _Validate(); + + long position = _source.Seek(dlibMove, (SeekOrigin)dwOrigin); + + if (IntPtr.Zero != plibNewPosition) + { + Marshal.WriteInt64(plibNewPosition, position); + } + } + + /// + /// Changes the size of the stream object. + /// + /// + /// The new size of the stream as a number of bytes. + /// + /// + /// For more information, see the existing documentation for IStream::SetSize in the MSDN library. + /// + public void SetSize(long libNewSize) + { + _Validate(); + _source.SetLength(libNewSize); + } + + /// + /// Retrieves the STATSTG structure for this stream. + /// + /// + /// When this method returns, contains a STATSTG structure that describes this stream object. + /// This parameter is passed uninitialized. + /// + /// + /// Members in the STATSTG structure that this method does not return, thus saving some memory allocation operations. + /// + public void Stat(out STATSTG pstatstg, int grfStatFlag) + { + pstatstg = default(STATSTG); + _Validate(); + + pstatstg.type = STGTY_STREAM; + pstatstg.cbSize = _source.Length; + pstatstg.grfMode = STGM_READWRITE; + pstatstg.grfLocksSupported = LOCK_EXCLUSIVE; + } + + /// + /// Removes the access restriction on a range of bytes previously restricted with the LockRegion method. + /// + /// The byte offset for the beginning of the range. + /// + /// + /// The length, in bytes, of the range to restrict. + /// + /// + /// The access restrictions previously placed on the range. + /// + /// + /// For more information, see the existing documentation for IStream::UnlockRegion in the MSDN library. + /// This class doesn't implement UnlockRegion. A COMException is thrown if it is used. + /// + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)")] + [Obsolete("The method is not implemented", true)] + public void UnlockRegion(long libOffset, long cb, int dwLockType) + { + HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); + } + + /// + /// Writes a specified number of bytes into the stream object starting at the current seek pointer. + /// + /// + /// The buffer to write this stream to. + /// + /// + /// The number of bytes to write to the stream. + /// + /// + /// On successful return, contains the actual number of bytes written to the stream object. + /// If the caller sets this pointer to null, this method does not provide the actual number + /// of bytes written. + /// + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void Write(byte[] pv, int cb, IntPtr pcbWritten) + { + _Validate(); + + _source.Write(pv, 0, cb); + + if (IntPtr.Zero != pcbWritten) + { + Marshal.WriteInt32(pcbWritten, cb); + } + } + + #endregion + + #region IDisposable Members + + /// + /// Releases resources controlled by this object. + /// + /// + /// Dispose can be called multiple times, but trying to use the object + /// after it has been disposed will generally throw ObjectDisposedExceptions. + /// + public void Dispose() + { + _source = null; + } + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/Standard/Utilities.cs b/Microsoft.Windows.Shell/Standard/Utilities.cs new file mode 100644 index 0000000..af68855 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/Utilities.cs @@ -0,0 +1,1037 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +// This file contains general utilities to aid in development. +// Classes here generally shouldn't be exposed publicly since +// they're not particular to any library functionality. +// Because the classes here are internal, it's likely this file +// might be included in multiple assemblies. +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.IO; + using System.Reflection; + using System.Runtime.InteropServices; + using System.Security.Cryptography; + using System.Text; + using System.Windows; + using System.Windows.Media; + using System.Windows.Media.Imaging; + + internal static partial class Utility + { + private static readonly Version _osVersion = Environment.OSVersion.Version; + private static readonly Version _presentationFrameworkVersion = Assembly.GetAssembly(typeof(Window)).GetName().Version; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static bool _MemCmp(IntPtr left, IntPtr right, long cb) + { + int offset = 0; + + for (; offset < (cb - sizeof(Int64)); offset += sizeof(Int64)) + { + Int64 left64 = Marshal.ReadInt64(left, offset); + Int64 right64 = Marshal.ReadInt64(right, offset); + + if (left64 != right64) + { + return false; + } + } + + for (; offset < cb; offset += sizeof(byte)) + { + byte left8 = Marshal.ReadByte(left, offset); + byte right8 = Marshal.ReadByte(right, offset); + + if (left8 != right8) + { + return false; + } + } + + return true; + } + + /// The native RGB macro. + /// + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int RGB(Color c) + { + return c.R | (c.G << 8) | (c.B << 16); + } + + /// Convert a native integer that represent a color with an alpha channel into a Color struct. + /// The integer that represents the color. Its bits are of the format 0xAARRGGBB. + /// A Color representation of the parameter. + public static Color ColorFromArgbDword(uint color) + { + return Color.FromArgb( + (byte)((color & 0xFF000000) >> 24), + (byte)((color & 0x00FF0000) >> 16), + (byte)((color & 0x0000FF00) >> 8), + (byte)((color & 0x000000FF) >> 0)); + } + + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int GET_X_LPARAM(IntPtr lParam) + { + return LOWORD(lParam.ToInt32()); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int GET_Y_LPARAM(IntPtr lParam) + { + return HIWORD(lParam.ToInt32()); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int HIWORD(int i) + { + return (short)(i >> 16); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int LOWORD(int i) + { + return (short)(i & 0xFFFF); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static bool AreStreamsEqual(Stream left, Stream right) + { + if (null == left) + { + return right == null; + } + if (null == right) + { + return false; + } + + if (!left.CanRead || !right.CanRead) + { + throw new NotSupportedException("The streams can't be read for comparison"); + } + + if (left.Length != right.Length) + { + return false; + } + + var length = (int)left.Length; + + // seek to beginning + left.Position = 0; + right.Position = 0; + + // total bytes read + int totalReadLeft = 0; + int totalReadRight = 0; + + // bytes read on this iteration + int cbReadLeft = 0; + int cbReadRight = 0; + + // where to store the read data + var leftBuffer = new byte[512]; + var rightBuffer = new byte[512]; + + // pin the left buffer + GCHandle handleLeft = GCHandle.Alloc(leftBuffer, GCHandleType.Pinned); + IntPtr ptrLeft = handleLeft.AddrOfPinnedObject(); + + // pin the right buffer + GCHandle handleRight = GCHandle.Alloc(rightBuffer, GCHandleType.Pinned); + IntPtr ptrRight = handleRight.AddrOfPinnedObject(); + + try + { + while (totalReadLeft < length) + { + Assert.AreEqual(totalReadLeft, totalReadRight); + + cbReadLeft = left.Read(leftBuffer, 0, leftBuffer.Length); + cbReadRight = right.Read(rightBuffer, 0, rightBuffer.Length); + + // verify the contents are an exact match + if (cbReadLeft != cbReadRight) + { + return false; + } + + if (!_MemCmp(ptrLeft, ptrRight, cbReadLeft)) + { + return false; + } + + totalReadLeft += cbReadLeft; + totalReadRight += cbReadRight; + } + + Assert.AreEqual(cbReadLeft, cbReadRight); + Assert.AreEqual(totalReadLeft, totalReadRight); + Assert.AreEqual(length, totalReadLeft); + + return true; + } + finally + { + handleLeft.Free(); + handleRight.Free(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool GuidTryParse(string guidString, out Guid guid) + { + Verify.IsNeitherNullNorEmpty(guidString, "guidString"); + + try + { + guid = new Guid(guidString); + return true; + } + catch (FormatException) + { + } + catch (OverflowException) + { + } + // Doesn't seem to be a valid guid. + guid = default(Guid); + return false; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFlagSet(int value, int mask) + { + return 0 != (value & mask); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFlagSet(uint value, uint mask) + { + return 0 != (value & mask); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFlagSet(long value, long mask) + { + return 0 != (value & mask); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFlagSet(ulong value, ulong mask) + { + return 0 != (value & mask); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsOSVistaOrNewer + { + get { return _osVersion >= new Version(6, 0); } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsOSWindows7OrNewer + { + get { return _osVersion >= new Version(6, 1); } + } + + /// + /// Is this using WPF4? + /// + /// + /// There are a few specific bugs in Window in 3.5SP1 and below that require workarounds + /// when handling WM_NCCALCSIZE on the HWND. + /// + public static bool IsPresentationFrameworkVersionLessThan4 + { + get { return _presentationFrameworkVersion < new Version(4, 0); } + } + + // Caller is responsible for destroying the HICON + // Caller is responsible to ensure that GDI+ has been initialized. + [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr GenerateHICON(ImageSource image, Size dimensions) + { + if (image == null) + { + return IntPtr.Zero; + } + + // If we're getting this from a ".ico" resource, then it comes through as a BitmapFrame. + // We can use leverage this as a shortcut to get the right 16x16 representation + // because DrawImage doesn't do that for us. + var bf = image as BitmapFrame; + if (bf != null) + { + bf = GetBestMatch(bf.Decoder.Frames, (int)dimensions.Width, (int)dimensions.Height); + } + else + { + // Constrain the dimensions based on the aspect ratio. + var drawingDimensions = new Rect(0, 0, dimensions.Width, dimensions.Height); + + // There's no reason to assume that the requested image dimensions are square. + double renderRatio = dimensions.Width / dimensions.Height; + double aspectRatio = image.Width / image.Height; + + // If it's smaller than the requested size, then place it in the middle and pad the image. + if (image.Width <= dimensions.Width && image.Height <= dimensions.Height) + { + drawingDimensions = new Rect((dimensions.Width - image.Width) / 2, (dimensions.Height - image.Height) / 2, image.Width, image.Height); + } + else if (renderRatio > aspectRatio) + { + double scaledRenderWidth = (image.Width / image.Height) * dimensions.Width; + drawingDimensions = new Rect((dimensions.Width - scaledRenderWidth) / 2, 0, scaledRenderWidth, dimensions.Height); + } + else if (renderRatio < aspectRatio) + { + double scaledRenderHeight = (image.Height / image.Width) * dimensions.Height; + drawingDimensions = new Rect(0, (dimensions.Height - scaledRenderHeight) / 2, dimensions.Width, scaledRenderHeight); + } + + var dv = new DrawingVisual(); + DrawingContext dc = dv.RenderOpen(); + dc.DrawImage(image, drawingDimensions); + dc.Close(); + + var bmp = new RenderTargetBitmap((int)dimensions.Width, (int)dimensions.Height, 96, 96, PixelFormats.Pbgra32); + bmp.Render(dv); + bf = BitmapFrame.Create(bmp); + } + + // Using GDI+ to convert to an HICON. + // I'd rather not duplicate their code. + using (MemoryStream memstm = new MemoryStream()) + { + BitmapEncoder enc = new PngBitmapEncoder(); + enc.Frames.Add(bf); + enc.Save(memstm); + + using (var istm = new ManagedIStream(memstm)) + { + // We are not bubbling out GDI+ errors when creating the native image fails. + IntPtr bitmap = IntPtr.Zero; + try + { + Status gpStatus = NativeMethods.GdipCreateBitmapFromStream(istm, out bitmap); + if (Status.Ok != gpStatus) + { + return IntPtr.Zero; + } + + IntPtr hicon; + gpStatus = NativeMethods.GdipCreateHICONFromBitmap(bitmap, out hicon); + if (Status.Ok != gpStatus) + { + return IntPtr.Zero; + } + + // Caller is responsible for freeing this. + return hicon; + } + finally + { + Utility.SafeDisposeImage(ref bitmap); + } + } + } + } + + public static BitmapFrame GetBestMatch(IList frames, int width, int height) + { + return _GetBestMatch(frames, _GetBitDepth(), width, height); + } + + private static int _MatchImage(BitmapFrame frame, int bitDepth, int width, int height, int bpp) + { + int score = 2 * _WeightedAbs(bpp, bitDepth, false) + + _WeightedAbs(frame.PixelWidth, width, true) + + _WeightedAbs(frame.PixelHeight, height, true); + + return score; + } + + private static int _WeightedAbs(int valueHave, int valueWant, bool fPunish) + { + int diff = (valueHave - valueWant); + + if (diff < 0) + { + diff = (fPunish ? -2 : -1) * diff; + } + + return diff; + } + + /// From a list of BitmapFrames find the one that best matches the requested dimensions. + /// The methods used here are copied from Win32 sources. We want to be consistent with + /// system behaviors. + private static BitmapFrame _GetBestMatch(IList frames, int bitDepth, int width, int height) + { + int bestScore = int.MaxValue; + int bestBpp = 0; + int bestIndex = 0; + + bool isBitmapIconDecoder = frames[0].Decoder is IconBitmapDecoder; + + for (int i = 0; i < frames.Count && bestScore != 0; ++i) + { + int currentIconBitDepth = isBitmapIconDecoder ? frames[i].Thumbnail.Format.BitsPerPixel : frames[i].Format.BitsPerPixel; + + if (currentIconBitDepth == 0) + { + currentIconBitDepth = 8; + } + + int score = _MatchImage(frames[i], bitDepth, width, height, currentIconBitDepth); + if (score < bestScore) + { + bestIndex = i; + bestBpp = currentIconBitDepth; + bestScore = score; + } + else if (score == bestScore) + { + // Tie breaker: choose the higher color depth. If that fails, choose first one. + if (bestBpp < currentIconBitDepth) + { + bestIndex = i; + bestBpp = currentIconBitDepth; + } + } + } + + return frames[bestIndex]; + } + + // This can be cached. It's not going to change under reasonable circumstances. + private static int s_bitDepth; // = 0; + private static int _GetBitDepth() + { + if (s_bitDepth == 0) + { + using (SafeDC dc = SafeDC.GetDesktop()) + { + s_bitDepth = NativeMethods.GetDeviceCaps(dc, DeviceCap.BITSPIXEL) * NativeMethods.GetDeviceCaps(dc, DeviceCap.PLANES); + } + } + return s_bitDepth; + } + + /// + /// Simple guard against the exceptions that File.Delete throws on null and empty strings. + /// + /// The path to delete. Unlike File.Delete, this can be null or empty. + /// + /// Note that File.Delete, and by extension SafeDeleteFile, does not throw an exception + /// if the file does not exist. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDeleteFile(string path) + { + if (!string.IsNullOrEmpty(path)) + { + + File.Delete(path); + } + } + + /// GDI's DeleteObject + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDeleteObject(ref IntPtr gdiObject) + { + IntPtr p = gdiObject; + gdiObject = IntPtr.Zero; + if (IntPtr.Zero != p) + { + NativeMethods.DeleteObject(p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDestroyIcon(ref IntPtr hicon) + { + IntPtr p = hicon; + hicon = IntPtr.Zero; + if (IntPtr.Zero != p) + { + NativeMethods.DestroyIcon(p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDestroyWindow(ref IntPtr hwnd) + { + IntPtr p = hwnd; + hwnd = IntPtr.Zero; + if (NativeMethods.IsWindow(p)) + { + NativeMethods.DestroyWindow(p); + } + } + + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDispose(ref T disposable) where T : IDisposable + { + // Dispose can safely be called on an object multiple times. + IDisposable t = disposable; + disposable = default(T); + if (null != t) + { + t.Dispose(); + } + } + + /// GDI+'s DisposeImage + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDisposeImage(ref IntPtr gdipImage) + { + IntPtr p = gdipImage; + gdipImage = IntPtr.Zero; + if (IntPtr.Zero != p) + { + NativeMethods.GdipDisposeImage(p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static void SafeCoTaskMemFree(ref IntPtr ptr) + { + IntPtr p = ptr; + ptr = IntPtr.Zero; + if (IntPtr.Zero != p) + { + Marshal.FreeCoTaskMem(p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static void SafeFreeHGlobal(ref IntPtr hglobal) + { + IntPtr p = hglobal; + hglobal = IntPtr.Zero; + if (IntPtr.Zero != p) + { + Marshal.FreeHGlobal(p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static void SafeRelease(ref T comObject) where T : class + { + T t = comObject; + comObject = default(T); + if (null != t) + { + Assert.IsTrue(Marshal.IsComObject(t)); + Marshal.ReleaseComObject(t); + } + } + + /// + /// Utility to help classes catenate their properties for implementing ToString(). + /// + /// The StringBuilder to catenate the results into. + /// The name of the property to be catenated. + /// The value of the property to be catenated. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void GeneratePropertyString(StringBuilder source, string propertyName, string value) + { + Assert.IsNotNull(source); + Assert.IsFalse(string.IsNullOrEmpty(propertyName)); + + if (0 != source.Length) + { + source.Append(' '); + } + + source.Append(propertyName); + source.Append(": "); + if (string.IsNullOrEmpty(value)) + { + source.Append(""); + } + else + { + source.Append('\"'); + source.Append(value); + source.Append('\"'); + } + } + + /// + /// Generates ToString functionality for a struct. This is an expensive way to do it, + /// it exists for the sake of debugging while classes are in flux. + /// Eventually this should just be removed and the classes should + /// do this without reflection. + /// + /// + /// + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [Obsolete] + public static string GenerateToString(T @object) where T : struct + { + var sbRet = new StringBuilder(); + foreach (PropertyInfo property in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)) + { + if (0 != sbRet.Length) + { + sbRet.Append(", "); + } + Assert.AreEqual(0, property.GetIndexParameters().Length); + object value = property.GetValue(@object, null); + string format = null == value ? "{0}: " : "{0}: \"{1}\""; + sbRet.AppendFormat(format, property.Name, value); + } + return sbRet.ToString(); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void CopyStream(Stream destination, Stream source) + { + Assert.IsNotNull(source); + Assert.IsNotNull(destination); + + destination.Position = 0; + + // If we're copying from, say, a web stream, don't fail because of this. + if (source.CanSeek) + { + source.Position = 0; + + // Consider that this could throw because + // the source stream doesn't know it's size... + destination.SetLength(source.Length); + } + + var buffer = new byte[4096]; + int cbRead; + + do + { + cbRead = source.Read(buffer, 0, buffer.Length); + if (0 != cbRead) + { + destination.Write(buffer, 0, cbRead); + } + } + while (buffer.Length == cbRead); + + // Reset the Seek pointer before returning. + destination.Position = 0; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string HashStreamMD5(Stream stm) + { + stm.Position = 0; + var hashBuilder = new StringBuilder(); + using (MD5 md5 = MD5.Create()) + { + foreach (byte b in md5.ComputeHash(stm)) + { + hashBuilder.Append(b.ToString("x2", CultureInfo.InvariantCulture)); + } + } + + return hashBuilder.ToString(); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void EnsureDirectory(string path) + { + if (!Directory.Exists(Path.GetDirectoryName(path))) + { + Directory.CreateDirectory(Path.GetDirectoryName(path)); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool MemCmp(byte[] left, byte[] right, int cb) + { + Assert.IsNotNull(left); + Assert.IsNotNull(right); + + Assert.IsTrue(cb <= Math.Min(left.Length, right.Length)); + + // pin this buffer + GCHandle handleLeft = GCHandle.Alloc(left, GCHandleType.Pinned); + IntPtr ptrLeft = handleLeft.AddrOfPinnedObject(); + + // pin the other buffer + GCHandle handleRight = GCHandle.Alloc(right, GCHandleType.Pinned); + IntPtr ptrRight = handleRight.AddrOfPinnedObject(); + + bool fRet = _MemCmp(ptrLeft, ptrRight, cb); + + handleLeft.Free(); + handleRight.Free(); + + return fRet; + } + + private class _UrlDecoder + { + private readonly Encoding _encoding; + private readonly char[] _charBuffer; + private readonly byte[] _byteBuffer; + private int _byteCount; + private int _charCount; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public _UrlDecoder(int size, Encoding encoding) + { + _encoding = encoding; + _charBuffer = new char[size]; + _byteBuffer = new byte[size]; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void AddByte(byte b) + { + _byteBuffer[_byteCount++] = b; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void AddChar(char ch) + { + _FlushBytes(); + _charBuffer[_charCount++] = ch; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private void _FlushBytes() + { + if (_byteCount > 0) + { + _charCount += _encoding.GetChars(_byteBuffer, 0, _byteCount, _charBuffer, _charCount); + _byteCount = 0; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public string GetString() + { + _FlushBytes(); + if (_charCount > 0) + { + return new string(_charBuffer, 0, _charCount); + } + return ""; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string UrlDecode(string url) + { + if (url == null) + { + return null; + } + + var decoder = new _UrlDecoder(url.Length, Encoding.UTF8); + int length = url.Length; + for (int i = 0; i < length; ++i) + { + char ch = url[i]; + + if (ch == '+') + { + decoder.AddByte((byte)' '); + continue; + } + + if (ch == '%' && i < length - 2) + { + // decode %uXXXX into a Unicode character. + if (url[i + 1] == 'u' && i < length - 5) + { + int a = _HexToInt(url[i + 2]); + int b = _HexToInt(url[i + 3]); + int c = _HexToInt(url[i + 4]); + int d = _HexToInt(url[i + 5]); + if (a >= 0 && b >= 0 && c >= 0 && d >= 0) + { + decoder.AddChar((char)((a << 12) | (b << 8) | (c << 4) | d)); + i += 5; + + continue; + } + } + else + { + // decode %XX into a Unicode character. + int a = _HexToInt(url[i + 1]); + int b = _HexToInt(url[i + 2]); + + if (a >= 0 && b >= 0) + { + decoder.AddByte((byte)((a << 4) | b)); + i += 2; + + continue; + } + } + } + + // Add any 7bit character as a byte. + if ((ch & 0xFF80) == 0) + { + decoder.AddByte((byte)ch); + } + else + { + decoder.AddChar(ch); + } + } + + return decoder.GetString(); + } + + /// + /// Encodes a URL string. Duplicated functionality from System.Web.HttpUtility.UrlEncode. + /// + /// + /// + /// + /// Duplicated from System.Web.HttpUtility because System.Web isn't part of the client profile. + /// URL Encoding replaces ' ' with '+' and unsafe ASCII characters with '%XX'. + /// Safe characters are defined in RFC2396 (http://www.ietf.org/rfc/rfc2396.txt). + /// They are the 7-bit ASCII alphanumerics and the mark characters "-_.!~*'()". + /// This implementation does not treat '~' as a safe character to be consistent with the System.Web version. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string UrlEncode(string url) + { + if (url == null) + { + return null; + } + + byte[] bytes = Encoding.UTF8.GetBytes(url); + + bool needsEncoding = false; + int unsafeCharCount = 0; + foreach (byte b in bytes) + { + if (b == ' ') + { + needsEncoding = true; + } + else if (!_UrlEncodeIsSafe(b)) + { + ++unsafeCharCount; + needsEncoding = true; + } + } + + if (needsEncoding) + { + var buffer = new byte[bytes.Length + (unsafeCharCount * 2)]; + int writeIndex = 0; + foreach (byte b in bytes) + { + if (_UrlEncodeIsSafe(b)) + { + buffer[writeIndex++] = b; + } + else if (b == ' ') + { + buffer[writeIndex++] = (byte)'+'; + } + else + { + buffer[writeIndex++] = (byte)'%'; + buffer[writeIndex++] = _IntToHex((b >> 4) & 0xF); + buffer[writeIndex++] = _IntToHex(b & 0xF); + } + } + bytes = buffer; + Assert.AreEqual(buffer.Length, writeIndex); + } + + return Encoding.ASCII.GetString(bytes); + } + + // HttpUtility's UrlEncode is slightly different from the RFC. + // RFC2396 describes unreserved characters as alphanumeric or + // the list "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" + // The System.Web version unnecessarily escapes '~', which should be okay... + // Keeping that same pattern here just to be consistent. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static bool _UrlEncodeIsSafe(byte b) + { + if (_IsAsciiAlphaNumeric(b)) + { + return true; + } + + switch ((char)b) + { + case '-': + case '_': + case '.': + case '!': + //case '~': + case '*': + case '\'': + case '(': + case ')': + return true; + } + + return false; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static bool _IsAsciiAlphaNumeric(byte b) + { + return (b >= 'a' && b <= 'z') + || (b >= 'A' && b <= 'Z') + || (b >= '0' && b <= '9'); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static byte _IntToHex(int n) + { + Assert.BoundedInteger(0, n, 16); + if (n <= 9) + { + return (byte)(n + '0'); + } + return (byte)(n - 10 + 'A'); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static int _HexToInt(char h) + { + if (h >= '0' && h <= '9') + { + return h - '0'; + } + + if (h >= 'a' && h <= 'f') + { + return h - 'a' + 10; + } + + if (h >= 'A' && h <= 'F') + { + return h - 'A' + 10; + } + + Assert.Fail("Invalid hex character " + h); + return -1; + } + + public static void AddDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener) + { + if (component == null) + { + return; + } + Assert.IsNotNull(property); + Assert.IsNotNull(listener); + + DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType()); + dpd.AddValueChanged(component, listener); + } + + public static void RemoveDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener) + { + if (component == null) + { + return; + } + Assert.IsNotNull(property); + Assert.IsNotNull(listener); + + DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType()); + dpd.RemoveValueChanged(component, listener); + } + + #region Extension Methods + + public static bool IsThicknessNonNegative(Thickness thickness) + { + if (!IsDoubleFiniteAndNonNegative(thickness.Top)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(thickness.Left)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(thickness.Bottom)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(thickness.Right)) + { + return false; + } + + return true; + } + + public static bool IsCornerRadiusValid(CornerRadius cornerRadius) + { + if (!IsDoubleFiniteAndNonNegative(cornerRadius.TopLeft)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(cornerRadius.TopRight)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(cornerRadius.BottomLeft)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(cornerRadius.BottomRight)) + { + return false; + } + + return true; + } + + public static bool IsDoubleFiniteAndNonNegative(double d) + { + if (double.IsNaN(d) || double.IsInfinity(d) || d < 0) + { + return false; + } + + return true; + } + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/Standard/Verify.cs b/Microsoft.Windows.Shell/Standard/Verify.cs new file mode 100644 index 0000000..b806b1f --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/Verify.cs @@ -0,0 +1,312 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +// This file contains general utilities to aid in development. +// Classes here generally shouldn't be exposed publicly since +// they're not particular to any library functionality. +// Because the classes here are internal, it's likely this file +// might be included in multiple assemblies. +namespace Standard +{ + using System; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.IO; + using System.Threading; + + /// + /// A static class for retail validated assertions. + /// Instead of breaking into the debugger an exception is thrown. + /// + internal static class Verify + { + /// + /// Ensure that the current thread's apartment state is what's expected. + /// + /// + /// The required apartment state for the current thread. + /// + /// + /// The message string for the exception to be thrown if the state is invalid. + /// + /// + /// Thrown if the calling thread's apartment state is not the same as the requiredState. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsApartmentState(ApartmentState requiredState, string message) + { + if (Thread.CurrentThread.GetApartmentState() != requiredState) + { + throw new InvalidOperationException(message); + } + } + + /// + /// Ensure that an argument is neither null nor empty. + /// + /// The string to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Performance", "CA1820:TestForEmptyStringsUsingStringLength")] + [DebuggerStepThrough] + public static void IsNeitherNullNorEmpty(string value, string name) + { + // catch caller errors, mixing up the parameters. Name should never be empty. + Assert.IsNeitherNullNorEmpty(name); + + // Notice that ArgumentNullException and ArgumentException take the parameters in opposite order :P + const string errorMessage = "The parameter can not be either null or empty."; + if (null == value) + { + throw new ArgumentNullException(name, errorMessage); + } + if ("" == value) + { + throw new ArgumentException(errorMessage, name); + } + } + + /// + /// Ensure that an argument is neither null nor does it consist only of whitespace. + /// + /// The string to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Performance", "CA1820:TestForEmptyStringsUsingStringLength")] + [DebuggerStepThrough] + public static void IsNeitherNullNorWhitespace(string value, string name) + { + // catch caller errors, mixing up the parameters. Name should never be empty. + Assert.IsNeitherNullNorEmpty(name); + + // Notice that ArgumentNullException and ArgumentException take the parameters in opposite order :P + const string errorMessage = "The parameter can not be either null or empty or consist only of white space characters."; + if (null == value) + { + throw new ArgumentNullException(name, errorMessage); + } + if ("" == value.Trim()) + { + throw new ArgumentException(errorMessage, name); + } + } + + /// Verifies that an argument is not null. + /// Type of the object to validate. Must be a class. + /// The object to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsNotDefault(T obj, string name) where T : struct + { + if (default(T).Equals(obj)) + { + throw new ArgumentException("The parameter must not be the default value.", name); + } + } + + /// Verifies that an argument is not null. + /// Type of the object to validate. Must be a class. + /// The object to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsNotNull(T obj, string name) where T : class + { + if (null == obj) + { + throw new ArgumentNullException(name); + } + } + + /// Verifies that an argument is null. + /// Type of the object to validate. Must be a class. + /// The object to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsNull(T obj, string name) where T : class + { + if (null != obj) + { + throw new ArgumentException("The parameter must be null.", name); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void PropertyIsNotNull(T obj, string name) where T : class + { + if (null == obj) + { + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The property {0} cannot be null at this time.", name)); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void PropertyIsNull(T obj, string name) where T : class + { + if (null != obj) + { + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The property {0} must be null at this time.", name)); + } + } + + /// + /// Verifies the specified statement is true. Throws an ArgumentException if it's not. + /// + /// The statement to be verified as true. + /// Name of the parameter to include in the ArgumentException. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsTrue(bool statement, string name) + { + if (!statement) + { + throw new ArgumentException("", name); + } + } + + /// + /// Verifies the specified statement is true. Throws an ArgumentException if it's not. + /// + /// The statement to be verified as true. + /// Name of the parameter to include in the ArgumentException. + /// The message to include in the ArgumentException. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsTrue(bool statement, string name, string message) + { + if (!statement) + { + throw new ArgumentException(message, name); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void AreEqual(T expected, T actual, string parameterName, string message) + { + if (null == expected) + { + // Two nulls are considered equal, regardless of type semantics. + if (null != actual && !actual.Equals(expected)) + { + throw new ArgumentException(message, parameterName); + } + } + else if (!expected.Equals(actual)) + { + throw new ArgumentException(message, parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void AreNotEqual(T notExpected, T actual, string parameterName, string message) + { + if (null == notExpected) + { + // Two nulls are considered equal, regardless of type semantics. + if (null == actual || actual.Equals(notExpected)) + { + throw new ArgumentException(message, parameterName); + } + } + else if (notExpected.Equals(actual)) + { + throw new ArgumentException(message, parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void UriIsAbsolute(Uri uri, string parameterName) + { + Verify.IsNotNull(uri, parameterName); + if (!uri.IsAbsoluteUri) + { + throw new ArgumentException("The URI must be absolute.", parameterName); + } + } + + /// + /// Verifies that the specified value is within the expected range. The assertion fails if it isn't. + /// + /// The lower bound inclusive value. + /// The value to verify. + /// The upper bound exclusive value. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void BoundedInteger(int lowerBoundInclusive, int value, int upperBoundExclusive, string parameterName) + { + if (value < lowerBoundInclusive || value >= upperBoundExclusive) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The integer value must be bounded with [{0}, {1})", lowerBoundInclusive, upperBoundExclusive), parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void BoundedDoubleInc(double lowerBoundInclusive, double value, double upperBoundInclusive, string message, string parameter) + { + if (value < lowerBoundInclusive || value > upperBoundInclusive) + { + throw new ArgumentException(message, parameter); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void TypeSupportsInterface(Type type, Type interfaceType, string parameterName) + { + Assert.IsNeitherNullNorEmpty(parameterName); + Verify.IsNotNull(type, "type"); + Verify.IsNotNull(interfaceType, "interfaceType"); + + if (type.GetInterface(interfaceType.Name) == null) + { + throw new ArgumentException("The type of this parameter does not support a required interface", parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void FileExists(string filePath, string parameterName) + { + Verify.IsNeitherNullNorEmpty(filePath, parameterName); + if (!File.Exists(filePath)) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "No file exists at \"{0}\"", filePath), parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + internal static void ImplementsInterface(object parameter, Type interfaceType, string parameterName) + { + Assert.IsNotNull(parameter); + Assert.IsNotNull(interfaceType); + Assert.IsTrue(interfaceType.IsInterface); + + bool isImplemented = false; + foreach (var ifaceType in parameter.GetType().GetInterfaces()) + { + if (ifaceType == interfaceType) + { + isImplemented = true; + break; + } + } + + if (!isImplemented) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The parameter must implement interface {0}.", interfaceType.ToString()), parameterName); + } + } + } +} diff --git a/Microsoft.Windows.Shell/SystemCommands.cs b/Microsoft.Windows.Shell/SystemCommands.cs new file mode 100644 index 0000000..e4678f9 --- /dev/null +++ b/Microsoft.Windows.Shell/SystemCommands.cs @@ -0,0 +1,91 @@ + +namespace Microsoft.Windows.Shell +{ + using System; + using System.Windows; + using System.Windows.Input; + using System.Windows.Interop; + using Standard; + + public static class SystemCommands + { + public static RoutedCommand CloseWindowCommand { get; private set; } + public static RoutedCommand MaximizeWindowCommand { get; private set; } + public static RoutedCommand MinimizeWindowCommand { get; private set; } + public static RoutedCommand RestoreWindowCommand { get; private set; } + public static RoutedCommand ShowSystemMenuCommand { get; private set; } + + static SystemCommands() + { + CloseWindowCommand = new RoutedCommand("CloseWindow", typeof(SystemCommands)); + MaximizeWindowCommand = new RoutedCommand("MaximizeWindow", typeof(SystemCommands)); + MinimizeWindowCommand = new RoutedCommand("MinimizeWindow", typeof(SystemCommands)); + RestoreWindowCommand = new RoutedCommand("RestoreWindow", typeof(SystemCommands)); + ShowSystemMenuCommand = new RoutedCommand("ShowSystemMenu", typeof(SystemCommands)); + } + + private static void _PostSystemCommand(Window window, SC command) + { + IntPtr hwnd = new WindowInteropHelper(window).Handle; + if (hwnd == IntPtr.Zero || !NativeMethods.IsWindow(hwnd)) + { + return; + } + + NativeMethods.PostMessage(hwnd, WM.SYSCOMMAND, new IntPtr((int)command), IntPtr.Zero); + } + + public static void CloseWindow(Window window) + { + Verify.IsNotNull(window, "window"); + _PostSystemCommand(window, SC.CLOSE); + } + + public static void MaximizeWindow(Window window) + { + Verify.IsNotNull(window, "window"); + _PostSystemCommand(window, SC.MAXIMIZE); + } + + public static void MinimizeWindow(Window window) + { + Verify.IsNotNull(window, "window"); + _PostSystemCommand(window, SC.MINIMIZE); + } + + public static void RestoreWindow(Window window) + { + Verify.IsNotNull(window, "window"); + _PostSystemCommand(window, SC.RESTORE); + } + + /// Display the system menu at a specified location. + /// The location to display the system menu, in logical screen coordinates. + public static void ShowSystemMenu(Window window, Point screenLocation) + { + Verify.IsNotNull(window, "window"); + ShowSystemMenuPhysicalCoordinates(window, DpiHelper.LogicalPixelsToDevice(screenLocation)); + } + + internal static void ShowSystemMenuPhysicalCoordinates(Window window, Point physicalScreenLocation) + { + const uint TPM_RETURNCMD = 0x0100; + const uint TPM_LEFTBUTTON = 0x0; + + Verify.IsNotNull(window, "window"); + IntPtr hwnd = new WindowInteropHelper(window).Handle; + if (hwnd == IntPtr.Zero || !NativeMethods.IsWindow(hwnd)) + { + return; + } + + IntPtr hmenu = NativeMethods.GetSystemMenu(hwnd, false); + + uint cmd = NativeMethods.TrackPopupMenuEx(hmenu, TPM_LEFTBUTTON | TPM_RETURNCMD, (int)physicalScreenLocation.X, (int)physicalScreenLocation.Y, hwnd, IntPtr.Zero); + if (0 != cmd) + { + NativeMethods.PostMessage(hwnd, WM.SYSCOMMAND, new IntPtr(cmd), IntPtr.Zero); + } + } + } +} diff --git a/Microsoft.Windows.Shell/SystemParameters2.cs b/Microsoft.Windows.Shell/SystemParameters2.cs new file mode 100644 index 0000000..f230163 --- /dev/null +++ b/Microsoft.Windows.Shell/SystemParameters2.cs @@ -0,0 +1,557 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Microsoft.Windows.Shell +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.InteropServices; + using System.Windows; + using System.Windows.Media; + using Standard; + + [SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable")] + public class SystemParameters2 : INotifyPropertyChanged + { + private delegate void _SystemMetricUpdate(IntPtr wParam, IntPtr lParam); + + [ThreadStatic] + private static SystemParameters2 _threadLocalSingleton; + + private MessageWindow _messageHwnd; + + private bool _isGlassEnabled; + private Color _glassColor; + private SolidColorBrush _glassColorBrush; + private Thickness _windowResizeBorderThickness; + private Thickness _windowNonClientFrameThickness; + private double _captionHeight; + private Size _smallIconSize; + private string _uxThemeName; + private string _uxThemeColor; + private bool _isHighContrast; + private CornerRadius _windowCornerRadius; + private Rect _captionButtonLocation; + + private readonly Dictionary> _UpdateTable; + + #region Initialization and Update Methods + + // Most properties exposed here have a way of being queried directly + // and a way of being notified of updates via a window message. + // This region is a grouping of both, for each of the exposed properties. + + private void _InitializeIsGlassEnabled() + { + IsGlassEnabled = NativeMethods.DwmIsCompositionEnabled(); + } + + private void _UpdateIsGlassEnabled(IntPtr wParam, IntPtr lParam) + { + // Neither the wParam or lParam are used in this case. + _InitializeIsGlassEnabled(); + } + + private void _InitializeGlassColor() + { + bool isOpaque; + uint color; + NativeMethods.DwmGetColorizationColor(out color, out isOpaque); + color |= isOpaque ? 0xFF000000 : 0; + + WindowGlassColor = Utility.ColorFromArgbDword(color); + + var glassBrush = new SolidColorBrush(WindowGlassColor); + glassBrush.Freeze(); + + WindowGlassBrush = glassBrush; + } + + private void _UpdateGlassColor(IntPtr wParam, IntPtr lParam) + { + bool isOpaque = lParam != IntPtr.Zero; + uint color = unchecked((uint)(int)wParam.ToInt64()); + color |= isOpaque ? 0xFF000000 : 0; + WindowGlassColor = Utility.ColorFromArgbDword(color); + var glassBrush = new SolidColorBrush(WindowGlassColor); + glassBrush.Freeze(); + WindowGlassBrush = glassBrush; + } + + private void _InitializeCaptionHeight() + { + Point ptCaption = new Point(0, NativeMethods.GetSystemMetrics(SM.CYCAPTION)); + WindowCaptionHeight = DpiHelper.DevicePixelsToLogical(ptCaption).Y; + } + + private void _UpdateCaptionHeight(IntPtr wParam, IntPtr lParam) + { + _InitializeCaptionHeight(); + } + + private void _InitializeWindowResizeBorderThickness() + { + Size frameSize = new Size( + NativeMethods.GetSystemMetrics(SM.CXSIZEFRAME), + NativeMethods.GetSystemMetrics(SM.CYSIZEFRAME)); + Size frameSizeInDips = DpiHelper.DeviceSizeToLogical(frameSize); + WindowResizeBorderThickness = new Thickness(frameSizeInDips.Width, frameSizeInDips.Height, frameSizeInDips.Width, frameSizeInDips.Height); + } + + private void _UpdateWindowResizeBorderThickness(IntPtr wParam, IntPtr lParam) + { + _InitializeWindowResizeBorderThickness(); + } + + private void _InitializeWindowNonClientFrameThickness() + { + Size frameSize = new Size( + NativeMethods.GetSystemMetrics(SM.CXSIZEFRAME), + NativeMethods.GetSystemMetrics(SM.CYSIZEFRAME)); + Size frameSizeInDips = DpiHelper.DeviceSizeToLogical(frameSize); + int captionHeight = NativeMethods.GetSystemMetrics(SM.CYCAPTION); + double captionHeightInDips = DpiHelper.DevicePixelsToLogical(new Point(0, captionHeight)).Y; + WindowNonClientFrameThickness = new Thickness(frameSizeInDips.Width, frameSizeInDips.Height + captionHeightInDips, frameSizeInDips.Width, frameSizeInDips.Height); + } + + private void _UpdateWindowNonClientFrameThickness(IntPtr wParam, IntPtr lParam) + { + _InitializeWindowNonClientFrameThickness(); + } + + private void _InitializeSmallIconSize() + { + SmallIconSize = new Size( + NativeMethods.GetSystemMetrics(SM.CXSMICON), + NativeMethods.GetSystemMetrics(SM.CYSMICON)); + } + + private void _UpdateSmallIconSize(IntPtr wParam, IntPtr lParam) + { + _InitializeSmallIconSize(); + } + + private void _LegacyInitializeCaptionButtonLocation() + { + // This calculation isn't quite right, but it's pretty close. + // I expect this is good enough for the scenarios where this is expected to be used. + int captionX = NativeMethods.GetSystemMetrics(SM.CXSIZE); + int captionY = NativeMethods.GetSystemMetrics(SM.CYSIZE); + + int frameX = NativeMethods.GetSystemMetrics(SM.CXSIZEFRAME) + NativeMethods.GetSystemMetrics(SM.CXEDGE); + int frameY = NativeMethods.GetSystemMetrics(SM.CYSIZEFRAME) + NativeMethods.GetSystemMetrics(SM.CYEDGE); + + Rect captionRect = new Rect(0, 0, captionX * 3, captionY); + captionRect.Offset(-frameX - captionRect.Width, frameY); + + WindowCaptionButtonsLocation = captionRect; + } + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + private void _InitializeCaptionButtonLocation() + { + // There is a completely different way to do this on XP. + if (!Utility.IsOSVistaOrNewer || !NativeMethods.IsThemeActive()) + { + _LegacyInitializeCaptionButtonLocation(); + return; + } + + var tbix = new TITLEBARINFOEX { cbSize = Marshal.SizeOf(typeof(TITLEBARINFOEX)) }; + IntPtr lParam = Marshal.AllocHGlobal(tbix.cbSize); + try + { + Marshal.StructureToPtr(tbix, lParam, false); + // This might flash a window in the taskbar while being calculated. + // WM_GETTITLEBARINFOEX doesn't work correctly unless the window is visible while processing. + NativeMethods.ShowWindow(_messageHwnd.Handle, SW.SHOW); + NativeMethods.SendMessage(_messageHwnd.Handle, WM.GETTITLEBARINFOEX, IntPtr.Zero, lParam); + tbix = (TITLEBARINFOEX)Marshal.PtrToStructure(lParam, typeof(TITLEBARINFOEX)); + } + finally + { + NativeMethods.ShowWindow(_messageHwnd.Handle, SW.HIDE); + Utility.SafeFreeHGlobal(ref lParam); + } + + // TITLEBARINFOEX has information relative to the screen. We need to convert the containing rect + // to instead be relative to the top-right corner of the window. + RECT rcAllCaptionButtons = RECT.Union(tbix.rgrect_CloseButton, tbix.rgrect_MinimizeButton); + // For all known themes, the RECT for the maximize box shouldn't add anything to the union of the minimize and close boxes. + Assert.AreEqual(rcAllCaptionButtons, RECT.Union(rcAllCaptionButtons, tbix.rgrect_MaximizeButton)); + + RECT rcWindow = NativeMethods.GetWindowRect(_messageHwnd.Handle); + + // Reorient the Top/Right to be relative to the top right edge of the Window. + var deviceCaptionLocation = new Rect( + rcAllCaptionButtons.Left - rcWindow.Width - rcWindow.Left, + rcAllCaptionButtons.Top - rcWindow.Top, + rcAllCaptionButtons.Width, + rcAllCaptionButtons.Height); + + Rect logicalCaptionLocation = DpiHelper.DeviceRectToLogical(deviceCaptionLocation); + + WindowCaptionButtonsLocation = logicalCaptionLocation; + } + + private void _UpdateCaptionButtonLocation(IntPtr wParam, IntPtr lParam) + { + _InitializeCaptionButtonLocation(); + } + + private void _InitializeHighContrast() + { + HIGHCONTRAST hc = NativeMethods.SystemParameterInfo_GetHIGHCONTRAST(); + HighContrast = (hc.dwFlags & HCF.HIGHCONTRASTON) != 0; + } + + private void _UpdateHighContrast(IntPtr wParam, IntPtr lParam) + { + _InitializeHighContrast(); + } + + private void _InitializeThemeInfo() + { + if (!NativeMethods.IsThemeActive()) + { + UxThemeName = "Classic"; + UxThemeColor = ""; + return; + } + + string name; + string color; + string size; + NativeMethods.GetCurrentThemeName(out name, out color, out size); + + // Consider whether this is the most useful way to expose this... + UxThemeName = System.IO.Path.GetFileNameWithoutExtension(name); + UxThemeColor = color; + } + + private void _UpdateThemeInfo(IntPtr wParam, IntPtr lParam) + { + _InitializeThemeInfo(); + } + + private void _InitializeWindowCornerRadius() + { + // The radius of window corners isn't exposed as a true system parameter. + // It instead is a logical size that we're approximating based on the current theme. + // There aren't any known variations based on theme color. + Assert.IsNeitherNullNorEmpty(UxThemeName); + + // These radii are approximate. The way WPF does rounding is different than how + // rounded-rectangle HRGNs are created, which is also different than the actual + // round corners on themed Windows. For now we're not exposing anything to + // mitigate the differences. + var cornerRadius = default(CornerRadius); + + // This list is known to be incomplete and very much not future-proof. + // On XP there are at least a couple of shipped themes that this won't catch, + // "Zune" and "Royale", but WPF doesn't know about these either. + // If a new theme was to replace Aero, then this will fall back on "classic" behaviors. + // This isn't ideal, but it's not the end of the world. WPF will generally have problems anyways. + switch (UxThemeName.ToUpperInvariant()) + { + case "LUNA": + cornerRadius = new CornerRadius(6, 6, 0, 0); + break; + case "AERO": + // Aero has two cases. One with glass and one without... + if (NativeMethods.DwmIsCompositionEnabled()) + { + cornerRadius = new CornerRadius(8); + } + else + { + cornerRadius = new CornerRadius(6, 6, 0, 0); + } + break; + case "CLASSIC": + case "ZUNE": + case "ROYALE": + default: + cornerRadius = new CornerRadius(0); + break; + } + + WindowCornerRadius = cornerRadius; + } + + private void _UpdateWindowCornerRadius(IntPtr wParam, IntPtr lParam) + { + // Neither the wParam or lParam are used in this case. + _InitializeWindowCornerRadius(); + } + + + #endregion + + /// + /// Private constructor. The public way to access this class is through the static Current property. + /// + private SystemParameters2() + { + // This window gets used for calculations about standard caption button locations + // so it has WS_OVERLAPPEDWINDOW as a style to give it normal caption buttons. + // This window may be shown during calculations of caption bar information, so create it at a location that's likely offscreen. + _messageHwnd = new MessageWindow((CS)0, WS.OVERLAPPEDWINDOW | WS.DISABLED, (WS_EX)0, new Rect(-16000, -16000, 100, 100), "", _WndProc); + _messageHwnd.Dispatcher.ShutdownStarted += (sender, e) => Utility.SafeDispose(ref _messageHwnd); + + // Fixup the default values of the DPs. + _InitializeIsGlassEnabled(); + _InitializeGlassColor(); + _InitializeCaptionHeight(); + _InitializeWindowNonClientFrameThickness(); + _InitializeWindowResizeBorderThickness(); + _InitializeCaptionButtonLocation(); + _InitializeSmallIconSize(); + _InitializeHighContrast(); + _InitializeThemeInfo(); + // WindowCornerRadius isn't exposed by true system parameters, so it requires the theme to be initialized first. + _InitializeWindowCornerRadius(); + + _UpdateTable = new Dictionary> + { + { WM.THEMECHANGED, + new List<_SystemMetricUpdate> + { + _UpdateThemeInfo, + _UpdateHighContrast, + _UpdateWindowCornerRadius, + _UpdateCaptionButtonLocation, } }, + { WM.SETTINGCHANGE, + new List<_SystemMetricUpdate> + { + _UpdateCaptionHeight, + _UpdateWindowResizeBorderThickness, + _UpdateSmallIconSize, + _UpdateHighContrast, + _UpdateWindowNonClientFrameThickness, + _UpdateCaptionButtonLocation, } }, + { WM.DWMNCRENDERINGCHANGED, new List<_SystemMetricUpdate> { _UpdateIsGlassEnabled } }, + { WM.DWMCOMPOSITIONCHANGED, new List<_SystemMetricUpdate> { _UpdateIsGlassEnabled } }, + { WM.DWMCOLORIZATIONCOLORCHANGED, new List<_SystemMetricUpdate> { _UpdateGlassColor } }, + }; + } + + public static SystemParameters2 Current + { + get + { + if (_threadLocalSingleton == null) + { + _threadLocalSingleton = new SystemParameters2(); + } + return _threadLocalSingleton; + } + } + + private IntPtr _WndProc(IntPtr hwnd, WM msg, IntPtr wParam, IntPtr lParam) + { + // Don't do this if called within the SystemParameters2 constructor + if (_UpdateTable != null) + { + List<_SystemMetricUpdate> handlers; + if (_UpdateTable.TryGetValue(msg, out handlers)) + { + Assert.IsNotNull(handlers); + foreach (var handler in handlers) + { + handler(wParam, lParam); + } + } + } + + return NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam); + } + + public bool IsGlassEnabled + { + get + { + // return _isGlassEnabled; + // It turns out there may be some lag between someone asking this + // and the window getting updated. It's not too expensive, just always do the check. + return NativeMethods.DwmIsCompositionEnabled(); + } + private set + { + if (value != _isGlassEnabled) + { + _isGlassEnabled = value; + _NotifyPropertyChanged("IsGlassEnabled"); + } + } + } + + public Color WindowGlassColor + { + get { return _glassColor; } + private set + { + if (value != _glassColor) + { + _glassColor = value; + _NotifyPropertyChanged("WindowGlassColor"); + } + } + } + + public SolidColorBrush WindowGlassBrush + { + get { return _glassColorBrush; } + private set + { + Assert.IsNotNull(value); + Assert.IsTrue(value.IsFrozen); + if (_glassColorBrush == null || value.Color != _glassColorBrush.Color) + { + _glassColorBrush = value; + _NotifyPropertyChanged("WindowGlassBrush"); + } + } + } + + public Thickness WindowResizeBorderThickness + { + get { return _windowResizeBorderThickness; } + private set + { + if (value != _windowResizeBorderThickness) + { + _windowResizeBorderThickness = value; + _NotifyPropertyChanged("WindowResizeBorderThickness"); + } + } + } + + public Thickness WindowNonClientFrameThickness + { + get { return _windowNonClientFrameThickness; } + private set + { + if (value != _windowNonClientFrameThickness) + { + _windowNonClientFrameThickness = value; + _NotifyPropertyChanged("WindowNonClientFrameThickness"); + } + } + } + + public double WindowCaptionHeight + { + get { return _captionHeight; } + private set + { + if (value != _captionHeight) + { + _captionHeight = value; + _NotifyPropertyChanged("WindowCaptionHeight"); + } + } + } + + public Size SmallIconSize + { + get { return new Size(_smallIconSize.Width, _smallIconSize.Height); } + private set + { + if (value != _smallIconSize) + { + _smallIconSize = value; + _NotifyPropertyChanged("SmallIconSize"); + } + } + } + + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Ux")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Ux")] + public string UxThemeName + { + get { return _uxThemeName; } + private set + { + if (value != _uxThemeName) + { + _uxThemeName = value; + _NotifyPropertyChanged("UxThemeName"); + } + } + } + + [SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", MessageId = "Ux")] + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Ux")] + public string UxThemeColor + { + get { return _uxThemeColor; } + private set + { + if (value != _uxThemeColor) + { + _uxThemeColor = value; + _NotifyPropertyChanged("UxThemeColor"); + } + } + } + + public bool HighContrast + { + get { return _isHighContrast; } + private set + { + if (value != _isHighContrast) + { + _isHighContrast = value; + _NotifyPropertyChanged("HighContrast"); + } + } + } + + public CornerRadius WindowCornerRadius + { + get { return _windowCornerRadius; } + private set + { + if (value != _windowCornerRadius) + { + _windowCornerRadius = value; + _NotifyPropertyChanged("WindowCornerRadius"); + } + } + } + + public Rect WindowCaptionButtonsLocation + { + get { return _captionButtonLocation; } + private set + { + if (value != _captionButtonLocation) + { + _captionButtonLocation = value; + _NotifyPropertyChanged("WindowCaptionButtonsLocation"); + } + } + } + + #region INotifyPropertyChanged Members + + private void _NotifyPropertyChanged(string propertyName) + { + Assert.IsNeitherNullNorEmpty(propertyName); + var handler = PropertyChanged; + if (handler != null) + { + handler(this, new PropertyChangedEventArgs(propertyName)); + } + } + + public event PropertyChangedEventHandler PropertyChanged; + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/TaskbarItemInfo.cs b/Microsoft.Windows.Shell/TaskbarItemInfo.cs new file mode 100644 index 0000000..e717890 --- /dev/null +++ b/Microsoft.Windows.Shell/TaskbarItemInfo.cs @@ -0,0 +1,856 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Microsoft.Windows.Shell +{ + // CONSIDER: + // The V4 implementation of this includes logic to handle hangs and crashes in Explorer. + // The native ITaskbarList3 APIs inconsistently expose when this happens by returning + // HRESULT_FROM_WIN32(ERROR_TIMEOUT) and HRESULT_FROM_WIN32(ERROR_INVALID_WINDOW_HANDLE). + // When WPF sees these HRESULTs returned it has some retry heuristics based on the error. + // + // This implementation currently just swallows FAILED HRESULTs. This prevents the app + // from crashing in these scenarios, but there's potential for properties to get out of sync + // or for repeated attempts to set these properties even when Explorer isn't running. + + using System; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Windows; + using System.Windows.Interop; + using System.Windows.Media; + using Standard; + + public enum TaskbarItemProgressState + { + None, + Indeterminate, + Normal, + Error, + Paused, + } + + public sealed class TaskbarItemInfo : Freezable + { + // Magic constant determined by Shell. + private const int c_MaximumThumbButtons = 7; + + // Register Window Message used by Shell to notify that the corresponding taskbar button has been added to the taskbar. + private static readonly WM WM_TASKBARBUTTONCREATED = NativeMethods.RegisterWindowMessage("TaskbarButtonCreated"); + + private static readonly Thickness _EmptyThickness = new Thickness(); + + private SafeGdiplusStartupToken _gdipToken; + private bool _haveAddedButtons; + private Window _window; + private HwndSource _hwndSource; + private ITaskbarList3 _taskbarList; + private readonly Size _overlaySize; + private bool _isAttached; + + protected override Freezable CreateInstanceCore() + { + return new TaskbarItemInfo(); + } + + #region Attached Properties and support methods. + + /// + /// TaskbarItem Attached Dependency Property + /// + public static readonly DependencyProperty TaskbarItemInfoProperty = DependencyProperty.RegisterAttached( + "TaskbarItemInfo", + typeof(TaskbarItemInfo), + typeof(TaskbarItemInfo), + new PropertyMetadata(null, _OnTaskbarItemInfoChanged, _CoerceTaskbarItemInfoValue)); + + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + public static TaskbarItemInfo GetTaskbarItemInfo(Window window) + { + Verify.IsNotNull(window, "window"); + return (TaskbarItemInfo)window.GetValue(TaskbarItemInfoProperty); + } + + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + public static void SetTaskbarItemInfo(Window window, TaskbarItemInfo value) + { + Verify.IsNotNull(window, "window"); + window.SetValue(TaskbarItemInfoProperty, value); + } + + /// + /// Handles changes to the TaskbarItem property. + /// + private static void _OnTaskbarItemInfoChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (DesignerProperties.GetIsInDesignMode(d)) + { + return; + } + + var window = (Window)d; + var oldbar = (TaskbarItemInfo)e.OldValue; + var newbar = (TaskbarItemInfo)e.NewValue; + + if (oldbar == newbar) + { + return; + } + + if (!Utility.IsOSWindows7OrNewer) + { + return; + } + + if (oldbar != null && oldbar._window != null) + { + oldbar._DetachWindow(); + } + + if (newbar != null) + { + newbar._SetWindow(window); + } + } + + /// + /// Coerces the TaskbarItem value. + /// + private static object _CoerceTaskbarItemInfoValue(DependencyObject d, object value) + { + if (DesignerProperties.GetIsInDesignMode(d)) + { + return value; + } + + Verify.IsNotNull(d, "d"); + + var w = (Window)d; + var superbar = (TaskbarItemInfo)value; + + // May be null if detaching + if (superbar != null) + { + // Can't attach the same TaskbarItemInfo object to multiple windows. + // This may be a redundant set to the same Window, though. + if (superbar._window != null && superbar._window != w) + { + throw new NotSupportedException(); + } + } + + w.VerifyAccess(); + + return superbar; + } + + #endregion + + #region Dependency Properties and support methods. + + /// + /// ProgressState Dependency Property + /// + public static readonly DependencyProperty ProgressStateProperty = DependencyProperty.Register( + "ProgressState", + typeof(TaskbarItemProgressState), + typeof(TaskbarItemInfo), + new PropertyMetadata( + TaskbarItemProgressState.None, + (d, e) => ((TaskbarItemInfo)d)._OnProgressStateChanged(), + (d, e) => _CoerceProgressState((TaskbarItemProgressState)e))); + + /// + /// Gets or sets the ProgressState property. This dependency property + /// indicates the progress state of the Window on the superbar. + /// + public TaskbarItemProgressState ProgressState + { + get { return (TaskbarItemProgressState)GetValue(ProgressStateProperty); } + set { SetValue(ProgressStateProperty, value); } + } + + /// + /// Handles changes to the ProgressState property. + /// + private void _OnProgressStateChanged() + { + if (!_isAttached) + { + return; + } + + _UpdateProgressState(true); + } + + private static TaskbarItemProgressState _CoerceProgressState(TaskbarItemProgressState value) + { + switch (value) + { + case TaskbarItemProgressState.Error: + case TaskbarItemProgressState.Indeterminate: + case TaskbarItemProgressState.None: + case TaskbarItemProgressState.Normal: + case TaskbarItemProgressState.Paused: + break; + default: + // Convert bad data into no-progress bar. + value = TaskbarItemProgressState.None; + break; + } + + return value; + } + + /// + /// ProgressValue Dependency Property + /// + public static readonly DependencyProperty ProgressValueProperty = DependencyProperty.Register( + "ProgressValue", + typeof(double), + typeof(TaskbarItemInfo), + new PropertyMetadata( + 0d, + (d, e) => ((TaskbarItemInfo)d)._OnProgressValueChanged(), + (d, e) => _CoerceProgressValue((double)e))); + + /// + /// Gets or sets the ProgressValue property. This dependency property + /// indicates the value of the progress bar for the Window's Superbar item. + /// + public double ProgressValue + { + get { return (double)GetValue(ProgressValueProperty); } + set { SetValue(ProgressValueProperty, value); } + } + + private void _OnProgressValueChanged() + { + if (!_isAttached) + { + return; + } + + _UpdateProgressValue(true); + } + + private static double _CoerceProgressValue(double progressValue) + { + if (double.IsNaN(progressValue)) + { + progressValue = 0; + } + + progressValue = Math.Max(progressValue, 0); + progressValue = Math.Min(1, progressValue); + + return progressValue; + } + + /// + /// Overlay Dependency Property + /// + public static readonly DependencyProperty OverlayProperty = DependencyProperty.Register( + "Overlay", + typeof(ImageSource), + typeof(TaskbarItemInfo), + new PropertyMetadata(null, (d, e) => ((TaskbarItemInfo)d)._OnOverlayChanged())); + + /// + /// Gets or sets the Overlay property. This dependency property + /// indicates the overlay that is used to indicate status for the associated Window. + /// + public ImageSource Overlay + { + get { return (ImageSource)GetValue(OverlayProperty); } + set { SetValue(OverlayProperty, value); } + } + + /// + /// Handles changes to the Overlay property. + /// + private void _OnOverlayChanged() + { + if (!_isAttached) + { + return; + } + + _UpdateOverlay(true); + } + + /// + /// Description Dependency Property + /// + public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register( + "Description", + typeof(string), + typeof(TaskbarItemInfo), + new PropertyMetadata( + string.Empty, + (d, e) => ((TaskbarItemInfo)d)._OnDescriptionChanged())); + + /// + /// Gets or sets the Description property. This dependency property + /// indicates the tooltip to display on the thumbnail for this window. + /// + public string Description + { + get { return (string)GetValue(DescriptionProperty); } + set { SetValue(DescriptionProperty, value); } + } + + /// + /// Handles changes to the Description property. + /// + private void _OnDescriptionChanged() + { + if (!_isAttached) + { + return; + } + + _UpdateTooltip(true); + } + + /// + /// ThumbnailClipMargin Dependency Property + /// + public static readonly DependencyProperty ThumbnailClipMarginProperty = DependencyProperty.Register( + "ThumbnailClipMargin", + typeof(Thickness), + typeof(TaskbarItemInfo), + new PropertyMetadata( + default(Thickness), + (d, e) => ((TaskbarItemInfo)d)._OnThumbnailClipMarginChanged(), + (d, e) => _CoerceThumbnailClipMargin((Thickness)e))); + + /// + /// Gets or sets the LiveThumbnailClipMargin property. This dependency property + /// indicates the border of the Window to clip when displayed in the taskbar thumbnail preview. + /// + public Thickness ThumbnailClipMargin + { + get { return (Thickness)GetValue(ThumbnailClipMarginProperty); } + set { SetValue(ThumbnailClipMarginProperty, value); } + } + + /// + /// Handles changes to the LiveThumbnailClipMargin property. + /// + private void _OnThumbnailClipMarginChanged() + { + if (!_isAttached) + { + return; + } + + _UpdateThumbnailClipping(true); + } + + private static Thickness _CoerceThumbnailClipMargin(Thickness margin) + { + // Any negative margins we'll treat as no nil. + if (margin.Left < 0 + || margin.Right < 0 + || margin.Top < 0 + || margin.Bottom < 0) + { + return _EmptyThickness; + } + return margin; + } + + /// + /// ThumbButtonInfos Dependency Property + /// + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Infos")] + public static readonly DependencyProperty ThumbButtonInfosProperty = DependencyProperty.Register( + "ThumbButtonInfos", + typeof(ThumbButtonInfoCollection), + typeof(TaskbarItemInfo), + new PropertyMetadata( + // Default is null, but setting it to an empty collection in the constructor + // to support the default mutable pattern. + null, + (d, e) => ((TaskbarItemInfo)d)._OnThumbButtonsChanged())); + + /// + /// Gets or sets the ThumbButtonInfos property. This dependency property + /// indicates the collection of command buttons to be displayed in the Window's DWM thumbnail. + /// + [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Infos")] + [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] + public ThumbButtonInfoCollection ThumbButtonInfos + { + get { return (ThumbButtonInfoCollection)GetValue(ThumbButtonInfosProperty); } + set { SetValue(ThumbButtonInfosProperty, value); } + } + + private void _OnThumbButtonsChanged() + { + if (!_isAttached) + { + return; + } + + _UpdateThumbButtons(true); + } + + #endregion + + // Caller is responsible for destroying the HICON. + private IntPtr _GetHICONFromImageSource(ImageSource image, Size dimensions) + { + // Verify that GDI+ has been initialized. Putting this behind a SafeHandle to ensure it gets shutdown. + if (null == _gdipToken) + { + _gdipToken = SafeGdiplusStartupToken.Startup(); + } + + return Utility.GenerateHICON(image, dimensions); + } + + public TaskbarItemInfo() + { + if (!DesignerProperties.GetIsInDesignMode(this)) + { + ITaskbarList taskbarList = null; + try + { + taskbarList = CLSID.CoCreateInstance(CLSID.TaskbarList); + taskbarList.HrInit(); + + // This QI will only work on Win7. + _taskbarList = taskbarList as ITaskbarList3; + + taskbarList = null; + } + finally + { + Utility.SafeRelease(ref taskbarList); + } + + _overlaySize = new Size( + NativeMethods.GetSystemMetrics(SM.CXSMICON), + NativeMethods.GetSystemMetrics(SM.CYSMICON)); + } + + // Set ThumbButtons to an empty list so callers can just use the property. + ThumbButtonInfos = new ThumbButtonInfoCollection(); + } + + private void _SetWindow(Window window) + { + Assert.IsNull(_window); + + if (null == window) + { + return; + } + + _window = window; + + // If we're not on Win7 then just set this property, but don't register anything + if (_taskbarList == null) + { + return; + } + + // Use whether we can get an HWND to determine if the Window has been shown. + // If this works we'll assume everything's kosher. + // If it fails we're going to jump through a few hoops to try to set our + // initial state only once the Window is ready. + IntPtr hwnd = new WindowInteropHelper(_window).Handle; + + bool isAttached = hwnd != IntPtr.Zero; + + if (!isAttached) + { + // SourceInitialized is too early. The Window isn't yet on the Superbar. + // Instead listen for the Shell message for the Taskbar button to be created and respond to that. + // This also keeps things working is Explorer stops, or the Window is temporarily removed from the taskbar. + _window.SourceInitialized += _OnWindowSourceInitialized; + } + else + { + _hwndSource = HwndSource.FromHwnd(hwnd); + _hwndSource.AddHook(_WndProc); + + _OnIsAttachedChanged(true); + } + } + + private void _OnWindowSourceInitialized(object sender, EventArgs e) + { + // We can become detached from the Window, so don't force + // it to keep indirect references to this object. + _window.SourceInitialized -= _OnWindowSourceInitialized; + + IntPtr hwnd = new WindowInteropHelper(_window).Handle; + _hwndSource = HwndSource.FromHwnd(hwnd); + // This should be early enough that the Taskbar button hasn't yet been created, + // so we can still handle the creation message. + _hwndSource.AddHook(_WndProc); + + // In case the application is run elevated, allow the + // TaskbarButtonCreated and WM_COMMAND messages through. + // In case the application is run with severe security restrictions, + // don't propagate exceptions for a lack of being able to do this. + // These methods return HRESULTs that we're ignoring. + MSGFLTINFO dontCare; + NativeMethods.ChangeWindowMessageFilterEx(hwnd, WM_TASKBARBUTTONCREATED, MSGFLT.ALLOW, out dontCare); + NativeMethods.ChangeWindowMessageFilterEx(hwnd, WM.COMMAND, MSGFLT.ALLOW, out dontCare); + } + + private IntPtr _WndProc(IntPtr hwnd, int uMsg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + WM message = (WM)uMsg; + + if (message == WM_TASKBARBUTTONCREATED) + { + _OnIsAttachedChanged(true); + _isAttached = true; + + handled = false; + } + else + { + switch (message) + { + case WM.COMMAND: + if (Utility.HIWORD(wParam.ToInt32()) == THUMBBUTTON.THBN_CLICKED) + { + int index = Utility.LOWORD(wParam.ToInt32()); + ThumbButtonInfos[index].InvokeClick(); + handled = true; + } + break; + case WM.SIZE: + _UpdateThumbnailClipping(_isAttached); + handled = false; + break; + } + } + + return IntPtr.Zero; + } + + private void _OnIsAttachedChanged(bool attached) + { + if (attached) + { + Assert.IsNotNull(_window); + Assert.IsNotNull(_hwndSource); + } + + // If we're changing attached state, then we'll need to redo this. + _haveAddedButtons = false; + + // If we're detaching from a Window when we don't have its HWND + // then we don't have anything to remove. + if (!attached && _hwndSource == null) + { + return; + } + + _UpdateOverlay(attached); + _UpdateProgressState(attached); + _UpdateProgressValue(attached); + _UpdateTooltip(attached); + _UpdateThumbnailClipping(attached); + _UpdateThumbButtons(attached); + + if (!attached) + { + _hwndSource = null; + } + } + + private void _DetachWindow() + { + Assert.IsNotNull(_window); + + // Remove all event listeners. + _window.SourceInitialized -= _OnWindowSourceInitialized; + + // Set all Superbar properties to defaults. + _isAttached = false; + _OnIsAttachedChanged(false); + + _window = null; + } + + private HRESULT _UpdateOverlay(bool attached) + { + ImageSource source = Overlay; + + // The additional string at the end of SetOverlayIcon sets the accDescription + // for screen readers. We don't currently have a property that utilizes this. + + if (null == source || !attached) + { + return _taskbarList.SetOverlayIcon(_hwndSource.Handle, IntPtr.Zero, null); + } + + IntPtr hicon = IntPtr.Zero; + try + { + hicon = _GetHICONFromImageSource(source, _overlaySize); + return _taskbarList.SetOverlayIcon(_hwndSource.Handle, hicon, null); + } + finally + { + Utility.SafeDestroyIcon(ref hicon); + } + } + + private HRESULT _UpdateTooltip(bool attached) + { + string tooltip = Description ?? ""; + if (!attached) + { + tooltip = ""; + } + + return _taskbarList.SetThumbnailTooltip(_hwndSource.Handle, tooltip); + } + + private HRESULT _UpdateProgressValue(bool attached) + { + // If we're not attached then don't modify this. + if (!attached + || ProgressState == TaskbarItemProgressState.None + || ProgressState == TaskbarItemProgressState.Indeterminate) + { + return HRESULT.S_OK; + } + + const ulong precisionValue = 1000; + // The coersion should enforce this. + Assert.BoundedDoubleInc(0, ProgressValue, 1); + + var intValue = (ulong)(ProgressValue * precisionValue); + return _taskbarList.SetProgressValue(_hwndSource.Handle, intValue, precisionValue); + } + + private HRESULT _UpdateProgressState(bool attached) + { + TaskbarItemProgressState ps = ProgressState; + + TBPF tbpf = TBPF.NOPROGRESS; + if (attached) + { + switch (ps) + { + case TaskbarItemProgressState.Error: + tbpf = TBPF.ERROR; + break; + case TaskbarItemProgressState.Indeterminate: + tbpf = TBPF.INDETERMINATE; + break; + case TaskbarItemProgressState.None: + tbpf = TBPF.NOPROGRESS; + break; + case TaskbarItemProgressState.Normal: + tbpf = TBPF.NORMAL; + break; + case TaskbarItemProgressState.Paused: + tbpf = TBPF.PAUSED; + break; + default: + // The coersion should have caught this. + Assert.Fail(); + tbpf = TBPF.NOPROGRESS; + break; + } + } + + HRESULT hr = _taskbarList.SetProgressState(_hwndSource.Handle, tbpf); + if (hr.Succeeded) + { + // Explicitly update this in case this property being set + // to None or Indeterminate before made the value not update. + hr = _UpdateProgressValue(attached); + } + + return hr; + } + + private HRESULT _UpdateThumbnailClipping(bool attached) + { + Assert.IsNotNull(_window); + + RefRECT interopRc = null; + if (attached && ThumbnailClipMargin != _EmptyThickness) + { + Thickness margin = ThumbnailClipMargin; + // Use the native GetClientRect. Window.ActualWidth and .ActualHeight include the non-client areas. + RECT physicalClientRc = NativeMethods.GetClientRect(_hwndSource.Handle); + Rect logicalClientRc = DpiHelper.DeviceRectToLogical(new Rect(physicalClientRc.Left, physicalClientRc.Top, physicalClientRc.Width, physicalClientRc.Height)); + + // Crop the clipping to ensure that the margin doesn't overlap itself. + if (margin.Left + margin.Right >= logicalClientRc.Width + || margin.Top + margin.Bottom >= logicalClientRc.Height) + { + interopRc = new RefRECT(0, 0, 0, 0); + } + else + { + Rect logicalClip = new Rect(margin.Left, margin.Top, logicalClientRc.Width - margin.Left - margin.Right, logicalClientRc.Height - margin.Top - margin.Bottom); + Rect physicalClip = DpiHelper.LogicalRectToDevice(logicalClip); + interopRc = new RefRECT((int)physicalClip.Left, (int)physicalClip.Top, (int)physicalClip.Right, (int)physicalClip.Bottom); + } + } + + // This will fail in the interop layer if called too early. + HRESULT hr = _taskbarList.SetThumbnailClip(_hwndSource.Handle, interopRc); + Assert.IsTrue(hr.Succeeded); + return hr; + } + + private HRESULT _RegisterThumbButtons() + { + HRESULT hr = HRESULT.S_OK; + + if (!_haveAddedButtons) + { + // The ITaskbarList3 API requires that the maximum number of buttons to ever be used + // are registered at the beginning. Modifications can be made to this list later. + var nativeButtons = new THUMBBUTTON[c_MaximumThumbButtons]; + + for (int i = 0; i < c_MaximumThumbButtons; ++i) + { + nativeButtons[i] = new THUMBBUTTON + { + iId = (uint)i, + dwFlags = THBF.NOBACKGROUND | THBF.DISABLED | THBF.HIDDEN, + dwMask = THB.FLAGS | THB.ICON | THB.TOOLTIP + }; + } + + // If this gets called (successfully) more than once it usually returns E_INVALIDARG. It's not really + // a failure and we potentially want to retry this operation. + hr = _taskbarList.ThumbBarAddButtons(_hwndSource.Handle, (uint)nativeButtons.Length, nativeButtons); + if (hr == HRESULT.E_INVALIDARG) + { + hr = HRESULT.S_FALSE; + } + _haveAddedButtons = hr.Succeeded; + } + + return hr; + } + + private HRESULT _UpdateThumbButtons(bool attached) + { + var nativeButtons = new THUMBBUTTON[c_MaximumThumbButtons]; + + HRESULT hr = _RegisterThumbButtons(); + if (hr.Failed) + { + return hr; + } + + ThumbButtonInfoCollection thumbButtons = ThumbButtonInfos; + + try + { + uint currentButton = 0; + if (attached && null != thumbButtons) + { + foreach (ThumbButtonInfo wrappedTB in thumbButtons) + { + var nativeTB = new THUMBBUTTON + { + iId = (uint)currentButton, + dwMask = THB.FLAGS | THB.TOOLTIP | THB.ICON, + }; + + switch (wrappedTB.Visibility) + { + case Visibility.Collapsed: + // HIDDEN removes the button from layout logic. + nativeTB.dwFlags = THBF.HIDDEN; + break; + + case Visibility.Hidden: + // To match WPF's notion of hidden, we want this not HIDDEN, + // but disabled, without background, and without icon. + nativeTB.dwFlags = THBF.DISABLED | THBF.NOBACKGROUND; + nativeTB.hIcon = IntPtr.Zero; + + break; + default: + case Visibility.Visible: + + nativeTB.szTip = wrappedTB.Description ?? ""; + nativeTB.hIcon = _GetHICONFromImageSource(wrappedTB.ImageSource, _overlaySize); + + if (!wrappedTB.IsBackgroundVisible) + { + nativeTB.dwFlags |= THBF.NOBACKGROUND; + } + + if (!wrappedTB.IsEnabled) + { + nativeTB.dwFlags |= THBF.DISABLED; + } + else + { + nativeTB.dwFlags |= THBF.ENABLED; + } + + // This is separate from enabled/disabled + if (!wrappedTB.IsInteractive) + { + nativeTB.dwFlags |= THBF.NONINTERACTIVE; + } + + if (wrappedTB.DismissWhenClicked) + { + nativeTB.dwFlags |= THBF.DISMISSONCLICK; + } + break; + } + + nativeButtons[currentButton] = nativeTB; + + ++currentButton; + if (currentButton == c_MaximumThumbButtons) + { + break; + } + } + } + + // If we're not attached, or the list is less than the maximum number of buttons + // then fill in the rest with collapsed, empty buttons. + for (; currentButton < c_MaximumThumbButtons; ++currentButton) + { + nativeButtons[currentButton] = new THUMBBUTTON + { + iId = (uint)currentButton, + dwFlags = THBF.NOBACKGROUND | THBF.DISABLED | THBF.HIDDEN, + dwMask = THB.FLAGS | THB.ICON | THB.TOOLTIP + }; + } + + // Finally, apply the update. + return _taskbarList.ThumbBarUpdateButtons(_hwndSource.Handle, (uint)nativeButtons.Length, nativeButtons); + } + finally + { + foreach (var nativeButton in nativeButtons) + { + IntPtr hico = nativeButton.hIcon; + if (IntPtr.Zero != hico) + { + Utility.SafeDestroyIcon(ref hico); + } + } + } + } + } +} diff --git a/Microsoft.Windows.Shell/ThumbButtonInfo.cs b/Microsoft.Windows.Shell/ThumbButtonInfo.cs new file mode 100644 index 0000000..56e9e59 --- /dev/null +++ b/Microsoft.Windows.Shell/ThumbButtonInfo.cs @@ -0,0 +1,347 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Microsoft.Windows.Shell +{ + using System; + using System.Diagnostics; + using System.Windows; + using System.Windows.Input; + using System.Windows.Media; + using System.ComponentModel; + using Standard; + + // This class doesn't lend itself to designer support, but still decorating the DefaultEvent. + [DefaultEvent("Click")] + public sealed class ThumbButtonInfo : Freezable, ICommandSource + { + // The CommandManager keeps weak references on delegates + // hooked for CanExecuteChanged. We need to explicitly keep a + // strong reference, because just adding an instance method causes + // the auto-generated handler to be GC'd. + private EventHandler _commandEvent; + + protected override Freezable CreateInstanceCore() + { + return new ThumbButtonInfo(); + } + + #region Dependency Properties and support methods + + public static readonly DependencyProperty VisibilityProperty = DependencyProperty.Register( + "Visibility", + typeof(Visibility), + typeof(ThumbButtonInfo), + new PropertyMetadata(Visibility.Visible)); + + /// + /// Gets or sets the whether this should be visible in the UI. + /// + public Visibility Visibility + { + get { return (Visibility)GetValue(VisibilityProperty); } + set { SetValue(VisibilityProperty, value); } + } + + public static readonly DependencyProperty DismissWhenClickedProperty = DependencyProperty.Register( + "DismissWhenClicked", + typeof(bool), + typeof(ThumbButtonInfo), + new PropertyMetadata(false)); + + /// + /// Gets or sets the DismissWhenClicked property. This dependency property + /// indicates whether the thumbnail window should disappear as a result + /// of the user clicking this button. + /// + public bool DismissWhenClicked + { + get { return (bool)GetValue(DismissWhenClickedProperty); } + set { SetValue(DismissWhenClickedProperty, value); } + } + + public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register( + "ImageSource", + typeof(ImageSource), + typeof(ThumbButtonInfo), + new PropertyMetadata(null)); + + /// + /// Gets or sets the ImageSource property. This dependency property + /// indicates the ImageSource to use for this button's display. + /// + public ImageSource ImageSource + { + get { return (ImageSource)GetValue(ImageSourceProperty); } + set { SetValue(ImageSourceProperty, value); } + } + + public static readonly DependencyProperty IsBackgroundVisibleProperty = DependencyProperty.Register( + "IsBackgroundVisible", + typeof(bool), + typeof(ThumbButtonInfo), + new PropertyMetadata(true)); + + /// + /// Gets or sets the IsBackgroundVisible property. This dependency property + /// indicates whether the default background should be shown. + /// + public bool IsBackgroundVisible + { + get { return (bool)GetValue(IsBackgroundVisibleProperty); } + set { SetValue(IsBackgroundVisibleProperty, value); } + } + + public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register( + "Description", + typeof(string), + typeof(ThumbButtonInfo), + new PropertyMetadata( + string.Empty, + null, + _CoerceDescription)); + + /// + /// Gets or sets the Description property. This dependency property + /// indicates the text to display in the tooltip for this button. + /// + public string Description + { + get { return (string)GetValue(DescriptionProperty); } + set { SetValue(DescriptionProperty, value); } + } + + // The THUMBBUTTON struct has a hard-coded length for this field of 260. + private static object _CoerceDescription(DependencyObject d, object value) + { + var text = (string)value; + + if (text != null && text.Length >= 260) + { + // Account for the NULL in native LPWSTRs + text = text.Substring(0, 259); + } + + return text; + } + + public static readonly DependencyProperty IsEnabledProperty = DependencyProperty.Register( + "IsEnabled", + typeof(bool), + typeof(ThumbButtonInfo), + new PropertyMetadata( + true, + null, + (d, e) => ((ThumbButtonInfo)d)._CoerceIsEnabledValue(e))); + + private object _CoerceIsEnabledValue(object value) + { + var enabled = (bool)value; + return enabled && _CanExecute; + } + + /// + /// Gets or sets the IsEnabled property. + /// + /// + /// This dependency property + /// indicates whether the button is receptive to user interaction and + /// should appear as such. The button will not raise click events from + /// the user when this property is false. + /// See also IsInteractive. + /// + public bool IsEnabled + { + get { return (bool)GetValue(IsEnabledProperty); } + set { SetValue(IsEnabledProperty, value); } + } + + public static readonly DependencyProperty IsInteractiveProperty = DependencyProperty.Register( + "IsInteractive", + typeof(bool), + typeof(ThumbButtonInfo), + new PropertyMetadata(true)); + + /// + /// Gets or sets the IsInteractive property. + /// + /// + /// This dependency property allows an enabled button, as determined + /// by the IsEnabled property, to not raise click events. Buttons that + /// have IsInteractive=false can be used to indicate status. + /// IsEnabled=false takes precedence over IsInteractive=false. + /// + public bool IsInteractive + { + get { return (bool)GetValue(IsInteractiveProperty); } + set { SetValue(IsInteractiveProperty, value); } + } + + public static readonly DependencyProperty CommandProperty = DependencyProperty.Register( + "Command", + typeof(ICommand), + typeof(ThumbButtonInfo), + new PropertyMetadata( + null, + (d, e) => ((ThumbButtonInfo)d)._OnCommandChanged(e))); + + private void _OnCommandChanged(DependencyPropertyChangedEventArgs e) + { + var oldCommand = (ICommand)e.OldValue; + var newCommand = (ICommand)e.NewValue; + + if (oldCommand == newCommand) + { + return; + } + + if (oldCommand != null) + { + _UnhookCommand(oldCommand); + } + if (newCommand != null) + { + _HookCommand(newCommand); + } + } + + /// + /// CommandParameter Dependency Property + /// + public static readonly DependencyProperty CommandParameterProperty = DependencyProperty.Register( + "CommandParameter", + typeof(object), + typeof(ThumbButtonInfo), + new PropertyMetadata( + null, + (d, e) => ((ThumbButtonInfo)d)._UpdateCanExecute())); + + // .Net property deferred to ICommandSource region. + + /// + /// CommandTarget Dependency Property + /// + public static readonly DependencyProperty CommandTargetProperty = DependencyProperty.Register( + "CommandTarget", + typeof(IInputElement), + typeof(ThumbButtonInfo), + new PropertyMetadata( + null, + (d, e) => ((ThumbButtonInfo)d)._UpdateCanExecute())); + + // .Net property deferred to ICommandSource region. + + private static readonly DependencyProperty _CanExecuteProperty = DependencyProperty.Register( + "_CanExecute", + typeof(bool), + typeof(ThumbButtonInfo), + new PropertyMetadata( + true, + (d, e) => d.CoerceValue(IsEnabledProperty))); + + private bool _CanExecute + { + get { return (bool)GetValue(_CanExecuteProperty); } + set { SetValue(_CanExecuteProperty, value); } + } + + #endregion + + public event EventHandler Click; + + internal void InvokeClick() + { + EventHandler local = Click; + if (local != null) + { + local(this, EventArgs.Empty); + } + + _InvokeCommand(); + } + + private void _InvokeCommand() + { + ICommand command = Command; + if (command != null) + { + object parameter = CommandParameter; + IInputElement target = CommandTarget; + + RoutedCommand routedCommand = command as RoutedCommand; + if (routedCommand != null) + { + if (routedCommand.CanExecute(parameter, target)) + { + routedCommand.Execute(parameter, target); + } + } + else if (command.CanExecute(parameter)) + { + command.Execute(parameter); + } + } + } + + private void _UnhookCommand(ICommand command) + { + Assert.IsNotNull(command); + command.CanExecuteChanged -= _commandEvent; + _commandEvent = null; + _UpdateCanExecute(); + } + + private void _HookCommand(ICommand command) + { + _commandEvent = (sender, e) => _UpdateCanExecute(); + command.CanExecuteChanged += _commandEvent; + _UpdateCanExecute(); + } + + private void _UpdateCanExecute() + { + if (Command != null) + { + object parameter = CommandParameter; + IInputElement target = CommandTarget; + + RoutedCommand routed = Command as RoutedCommand; + if (routed != null) + { + _CanExecute = routed.CanExecute(parameter, target); + } + else + { + _CanExecute = Command.CanExecute(parameter); + } + } + else + { + _CanExecute = true; + } + } + + #region ICommandSource Members + + public ICommand Command + { + get { return (ICommand)GetValue(CommandProperty); } + set { SetValue(CommandProperty, value); } + } + + public object CommandParameter + { + get { return (object)GetValue(CommandParameterProperty); } + set { SetValue(CommandParameterProperty, value); } + } + + public IInputElement CommandTarget + { + get { return (IInputElement)GetValue(CommandTargetProperty); } + set { SetValue(CommandTargetProperty, value); } + } + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/ThumbButtonInfoCollection.cs b/Microsoft.Windows.Shell/ThumbButtonInfoCollection.cs new file mode 100644 index 0000000..8533405 --- /dev/null +++ b/Microsoft.Windows.Shell/ThumbButtonInfoCollection.cs @@ -0,0 +1,36 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Microsoft.Windows.Shell +{ + using System.Windows; + + public class ThumbButtonInfoCollection : FreezableCollection + { + protected override Freezable CreateInstanceCore() + { + return new ThumbButtonInfoCollection(); + } + + /// + /// A frozen empty ThumbButtonInfoCollection. + /// + internal static ThumbButtonInfoCollection Empty + { + get + { + if (s_empty == null) + { + var collection = new ThumbButtonInfoCollection(); + collection.Freeze(); + s_empty = collection; + } + + return s_empty; + } + } + + private static ThumbButtonInfoCollection s_empty; + } +} diff --git a/Microsoft.Windows.Shell/WindowChrome.cs b/Microsoft.Windows.Shell/WindowChrome.cs new file mode 100644 index 0000000..69634ee --- /dev/null +++ b/Microsoft.Windows.Shell/WindowChrome.cs @@ -0,0 +1,235 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Microsoft.Windows.Shell +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Windows; + using System.Windows.Data; + using Standard; + + public class WindowChrome : Freezable + { + private struct _SystemParameterBoundProperty + { + public string SystemParameterPropertyName { get; set; } + public DependencyProperty DependencyProperty { get; set; } + } + + // Named property available for fully extending the glass frame. + public static Thickness GlassFrameCompleteThickness { get { return new Thickness(-1); } } + + #region Attached Properties + + public static readonly DependencyProperty WindowChromeProperty = DependencyProperty.RegisterAttached( + "WindowChrome", + typeof(WindowChrome), + typeof(WindowChrome), + new PropertyMetadata(null, _OnChromeChanged)); + + private static void _OnChromeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + // The different design tools handle drawing outside their custom window objects differently. + // Rather than try to support this concept in the design surface let the designer draw its own + // chrome anyways. + // There's certainly room for improvement here. + if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(d)) + { + return; + } + + var window = (Window)d; + var newChrome = (WindowChrome)e.NewValue; + + Assert.IsNotNull(window); + + // Update the ChromeWorker with this new object. + + // If there isn't currently a worker associated with the Window then assign a new one. + // There can be a many:1 relationship of to Window to WindowChrome objects, but a 1:1 for a Window and a WindowChromeWorker. + WindowChromeWorker chromeWorker = WindowChromeWorker.GetWindowChromeWorker(window); + if (chromeWorker == null) + { + chromeWorker = new WindowChromeWorker(); + WindowChromeWorker.SetWindowChromeWorker(window, chromeWorker); + } + + chromeWorker.SetWindowChrome(newChrome); + } + + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static WindowChrome GetWindowChrome(Window window) + { + Verify.IsNotNull(window, "window"); + return (WindowChrome)window.GetValue(WindowChromeProperty); + } + + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static void SetWindowChrome(Window window, WindowChrome chrome) + { + Verify.IsNotNull(window, "window"); + window.SetValue(WindowChromeProperty, chrome); + } + + public static readonly DependencyProperty IsHitTestVisibleInChromeProperty = DependencyProperty.RegisterAttached( + "IsHitTestVisibleInChrome", + typeof(bool), + typeof(WindowChrome), + new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.Inherits)); + + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static bool GetIsHitTestVisibleInChrome(IInputElement inputElement) + { + Verify.IsNotNull(inputElement, "inputElement"); + var dobj = inputElement as DependencyObject; + if (dobj == null) + { + throw new ArgumentException("The element must be a DependencyObject", "inputElement"); + } + return (bool)dobj.GetValue(IsHitTestVisibleInChromeProperty); + } + + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static void SetIsHitTestVisibleInChrome(IInputElement inputElement, bool hitTestVisible) + { + Verify.IsNotNull(inputElement, "inputElement"); + var dobj = inputElement as DependencyObject; + if (dobj == null) + { + throw new ArgumentException("The element must be a DependencyObject", "inputElement"); + } + dobj.SetValue(IsHitTestVisibleInChromeProperty, hitTestVisible); + } + + #endregion + + #region Dependency Properties + + public static readonly DependencyProperty CaptionHeightProperty = DependencyProperty.Register( + "CaptionHeight", + typeof(double), + typeof(WindowChrome), + new PropertyMetadata( + 0d, + (d, e) => ((WindowChrome)d)._OnPropertyChangedThatRequiresRepaint()), + value => (double)value >= 0d); + + /// The extent of the top of the window to treat as the caption. + public double CaptionHeight + { + get { return (double)GetValue(CaptionHeightProperty); } + set { SetValue(CaptionHeightProperty, value); } + } + + public static readonly DependencyProperty ResizeBorderThicknessProperty = DependencyProperty.Register( + "ResizeBorderThickness", + typeof(Thickness), + typeof(WindowChrome), + new PropertyMetadata(default(Thickness)), + (value) => Utility.IsThicknessNonNegative((Thickness)value)); + + public Thickness ResizeBorderThickness + { + get { return (Thickness)GetValue(ResizeBorderThicknessProperty); } + set { SetValue(ResizeBorderThicknessProperty, value); } + } + + public static readonly DependencyProperty GlassFrameThicknessProperty = DependencyProperty.Register( + "GlassFrameThickness", + typeof(Thickness), + typeof(WindowChrome), + new PropertyMetadata( + default(Thickness), + (d, e) => ((WindowChrome)d)._OnPropertyChangedThatRequiresRepaint(), + (d, o) => _CoerceGlassFrameThickness((Thickness)o))); + + private static object _CoerceGlassFrameThickness(Thickness thickness) + { + // If it's explicitly set, but set to a thickness with at least one negative side then + // coerce the value to the stock GlassFrameCompleteThickness. + if (!Utility.IsThicknessNonNegative(thickness)) + { + return GlassFrameCompleteThickness; + } + + return thickness; + } + public Thickness GlassFrameThickness + { + get { return (Thickness)GetValue(GlassFrameThicknessProperty); } + set { SetValue(GlassFrameThicknessProperty, value); } + } + + public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register( + "CornerRadius", + typeof(CornerRadius), + typeof(WindowChrome), + new PropertyMetadata( + default(CornerRadius), + (d, e) => ((WindowChrome)d)._OnPropertyChangedThatRequiresRepaint()), + (value) => Utility.IsCornerRadiusValid((CornerRadius)value)); + + public CornerRadius CornerRadius + { + get { return (CornerRadius)GetValue(CornerRadiusProperty); } + set { SetValue(CornerRadiusProperty, value); } + } + + #endregion + + protected override Freezable CreateInstanceCore() + { + return new WindowChrome(); + } + + private static readonly List<_SystemParameterBoundProperty> _BoundProperties = new List<_SystemParameterBoundProperty> + { + new _SystemParameterBoundProperty { DependencyProperty = CornerRadiusProperty, SystemParameterPropertyName = "WindowCornerRadius" }, + new _SystemParameterBoundProperty { DependencyProperty = CaptionHeightProperty, SystemParameterPropertyName = "WindowCaptionHeight" }, + new _SystemParameterBoundProperty { DependencyProperty = ResizeBorderThicknessProperty, SystemParameterPropertyName = "WindowResizeBorderThickness" }, + new _SystemParameterBoundProperty { DependencyProperty = GlassFrameThicknessProperty, SystemParameterPropertyName = "WindowNonClientFrameThickness" }, + }; + + public WindowChrome() + { + // Effective default values for some of these properties are set to be bindings + // that set them to system defaults. + // A more correct way to do this would be to Coerce the value iff the source of the DP was the default value. + // Unfortunately with the current property system we can't detect whether the value being applied at the time + // of the coersion is the default. + foreach (var bp in _BoundProperties) + { + // This list must be declared after the DP's are assigned. + Assert.IsNotNull(bp.DependencyProperty); + BindingOperations.SetBinding( + this, + bp.DependencyProperty, + new Binding + { + Source = SystemParameters2.Current, + Path = new PropertyPath(bp.SystemParameterPropertyName), + Mode = BindingMode.OneWay, + UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, + }); + } + } + + private void _OnPropertyChangedThatRequiresRepaint() + { + var handler = PropertyChangedThatRequiresRepaint; + if (handler != null) + { + handler(this, EventArgs.Empty); + } + } + + internal event EventHandler PropertyChangedThatRequiresRepaint; + } +} diff --git a/Microsoft.Windows.Shell/WindowChromeWorker.cs b/Microsoft.Windows.Shell/WindowChromeWorker.cs new file mode 100644 index 0000000..883b7e7 --- /dev/null +++ b/Microsoft.Windows.Shell/WindowChromeWorker.cs @@ -0,0 +1,1195 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace Microsoft.Windows.Shell +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.InteropServices; + using System.Threading; + using System.Windows; + using System.Windows.Interop; + using System.Windows.Media; + using System.Windows.Threading; + using Standard; + + using HANDLE_MESSAGE = System.Collections.Generic.KeyValuePair; + + internal class WindowChromeWorker : DependencyObject + { + // Delegate signature used for Dispatcher.BeginInvoke. + private delegate void _Action(); + + #region Fields + + private const SWP _SwpFlags = SWP.FRAMECHANGED | SWP.NOSIZE | SWP.NOMOVE | SWP.NOZORDER | SWP.NOOWNERZORDER | SWP.NOACTIVATE; + + private readonly List _messageTable; + + /// The Window that's chrome is being modified. + private Window _window; + /// Underlying HWND for the _window. + private IntPtr _hwnd; + private HwndSource _hwndSource = null; + private bool _isHooked = false; + + // These fields are for tracking workarounds for WPF 3.5SP1 behaviors. + private bool _isFixedUp = false; + private bool _isUserResizing = false; + private bool _hasUserMovedWindow = false; + private Point _windowPosAtStartOfUserMove = default(Point); + + // Field to track attempts to force off Device Bitmaps on Win7. + private int _blackGlassFixupAttemptCount; + + /// Object that describes the current modifications being made to the chrome. + private WindowChrome _chromeInfo; + + // Keep track of this so we can detect when we need to apply changes. Tracking these separately + // as I've seen using just one cause things to get enough out of sync that occasionally the caption will redraw. + private WindowState _lastRoundingState; + private WindowState _lastMenuState; + private bool _isGlassEnabled; + + #endregion + + public WindowChromeWorker() + { + _messageTable = new List + { + new HANDLE_MESSAGE(WM.SETTEXT, _HandleSetTextOrIcon), + new HANDLE_MESSAGE(WM.SETICON, _HandleSetTextOrIcon), + new HANDLE_MESSAGE(WM.NCACTIVATE, _HandleNCActivate), + new HANDLE_MESSAGE(WM.NCCALCSIZE, _HandleNCCalcSize), + new HANDLE_MESSAGE(WM.NCHITTEST, _HandleNCHitTest), + new HANDLE_MESSAGE(WM.NCRBUTTONUP, _HandleNCRButtonUp), + new HANDLE_MESSAGE(WM.SIZE, _HandleSize), + new HANDLE_MESSAGE(WM.WINDOWPOSCHANGED, _HandleWindowPosChanged), + new HANDLE_MESSAGE(WM.DWMCOMPOSITIONCHANGED, _HandleDwmCompositionChanged), + }; + + if (Utility.IsPresentationFrameworkVersionLessThan4) + { + _messageTable.AddRange(new[] + { + new HANDLE_MESSAGE(WM.SETTINGCHANGE, _HandleSettingChange), + new HANDLE_MESSAGE(WM.ENTERSIZEMOVE, _HandleEnterSizeMove), + new HANDLE_MESSAGE(WM.EXITSIZEMOVE, _HandleExitSizeMove), + new HANDLE_MESSAGE(WM.MOVE, _HandleMove), + }); + } + } + + public void SetWindowChrome(WindowChrome newChrome) + { + VerifyAccess(); + Assert.IsNotNull(_window); + + if (newChrome == _chromeInfo) + { + // Nothing's changed. + return; + } + + if (_chromeInfo != null) + { + _chromeInfo.PropertyChangedThatRequiresRepaint -= _OnChromePropertyChangedThatRequiresRepaint; + } + + _chromeInfo = newChrome; + if (_chromeInfo != null) + { + _chromeInfo.PropertyChangedThatRequiresRepaint += _OnChromePropertyChangedThatRequiresRepaint; + } + + _ApplyNewCustomChrome(); + } + + private void _OnChromePropertyChangedThatRequiresRepaint(object sender, EventArgs e) + { + _UpdateFrameState(true); + } + + public static readonly DependencyProperty WindowChromeWorkerProperty = DependencyProperty.RegisterAttached( + "WindowChromeWorker", + typeof(WindowChromeWorker), + typeof(WindowChromeWorker), + new PropertyMetadata(null, _OnChromeWorkerChanged)); + + private static void _OnChromeWorkerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var w = (Window)d; + var cw = (WindowChromeWorker)e.NewValue; + + // The WindowChromeWorker object should only be set on the window once, and never to null. + Assert.IsNotNull(w); + Assert.IsNotNull(cw); + Assert.IsNull(cw._window); + + cw._SetWindow(w); + } + + private void _SetWindow(Window window) + { + Assert.IsNull(_window); + Assert.IsNotNull(window); + + _window = window; + + // There are potentially a couple funny states here. + // The window may have been shown and closed, in which case it's no longer usable. + // We shouldn't add any hooks in that case, just exit early. + // If the window hasn't yet been shown, then we need to make sure to remove hooks after it's closed. + _hwnd = new WindowInteropHelper(_window).Handle; + + if (Utility.IsPresentationFrameworkVersionLessThan4) + { + // On older versions of the framework the client size of the window is incorrectly calculated. + // We need to modify the template to fix this on behalf of the user. + Utility.AddDependencyPropertyChangeListener(_window, Window.TemplateProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); + Utility.AddDependencyPropertyChangeListener(_window, Window.FlowDirectionProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); + } + + _window.Closed += _UnsetWindow; + + // Use whether we can get an HWND to determine if the Window has been loaded. + if (IntPtr.Zero != _hwnd) + { + // We've seen that the HwndSource can't always be retrieved from the HWND, so cache it early. + // Specifically it seems to sometimes disappear when the OS theme is changing. + _hwndSource = HwndSource.FromHwnd(_hwnd); + Assert.IsNotNull(_hwndSource); + _window.ApplyTemplate(); + + if (_chromeInfo != null) + { + _ApplyNewCustomChrome(); + } + } + else + { + _window.SourceInitialized += (sender, e) => + { + _hwnd = new WindowInteropHelper(_window).Handle; + Assert.IsNotDefault(_hwnd); + _hwndSource = HwndSource.FromHwnd(_hwnd); + Assert.IsNotNull(_hwndSource); + + if (_chromeInfo != null) + { + _ApplyNewCustomChrome(); + } + }; + } + } + + private void _UnsetWindow(object sender, EventArgs e) + { + if (Utility.IsPresentationFrameworkVersionLessThan4) + { + Utility.RemoveDependencyPropertyChangeListener(_window, Window.TemplateProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); + Utility.RemoveDependencyPropertyChangeListener(_window, Window.FlowDirectionProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); + } + + if (_chromeInfo != null) + { + _chromeInfo.PropertyChangedThatRequiresRepaint -= _OnChromePropertyChangedThatRequiresRepaint; + } + + _RestoreStandardChromeState(true); + } + + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static WindowChromeWorker GetWindowChromeWorker(Window window) + { + Verify.IsNotNull(window, "window"); + return (WindowChromeWorker)window.GetValue(WindowChromeWorkerProperty); + } + + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static void SetWindowChromeWorker(Window window, WindowChromeWorker chrome) + { + Verify.IsNotNull(window, "window"); + window.SetValue(WindowChromeWorkerProperty, chrome); + } + + private void _OnWindowPropertyChangedThatRequiresTemplateFixup(object sender, EventArgs e) + { + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + + if (_chromeInfo != null && _hwnd != IntPtr.Zero) + { + // Assume that when the template changes it's going to be applied. + // We don't have a good way to externally hook into the template + // actually being applied, so we asynchronously post the fixup operation + // at Loaded priority, so it's expected that the visual tree will be + // updated before _FixupFrameworkIssues is called. + _window.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (_Action)_FixupFrameworkIssues); + } + } + + private void _ApplyNewCustomChrome() + { + if (_hwnd == IntPtr.Zero) + { + // Not yet hooked. + return; + } + + if (_chromeInfo == null) + { + _RestoreStandardChromeState(false); + return; + } + + if (!_isHooked) + { + _hwndSource.AddHook(_WndProc); + _isHooked = true; + } + + _FixupFrameworkIssues(); + + // Force this the first time. + _UpdateSystemMenu(_window.WindowState); + _UpdateFrameState(true); + + NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, _SwpFlags); + } + + private void _FixupFrameworkIssues() + { + Assert.IsNotNull(_chromeInfo); + Assert.IsNotNull(_window); + + // This margin is only necessary if the client rect is going to be calculated incorrectly by WPF. + // This bug was fixed in V4 of the framework. + if (!Utility.IsPresentationFrameworkVersionLessThan4) + { + return; + } + + if (_window.Template == null) + { + // Nothing to fixup yet. This will get called again when a template does get set. + return; + } + + // Guard against the visual tree being empty. + if (VisualTreeHelper.GetChildrenCount(_window) == 0) + { + // The template isn't null, but we don't have a visual tree. + // Hope that ApplyTemplate is in the queue and repost this, because there's not much we can do right now. + _window.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (_Action)_FixupFrameworkIssues); + return; + } + + var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0); + + RECT rcWindow = NativeMethods.GetWindowRect(_hwnd); + RECT rcAdjustedClient = _GetAdjustedWindowRect(rcWindow); + + Rect rcLogicalWindow = DpiHelper.DeviceRectToLogical(new Rect(rcWindow.Left, rcWindow.Top, rcWindow.Width, rcWindow.Height)); + Rect rcLogicalClient = DpiHelper.DeviceRectToLogical(new Rect(rcAdjustedClient.Left, rcAdjustedClient.Top, rcAdjustedClient.Width, rcAdjustedClient.Height)); + + Thickness nonClientThickness = new Thickness( + rcLogicalWindow.Left - rcLogicalClient.Left, + rcLogicalWindow.Top - rcLogicalClient.Top, + rcLogicalClient.Right - rcLogicalWindow.Right, + rcLogicalClient.Bottom - rcLogicalWindow.Bottom); + + rootElement.Margin = new Thickness( + 0, + 0, + -(nonClientThickness.Left + nonClientThickness.Right), + -(nonClientThickness.Top + nonClientThickness.Bottom)); + + // The negative thickness on the margin doesn't properly get applied in RTL layouts. + // The width is right, but there is a black bar on the right. + // To fix this we just add an additional RenderTransform to the root element. + // This works fine, but if the window is dynamically changing its FlowDirection then this can have really bizarre side effects. + // This will mostly work if the FlowDirection is dynamically changed, but there aren't many real scenarios that would call for + // that so I'm not addressing the rest of the quirkiness. + if (_window.FlowDirection == FlowDirection.RightToLeft) + { + rootElement.RenderTransform = new MatrixTransform(1, 0, 0, 1, -(nonClientThickness.Left + nonClientThickness.Right), 0); + } + else + { + rootElement.RenderTransform = null; + } + + if (!_isFixedUp) + { + _hasUserMovedWindow = false; + _window.StateChanged += _FixupRestoreBounds; + + _isFixedUp = true; + } + } + + // There was a regression in DWM in Windows 7 with regard to handling WM_NCCALCSIZE to effect custom chrome. + // When windows with glass are maximized on a multimonitor setup the glass frame tends to turn black. + // Also when windows are resized they tend to flicker black, sometimes staying that way until resized again. + // + // This appears to be a bug in DWM related to device bitmap optimizations. At least on RTM Win7 we can + // evoke a legacy code path that bypasses the bug by calling an esoteric DWM function. This doesn't affect + // the system, just the application. + // WPF also tends to call this function anyways during animations, so we're just forcing the issue + // consistently and a bit earlier. + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + private void _FixupWindows7Issues() + { + if (_blackGlassFixupAttemptCount > 5) + { + // Don't keep trying if there's an endemic problem with this. + return; + } + + if (Utility.IsOSWindows7OrNewer && NativeMethods.DwmIsCompositionEnabled()) + { + ++_blackGlassFixupAttemptCount; + + bool success = false; + try + { + DWM_TIMING_INFO? dti = NativeMethods.DwmGetCompositionTimingInfo(_hwnd); + success = dti != null; + } + catch (Exception) + { + // We aren't sure of all the reasons this could fail. + // If we find new ones we should consider making the NativeMethod swallow them as well. + // Since we have a limited number of retries and this method isn't actually critical, just repost. + + // Disabling this for the published code to reduce debug noise. This will get compiled away for retail binaries anyways. + //Assert.Fail(e.Message); + } + + // NativeMethods.DwmGetCompositionTimingInfo swallows E_PENDING. + // If the call wasn't successful, try again later. + if (!success) + { + Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (_Action)_FixupWindows7Issues); + } + else + { + // Reset this. We will want to force this again if DWM composition changes. + _blackGlassFixupAttemptCount = 0; + } + } + } + + private void _FixupRestoreBounds(object sender, EventArgs e) + { + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + if (_window.WindowState == WindowState.Maximized || _window.WindowState == WindowState.Minimized) + { + // Old versions of WPF sometimes force their incorrect idea of the Window's location + // on the Win32 restore bounds. If we have reason to think this is the case, then + // try to undo what WPF did after it has done its thing. + if (_hasUserMovedWindow) + { + _hasUserMovedWindow = false; + WINDOWPLACEMENT wp = NativeMethods.GetWindowPlacement(_hwnd); + + RECT adjustedDeviceRc = _GetAdjustedWindowRect(new RECT { Bottom = 100, Right = 100 }); + Point adjustedTopLeft = DpiHelper.DevicePixelsToLogical( + new Point( + wp.rcNormalPosition.Left - adjustedDeviceRc.Left, + wp.rcNormalPosition.Top - adjustedDeviceRc.Top)); + + _window.Top = adjustedTopLeft.Y; + _window.Left = adjustedTopLeft.X; + } + } + } + + private RECT _GetAdjustedWindowRect(RECT rcWindow) + { + // This should only be used to work around issues in the Framework that were fixed in 4.0 + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + + var style = (WS)NativeMethods.GetWindowLongPtr(_hwnd, GWL.STYLE); + var exstyle = (WS_EX)NativeMethods.GetWindowLongPtr(_hwnd, GWL.EXSTYLE); + + return NativeMethods.AdjustWindowRectEx(rcWindow, style, false, exstyle); + } + + // Windows tries hard to hide this state from applications. + // Generally you can tell that the window is in a docked position because the restore bounds from GetWindowPlacement + // don't match the current window location and it's not in a maximized or minimized state. + // Because this isn't doced or supported, it's also not incredibly consistent. Sometimes some things get updated in + // different orders, so this isn't absolutely reliable. + private bool _IsWindowDocked + { + get + { + // We're only detecting this state to work around .Net 3.5 issues. + // This logic won't work correctly when those issues are fixed. + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + + if (_window.WindowState != WindowState.Normal) + { + return false; + } + + RECT adjustedOffset = _GetAdjustedWindowRect(new RECT { Bottom = 100, Right = 100 }); + Point windowTopLeft = new Point(_window.Left, _window.Top); + windowTopLeft -= (Vector)DpiHelper.DevicePixelsToLogical(new Point(adjustedOffset.Left, adjustedOffset.Top)); + + return _window.RestoreBounds.Location != windowTopLeft; + } + } + + #region WindowProc and Message Handlers + + private IntPtr _WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + // Only expecting messages for our cached HWND. + Assert.AreEqual(hwnd, _hwnd); + + var message = (WM)msg; + foreach (var handlePair in _messageTable) + { + if (handlePair.Key == message) + { + return handlePair.Value(message, wParam, lParam, out handled); + } + } + return IntPtr.Zero; + } + + private IntPtr _HandleSetTextOrIcon(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + bool modified = _ModifyStyle(WS.VISIBLE, 0); + + // Setting the caption text and icon cause Windows to redraw the caption. + // Letting the default WndProc handle the message without the WS_VISIBLE + // style applied bypasses the redraw. + IntPtr lRet = NativeMethods.DefWindowProc(_hwnd, uMsg, wParam, lParam); + + // Put back the style we removed. + if (modified) + { + _ModifyStyle(0, WS.VISIBLE); + } + handled = true; + return lRet; + } + + private IntPtr _HandleNCActivate(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // Despite MSDN's documentation of lParam not being used, + // calling DefWindowProc with lParam set to -1 causes Windows not to draw over the caption. + + // Directly call DefWindowProc with a custom parameter + // which bypasses any other handling of the message. + IntPtr lRet = NativeMethods.DefWindowProc(_hwnd, WM.NCACTIVATE, wParam, new IntPtr(-1)); + handled = true; + return lRet; + } + + private IntPtr _HandleNCCalcSize(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // lParam is an [in, out] that can be either a RECT* (wParam == FALSE) or an NCCALCSIZE_PARAMS*. + // Since the first field of NCCALCSIZE_PARAMS is a RECT and is the only field we care about + // we can unconditionally treat it as a RECT. + + // Since we always want the client size to equal the window size, we can unconditionally handle it + // without having to modify the parameters. + + handled = true; + return new IntPtr((int)WVR.REDRAW); + } + + private IntPtr _HandleNCHitTest(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + IntPtr lRet = IntPtr.Zero; + handled = false; + + // Give DWM a chance at this first. + if (Utility.IsOSVistaOrNewer && _chromeInfo.GlassFrameThickness != default(Thickness) && _isGlassEnabled) + { + // If we're on Vista, give the DWM a chance to handle the message first. + handled = NativeMethods.DwmDefWindowProc(_hwnd, uMsg, wParam, lParam, out lRet); + } + + // Handle letting the system know if we consider the mouse to be in our effective non-client area. + // If DWM already handled this by way of DwmDefWindowProc, then respect their call. + if (IntPtr.Zero == lRet) + { + var mousePosScreen = new Point(Utility.GET_X_LPARAM(lParam), Utility.GET_Y_LPARAM(lParam)); + Rect windowPosition = _GetWindowRect(); + + HT ht = _HitTestNca( + DpiHelper.DeviceRectToLogical(windowPosition), + DpiHelper.DevicePixelsToLogical(mousePosScreen)); + + // Don't blindly respect HTCAPTION. + // We want UIElements in the caption area to be actionable so run through a hittest first. + if (ht != HT.CLIENT) + { + Point mousePosWindow = mousePosScreen; + mousePosWindow.Offset(-windowPosition.X, -windowPosition.Y); + mousePosWindow = DpiHelper.DevicePixelsToLogical(mousePosWindow); + IInputElement inputElement = _window.InputHitTest(mousePosWindow); + if (inputElement != null && WindowChrome.GetIsHitTestVisibleInChrome(inputElement)) + { + ht = HT.CLIENT; + } + } + handled = true; + lRet = new IntPtr((int)ht); + } + return lRet; + } + + private IntPtr _HandleNCRButtonUp(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // Emulate the system behavior of clicking the right mouse button over the caption area + // to bring up the system menu. + if (HT.CAPTION == (HT)wParam.ToInt32()) + { + SystemCommands.ShowSystemMenuPhysicalCoordinates(_window, new Point(Utility.GET_X_LPARAM(lParam), Utility.GET_Y_LPARAM(lParam))); + } + handled = false; + return IntPtr.Zero; + } + + private IntPtr _HandleSize(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + const int SIZE_MAXIMIZED = 2; + + // Force when maximized. + // We can tell what's happening right now, but the Window doesn't yet know it's + // maximized. Not forcing this update will eventually cause the + // default caption to be drawn. + WindowState? state = null; + if (wParam.ToInt32() == SIZE_MAXIMIZED) + { + state = WindowState.Maximized; + } + _UpdateSystemMenu(state); + + // Still let the default WndProc handle this. + handled = false; + return IntPtr.Zero; + } + + private IntPtr _HandleWindowPosChanged(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx + // The WM_WINDOWPOSCHANGED message is sent at the end of the window + // state change process. It sort of combines the other state change + // notifications, WM_MOVE, WM_SIZE, and WM_SHOWWINDOW. But it doesn't + // suffer from the same limitations as WM_SHOWWINDOW, so you can + // reliably use it to react to the window being shown or hidden. + + _UpdateSystemMenu(null); + + if (!_isGlassEnabled) + { + Assert.IsNotDefault(lParam); + var wp = (WINDOWPOS)Marshal.PtrToStructure(lParam, typeof(WINDOWPOS)); + _SetRoundingRegion(wp); + } + + // Still want to pass this to DefWndProc + handled = false; + return IntPtr.Zero; + } + + private IntPtr _HandleDwmCompositionChanged(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + _UpdateFrameState(false); + + handled = false; + return IntPtr.Zero; + } + + private IntPtr _HandleSettingChange(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // There are several settings that can cause fixups for the template to become invalid when changed. + // These shouldn't be required on the v4 framework. + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + + _FixupFrameworkIssues(); + + handled = false; + return IntPtr.Zero; + } + + private IntPtr _HandleEnterSizeMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // This is only intercepted to deal with bugs in Window in .Net 3.5 and below. + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + + _isUserResizing = true; + + // On Win7 if the user is dragging the window out of the maximized state then we don't want to use that location + // as a restore point. + Assert.Implies(_window.WindowState == WindowState.Maximized, Utility.IsOSWindows7OrNewer); + if (_window.WindowState != WindowState.Maximized) + { + // Check for the docked window case. The window can still be restored when it's in this position so + // try to account for that and not update the start position. + if (!_IsWindowDocked) + { + _windowPosAtStartOfUserMove = new Point(_window.Left, _window.Top); + } + // Realistically we also don't want to update the start position when moving from one docked state to another (or to and from maximized), + // but it's tricky to detect and this is already a workaround for a bug that's fixed in newer versions of the framework. + // Not going to try to handle all cases. + } + + handled = false; + return IntPtr.Zero; + } + + private IntPtr _HandleExitSizeMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // This is only intercepted to deal with bugs in Window in .Net 3.5 and below. + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + + _isUserResizing = false; + + // On Win7 the user can change the Window's state by dragging the window to the top of the monitor. + // If they did that, then we need to try to update the restore bounds or else WPF will put the window at the maximized location (e.g. (-8,-8)). + if (_window.WindowState == WindowState.Maximized) + { + Assert.IsTrue(Utility.IsOSWindows7OrNewer); + _window.Top = _windowPosAtStartOfUserMove.Y; + _window.Left = _windowPosAtStartOfUserMove.X; + } + + handled = false; + return IntPtr.Zero; + } + + private IntPtr _HandleMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // This is only intercepted to deal with bugs in Window in .Net 3.5 and below. + Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + + if (_isUserResizing) + { + _hasUserMovedWindow = true; + } + + handled = false; + return IntPtr.Zero; + } + + #endregion + + /// Add and remove a native WindowStyle from the HWND. + /// The styles to be removed. These can be bitwise combined. + /// The styles to be added. These can be bitwise combined. + /// Whether the styles of the HWND were modified as a result of this call. + private bool _ModifyStyle(WS removeStyle, WS addStyle) + { + Assert.IsNotDefault(_hwnd); + var dwStyle = (WS)NativeMethods.GetWindowLongPtr(_hwnd, GWL.STYLE).ToInt32(); + var dwNewStyle = (dwStyle & ~removeStyle) | addStyle; + if (dwStyle == dwNewStyle) + { + return false; + } + + NativeMethods.SetWindowLongPtr(_hwnd, GWL.STYLE, new IntPtr((int)dwNewStyle)); + return true; + } + + /// + /// Get the WindowState as the native HWND knows it to be. This isn't necessarily the same as what Window thinks. + /// + private WindowState _GetHwndState() + { + var wpl = NativeMethods.GetWindowPlacement(_hwnd); + switch (wpl.showCmd) + { + case SW.SHOWMINIMIZED: return WindowState.Minimized; + case SW.SHOWMAXIMIZED: return WindowState.Maximized; + } + return WindowState.Normal; + } + + /// + /// Get the bounding rectangle for the window in physical coordinates. + /// + /// The bounding rectangle for the window. + private Rect _GetWindowRect() + { + // Get the window rectangle. + RECT windowPosition = NativeMethods.GetWindowRect(_hwnd); + return new Rect(windowPosition.Left, windowPosition.Top, windowPosition.Width, windowPosition.Height); + } + + /// + /// Update the items in the system menu based on the current, or assumed, WindowState. + /// + /// + /// The state to assume that the Window is in. This can be null to query the Window's state. + /// + /// + /// We want to update the menu while we have some control over whether the caption will be repainted. + /// + private void _UpdateSystemMenu(WindowState? assumeState) + { + const MF mfEnabled = MF.ENABLED | MF.BYCOMMAND; + const MF mfDisabled = MF.GRAYED | MF.DISABLED | MF.BYCOMMAND; + + WindowState state = assumeState ?? _GetHwndState(); + + if (null != assumeState || _lastMenuState != state) + { + _lastMenuState = state; + + bool modified = _ModifyStyle(WS.VISIBLE, 0); + IntPtr hmenu = NativeMethods.GetSystemMenu(_hwnd, false); + if (IntPtr.Zero != hmenu) + { + var dwStyle = (WS)NativeMethods.GetWindowLongPtr(_hwnd, GWL.STYLE).ToInt32(); + + bool canMinimize = Utility.IsFlagSet((int)dwStyle, (int)WS.MINIMIZEBOX); + bool canMaximize = Utility.IsFlagSet((int)dwStyle, (int)WS.MAXIMIZEBOX); + bool canSize = Utility.IsFlagSet((int)dwStyle, (int)WS.THICKFRAME); + + switch (state) + { + case WindowState.Maximized: + NativeMethods.EnableMenuItem(hmenu, SC.RESTORE, mfEnabled); + NativeMethods.EnableMenuItem(hmenu, SC.MOVE, mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.SIZE, mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.MINIMIZE, canMinimize ? mfEnabled : mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.MAXIMIZE, mfDisabled); + break; + case WindowState.Minimized: + NativeMethods.EnableMenuItem(hmenu, SC.RESTORE, mfEnabled); + NativeMethods.EnableMenuItem(hmenu, SC.MOVE, mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.SIZE, mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.MINIMIZE, mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.MAXIMIZE, canMaximize ? mfEnabled : mfDisabled); + break; + default: + NativeMethods.EnableMenuItem(hmenu, SC.RESTORE, mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.MOVE, mfEnabled); + NativeMethods.EnableMenuItem(hmenu, SC.SIZE, canSize ? mfEnabled : mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.MINIMIZE, canMinimize ? mfEnabled : mfDisabled); + NativeMethods.EnableMenuItem(hmenu, SC.MAXIMIZE, canMaximize ? mfEnabled : mfDisabled); + break; + } + } + + if (modified) + { + _ModifyStyle(0, WS.VISIBLE); + } + } + } + + private void _UpdateFrameState(bool force) + { + if (IntPtr.Zero == _hwnd) + { + return; + } + + // Don't rely on SystemParameters2 for this, just make the check ourselves. + bool frameState = NativeMethods.DwmIsCompositionEnabled(); + + if (force || frameState != _isGlassEnabled) + { + _isGlassEnabled = frameState && _chromeInfo.GlassFrameThickness != default(Thickness); + + if (!_isGlassEnabled) + { + _SetRoundingRegion(null); + } + else + { + _ClearRoundingRegion(); + _ExtendGlassFrame(); + + _FixupWindows7Issues(); + } + + NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, _SwpFlags); + } + } + + private void _ClearRoundingRegion() + { + NativeMethods.SetWindowRgn(_hwnd, IntPtr.Zero, NativeMethods.IsWindowVisible(_hwnd)); + } + + private void _SetRoundingRegion(WINDOWPOS? wp) + { + const int MONITOR_DEFAULTTONEAREST = 0x00000002; + + // We're early - WPF hasn't necessarily updated the state of the window. + // Need to query it ourselves. + WINDOWPLACEMENT wpl = NativeMethods.GetWindowPlacement(_hwnd); + + if (wpl.showCmd == SW.SHOWMAXIMIZED) + { + int left; + int top; + + if (wp.HasValue) + { + left = wp.Value.x; + top = wp.Value.y; + } + else + { + Rect r = _GetWindowRect(); + left = (int)r.Left; + top = (int)r.Top; + } + + IntPtr hMon = NativeMethods.MonitorFromWindow(_hwnd, MONITOR_DEFAULTTONEAREST); + + MONITORINFO mi = NativeMethods.GetMonitorInfo(hMon); + RECT rcMax = mi.rcWork; + // The location of maximized window takes into account the border that Windows was + // going to remove, so we also need to consider it. + rcMax.Offset(-left, -top); + + IntPtr hrgn = IntPtr.Zero; + try + { + hrgn = NativeMethods.CreateRectRgnIndirect(rcMax); + NativeMethods.SetWindowRgn(_hwnd, hrgn, NativeMethods.IsWindowVisible(_hwnd)); + hrgn = IntPtr.Zero; + } + finally + { + Utility.SafeDeleteObject(ref hrgn); + } + } + else + { + Size windowSize; + + // Use the size if it's specified. + if (null != wp && !Utility.IsFlagSet(wp.Value.flags, (int)SWP.NOSIZE)) + { + windowSize = new Size((double)wp.Value.cx, (double)wp.Value.cy); + } + else if (null != wp && (_lastRoundingState == _window.WindowState)) + { + return; + } + else + { + windowSize = _GetWindowRect().Size; + } + + _lastRoundingState = _window.WindowState; + + IntPtr hrgn = IntPtr.Zero; + try + { + double shortestDimension = Math.Min(windowSize.Width, windowSize.Height); + + double topLeftRadius = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.TopLeft, 0)).X; + topLeftRadius = Math.Min(topLeftRadius, shortestDimension / 2); + + if (_IsUniform(_chromeInfo.CornerRadius)) + { + // RoundedRect HRGNs require an additional pixel of padding. + hrgn = _CreateRoundRectRgn(new Rect(windowSize), topLeftRadius); + } + else + { + // We need to combine HRGNs for each of the corners. + // Create one for each quadrant, but let it overlap into the two adjacent ones + // by the radius amount to ensure that there aren't corners etched into the middle + // of the window. + hrgn = _CreateRoundRectRgn(new Rect(0, 0, windowSize.Width / 2 + topLeftRadius, windowSize.Height / 2 + topLeftRadius), topLeftRadius); + + double topRightRadius = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.TopRight, 0)).X; + topRightRadius = Math.Min(topRightRadius, shortestDimension / 2); + Rect topRightRegionRect = new Rect(0, 0, windowSize.Width / 2 + topRightRadius, windowSize.Height / 2 + topRightRadius); + topRightRegionRect.Offset(windowSize.Width / 2 - topRightRadius, 0); + Assert.AreEqual(topRightRegionRect.Right, windowSize.Width); + + _CreateAndCombineRoundRectRgn(hrgn, topRightRegionRect, topRightRadius); + + double bottomLeftRadius = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.BottomLeft, 0)).X; + bottomLeftRadius = Math.Min(bottomLeftRadius, shortestDimension / 2); + Rect bottomLeftRegionRect = new Rect(0, 0, windowSize.Width / 2 + bottomLeftRadius, windowSize.Height / 2 + bottomLeftRadius); + bottomLeftRegionRect.Offset(0, windowSize.Height / 2 - bottomLeftRadius); + Assert.AreEqual(bottomLeftRegionRect.Bottom, windowSize.Height); + + _CreateAndCombineRoundRectRgn(hrgn, bottomLeftRegionRect, bottomLeftRadius); + + double bottomRightRadius = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.CornerRadius.BottomRight, 0)).X; + bottomRightRadius = Math.Min(bottomRightRadius, shortestDimension / 2); + Rect bottomRightRegionRect = new Rect(0, 0, windowSize.Width / 2 + bottomRightRadius, windowSize.Height / 2 + bottomRightRadius); + bottomRightRegionRect.Offset(windowSize.Width / 2 - bottomRightRadius, windowSize.Height / 2 - bottomRightRadius); + Assert.AreEqual(bottomRightRegionRect.Right, windowSize.Width); + Assert.AreEqual(bottomRightRegionRect.Bottom, windowSize.Height); + + _CreateAndCombineRoundRectRgn(hrgn, bottomRightRegionRect, bottomRightRadius); + } + + NativeMethods.SetWindowRgn(_hwnd, hrgn, NativeMethods.IsWindowVisible(_hwnd)); + hrgn = IntPtr.Zero; + } + finally + { + // Free the memory associated with the HRGN if it wasn't assigned to the HWND. + Utility.SafeDeleteObject(ref hrgn); + } + } + } + + private static IntPtr _CreateRoundRectRgn(Rect region, double radius) + { + // Round outwards. + + if (DoubleUtilities.AreClose(0, radius)) + { + return NativeMethods.CreateRectRgn( + (int)Math.Floor(region.Left), + (int)Math.Floor(region.Top), + (int)Math.Ceiling(region.Right), + (int)Math.Ceiling(region.Bottom)); + } + + // RoundedRect HRGNs require an additional pixel of padding on the bottom right to look correct. + return NativeMethods.CreateRoundRectRgn( + (int)Math.Floor(region.Left), + (int)Math.Floor(region.Top), + (int)Math.Ceiling(region.Right) + 1, + (int)Math.Ceiling(region.Bottom) + 1, + (int)Math.Ceiling(radius), + (int)Math.Ceiling(radius)); + } + + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "HRGNs")] + private static void _CreateAndCombineRoundRectRgn(IntPtr hrgnSource, Rect region, double radius) + { + IntPtr hrgn = IntPtr.Zero; + try + { + hrgn = _CreateRoundRectRgn(region, radius); + CombineRgnResult result = NativeMethods.CombineRgn(hrgnSource, hrgnSource, hrgn, RGN.OR); + if (result == CombineRgnResult.ERROR) + { + throw new InvalidOperationException("Unable to combine two HRGNs."); + } + } + catch + { + Utility.SafeDeleteObject(ref hrgn); + throw; + } + } + + private static bool _IsUniform(CornerRadius cornerRadius) + { + if (!DoubleUtilities.AreClose(cornerRadius.BottomLeft, cornerRadius.BottomRight)) + { + return false; + } + + if (!DoubleUtilities.AreClose(cornerRadius.TopLeft, cornerRadius.TopRight)) + { + return false; + } + + if (!DoubleUtilities.AreClose(cornerRadius.BottomLeft, cornerRadius.TopRight)) + { + return false; + } + + return true; + } + + private void _ExtendGlassFrame() + { + Assert.IsNotNull(_window); + + // Expect that this might be called on OSes other than Vista. + if (!Utility.IsOSVistaOrNewer) + { + // Not an error. Just not on Vista so we're not going to get glass. + return; + } + + if (IntPtr.Zero == _hwnd) + { + // Can't do anything with this call until the Window has been shown. + return; + } + + // Ensure standard HWND background painting when DWM isn't enabled. + if (!NativeMethods.DwmIsCompositionEnabled()) + { + _hwndSource.CompositionTarget.BackgroundColor = SystemColors.WindowColor; + } + else + { + // This makes the glass visible at a Win32 level so long as nothing else is covering it. + // The Window's Background needs to be changed independent of this. + + // Apply the transparent background to the HWND + _hwndSource.CompositionTarget.BackgroundColor = Colors.Transparent; + + // Thickness is going to be DIPs, need to convert to system coordinates. + Point deviceTopLeft = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.GlassFrameThickness.Left, _chromeInfo.GlassFrameThickness.Top)); + Point deviceBottomRight = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.GlassFrameThickness.Right, _chromeInfo.GlassFrameThickness.Bottom)); + + var dwmMargin = new MARGINS + { + // err on the side of pushing in glass an extra pixel. + cxLeftWidth = (int)Math.Ceiling(deviceTopLeft.X), + cxRightWidth = (int)Math.Ceiling(deviceBottomRight.X), + cyTopHeight = (int)Math.Ceiling(deviceTopLeft.Y), + cyBottomHeight = (int)Math.Ceiling(deviceBottomRight.Y), + }; + + NativeMethods.DwmExtendFrameIntoClientArea(_hwnd, ref dwmMargin); + } + } + + /// + /// Matrix of the HT values to return when responding to NC window messages. + /// + [SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Member")] + private static readonly HT[,] _HitTestBorders = new[,] + { + { HT.TOPLEFT, HT.TOP, HT.TOPRIGHT }, + { HT.LEFT, HT.CLIENT, HT.RIGHT }, + { HT.BOTTOMLEFT, HT.BOTTOM, HT.BOTTOMRIGHT }, + }; + + private HT _HitTestNca(Rect windowPosition, Point mousePosition) + { + // Determine if hit test is for resizing, default middle (1,1). + int uRow = 1; + int uCol = 1; + bool onResizeBorder = false; + + // Determine if the point is at the top or bottom of the window. + if (mousePosition.Y >= windowPosition.Top && mousePosition.Y < windowPosition.Top + _chromeInfo.ResizeBorderThickness.Top + _chromeInfo.CaptionHeight) + { + onResizeBorder = (mousePosition.Y < (windowPosition.Top + _chromeInfo.ResizeBorderThickness.Top)); + uRow = 0; // top (caption or resize border) + } + else if (mousePosition.Y < windowPosition.Bottom && mousePosition.Y >= windowPosition.Bottom - (int)_chromeInfo.ResizeBorderThickness.Bottom) + { + uRow = 2; // bottom + } + + // Determine if the point is at the left or right of the window. + if (mousePosition.X >= windowPosition.Left && mousePosition.X < windowPosition.Left + (int)_chromeInfo.ResizeBorderThickness.Left) + { + uCol = 0; // left side + } + else if (mousePosition.X < windowPosition.Right && mousePosition.X >= windowPosition.Right - _chromeInfo.ResizeBorderThickness.Right) + { + uCol = 2; // right side + } + + // If the cursor is in one of the top edges by the caption bar, but below the top resize border, + // then resize left-right rather than diagonally. + if (uRow == 0 && uCol != 1 && !onResizeBorder) + { + uRow = 1; + } + + HT ht = _HitTestBorders[uRow, uCol]; + + if (ht == HT.TOP && !onResizeBorder) + { + ht = HT.CAPTION; + } + + return ht; + } + + #region Remove Custom Chrome Methods + + private void _RestoreStandardChromeState(bool isClosing) + { + VerifyAccess(); + + _UnhookCustomChrome(); + + if (!isClosing) + { + _RestoreFrameworkIssueFixups(); + _RestoreGlassFrame(); + _RestoreHrgn(); + + _window.InvalidateMeasure(); + } + } + + private void _UnhookCustomChrome() + { + Assert.IsNotDefault(_hwnd); + Assert.IsNotNull(_window); + + if (_isHooked) + { + _hwndSource.RemoveHook(_WndProc); + _isHooked = false; + } + } + + private void _RestoreFrameworkIssueFixups() + { + // This margin is only necessary if the client rect is going to be calculated incorrectly by WPF. + // This bug was fixed in V4 of the framework. + if (Utility.IsPresentationFrameworkVersionLessThan4) + { + Assert.IsTrue(_isFixedUp); + + var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0); + // Undo anything that was done before. + rootElement.Margin = new Thickness(); + + _window.StateChanged -= _FixupRestoreBounds; + _isFixedUp = false; + } + } + + private void _RestoreGlassFrame() + { + Assert.IsNull(_chromeInfo); + Assert.IsNotNull(_window); + + // Expect that this might be called on OSes other than Vista + // and if the window hasn't yet been shown, then we don't need to undo anything. + if (!Utility.IsOSVistaOrNewer || _hwnd == IntPtr.Zero) + { + return; + } + + _hwndSource.CompositionTarget.BackgroundColor = SystemColors.WindowColor; + + if (NativeMethods.DwmIsCompositionEnabled()) + { + // If glass is enabled, push it back to the normal bounds. + var dwmMargin = new MARGINS(); + NativeMethods.DwmExtendFrameIntoClientArea(_hwnd, ref dwmMargin); + } + } + + private void _RestoreHrgn() + { + _ClearRoundingRegion(); + NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, _SwpFlags); + } + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/app.config b/Microsoft.Windows.Shell/app.config new file mode 100644 index 0000000..6ff5afb --- /dev/null +++ b/Microsoft.Windows.Shell/app.config @@ -0,0 +1,3 @@ + + + diff --git a/TaskbarSample/App.xaml b/TaskbarSample/App.xaml new file mode 100644 index 0000000..3c89d00 --- /dev/null +++ b/TaskbarSample/App.xaml @@ -0,0 +1,36 @@ + + + + + + + + + + + + diff --git a/TaskbarSample/App.xaml.cs b/TaskbarSample/App.xaml.cs new file mode 100644 index 0000000..797267b --- /dev/null +++ b/TaskbarSample/App.xaml.cs @@ -0,0 +1,45 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace TaskbarSample +{ + using System.Text; + using System.Windows; + using Microsoft.Windows.Shell; + + public partial class App : Application + { + private void OnJumpItemsRejected(object sender, JumpItemsRejectedEventArgs e) + { + var sb = new StringBuilder(); + sb.AppendFormat("{0} Jump Items Rejected:\n", e.RejectionReasons.Count); + for (int i = 0; i < e.RejectionReasons.Count; ++i) + { + sb.AppendFormat("Reason: {0}\tItem: {1}\n", e.RejectionReasons[i], e.RejectedItems[i]); + } + + MessageBox.Show(sb.ToString()); + } + + private void OnJumpItemsRemoved(object sender, JumpItemsRemovedEventArgs e) + { + StringBuilder sb = new StringBuilder(); + sb.AppendFormat("{0} Jump Items Removed by the user:\n", e.RemovedItems.Count); + for (int i = 0; i < e.RemovedItems.Count; ++i) + { + sb.AppendFormat("{0}\n", e.RemovedItems[i]); + } + + MessageBox.Show(sb.ToString()); + } + + private void OnStartup(object sender, StartupEventArgs e) + { + if (e.Args.Length > 0) + { + MessageBox.Show(e.Args[0], "Application Startup Argument"); + } + } + } +} diff --git a/TaskbarSample/Images/CircleGreen.png b/TaskbarSample/Images/CircleGreen.png new file mode 100644 index 0000000000000000000000000000000000000000..06136053e1997e20dc5676b9141df584b7cdb9dc GIT binary patch literal 141343 zcmXV1bySpZ6WwB2dg+FxyA48M7Z7Oyk&;+iB}F=yr9)Uj3F#71P(r%9Lq!_tk`4jM zZ~dL`k3D;qb2!hu&&=Gpb7$UYU7ZJH#7x8h0Dw$gO+_C70E6)#01S%%i%)gKEBqJ4 z0i}%s0KW9zC5YL?|7P^KZ|w2N)!xI~%H0ltvURn#L#R7jIoRpjS=su&=(D>A0P&Tp ztDp>grnfT*16WqmZn8zD-~TfFw4?pg+y&G2K8&2GFMPn93PiL*RePC45`uGEfrUX} zi~J9!QN7_brm)N~U1f<{U8e!_WZS;S)jTGKDPE^7d&WW|%@;aPO6_NkR;9Lgw|i&o zy|d=;jqLf}LY4chF(%@{-8u#%xg~2>tQaPsn|0E*Z?VUxVG^uFejk=o}ZgY)Jc6 z^pyGag{^bPdEBF`Jy>H(Ma^Pq!)3ovVG#7Tcth0ng5v4%56ZqP{G>xuiXOq!k2Y~9$?oF#CA zC?sLAWcAO%g`gp=2@)qE#>oL1NO5B()eG@QxjBbGImXvGLrPqjxSGknSoM%F^v3<# zLLL2uyETP*GI-~m<1GR5g-3sCr2cX|oSJXGT#BW9d>=#1Y1KXPh=V+l2B6>8gl-k( z`;h%?A;B7elE6_N3y{n@D8mQOE+4BLBq*tD^veEmz5j;IH$Rx3k_sYOqwS-Wc4Hs* zq9D6(=d1{>P9s3P7uz6u(tN1cLu0nirnynyYjapbJA3!T1;K>+oLHIY;>(l7{kq$b(W_efXJ?PkqMq#=}&fe)|LkNJ!6Q!x-eD!w4NQ4N8iiQw1kA_8=0 zrxKvR@fIOEk6z;Iu1@6`Y_JR{w2sU(+Zd--{WoDR;6XkDMo$fOzhQkf7%WDu5@Jxs z{<=I+KltT%-TL!_>(aZHfw$Xd>3MWiVbBZWcqystSBYFq+&ZGYbcCEU8qtJnCw;__ z!VpC)qLLdbxyJH{c&sTgSo!yMOWZa_S2tI~3qxxxaPJcr-M$c&lY1rDJ@k)J?2s=-{84#TG?WRmv1Yc=^Jzw?CKTn*saFVNP0#k<1^w#No ziRGt(>feZFTt`2A8g_lXbN5$NRAv3dO_Zy)tV2R|iHia)_che&$N>pgXmif*j6Cfbs^Nj+4MmTIe(M4g$FS zvpL%YI5|Jx{5riw3<}~w$=v7<-w_YpS&0H`CvtM+EhyBXnhjdTynD;ke~Sw&QriTI|X9$ ztiCe>{XjZVTKsQRGZQD$#S2-SjTBDL`EW~ZrB%%I4y4bHu-W^Eb|2)*T?M1M5>$MF zT)cA6PS?-PS!s+lD@XA8&=ZfDv^9=i>7SNYQ(n|i8<#()eZ<{(dNPy8X?3RpnwQ7X zwS;tfGR3!2012H9rmqCU5)~xid@yl2@rxy%Xi45;Pk|BgD9EAyUeUIcBk^lH3LPYU}AjfiyWzveD1nPB(o0=g_FD2n??uh}J zCt`P_90+bGqn%ev=>14dI2Tub=xD-;_F9f~RQg<>YE*(bLz*~W;0la!{ZO5b24y>T*vjQA?0SY1vwk6}W#cGSJsS6>H|-hGs8bAJ{5tpR z3_QvK(5a&Q{k?Vc!c8*!m72?f*t%0o2HH%BvNx9CVw#4CP)&&&pyoiL|CpECZvQRu zIq*&9x1xz~o@z>Jz#?}z7~@f_KWh{?B~Zi-3-jD-qEG9S5OS>qQ*DJ^2hu=bi69AF zUr2xk=p+q#j1O-9UP!NB33mlJ(SA{DguHcd0J{Q%j-&Kl_7%1`k%H1V0l_ZG#{yEc zk4BCjC|;KvylTmiWa0^_HEeS(#XQxm=N4iB6jZWRe#085(<3-?5s%OFZ>r?(Zc7lfe@}WiKDswT=s2#ja?Sf*Rt|B}kZRzCM9F;2+s4E#=Pv1UK~O8P zz(I0;7~*XV5y6O&URoqo2rdq-i(m_bV78Hp)D>VQkgi6?u&Nh=NUT+>o=n}I5N-c{ ziG4n(A<;0yeR!LXImeLz8&KN56BdRwTsuk^(ZiL%;Z%TPI-runMF(e12Pd#;G_d54 z{!PT_5lLv{cb@V3%@ON^!_^m{#f~aRuD;7=9vfl%Uw4zXF&WEIEFri~S(6?Y8e&*t z27@kE&^$^~L=LfB{^&KUuKQRrF->73NQ&{^dlf)IMY?XaEujH5P=Co5dW}i5B@A+3 z&vXwBF0WuL_nhViUrp7DzA;g=TSI_r9*i3_IaB&yY}g8Hjs4S1KzKw@nS!z+N~F zk#o!08GSZ}_k&<*5kK*P=PVyH1&nSDejnOx3%OLUg44oDV)`RgPO`JFw;hVfufvDm z$7ZI{lZ;kLPHfV+h^@=?QbIMfhjNfC7?560LHGxKc4URaO%mC8*SNr(#fD6noq{*d z62`>vt6N{B_zg~$$-sb<2GF1-_n#MSKX zhp9{)Pq?)$b-m!Z&#ZVUo|wFi!Oq0Qw@3|#6DC?Ec}-TwNbm}yJBpFCL`f=uFlnCDi7#c6J}bIopUSiat07t`h|D6A%r=6# z(&9qD4~9Hd|8|+2yxFn$K0zTyJb1aYvrX$gO_7`&CbSoBdm;r+Wlinc#n`!JwXbAT4Y(e8b2w%!oA{bKf zejaM{Jp0VqTS8>aX!S(U$GAf3m2Py5ak@5-o%~lAj=6ISQk}LLs6V2tvxan$c|GZ$ zvagWxHkoOMJo0`=mn$XNjrY3}ArX<=21bufeA*It7eiM`kgx2|*@+@MURR%-tIeL12^Vnx=VtL1c z?XY>^qt|RNJI$8@P6~D7_G^i_(bJ#Go}35n?e*SNF^LGbpc%c*m9JQ*W^-<1Dko{Z z=X-m5Ra`CS`6)>V{rw_(^08KuG{oMXo-gupzqAA&kLD_OtenSZ$`SUSAim714s+g( zTK|$%AIuxfb=(-Hq6B;MmL3SJxn20h(P#c(c}tfC0RvgvDM=lZBVdVlLCE-GqiwC0 zF%w@y^yi}LpMA9oNzR23C8hW6_LU|Yni_*Tk@=nITXZVmYbq*-ndgqN`5_hKwzqx{ z4D=7K)ExJoQ8JLfIFRrl^M08U`VA2@a7MR#9@56fK$4)uPlc7=@t5*T5ftPX{7`O8 z((CykH^0-s77KdCcF%>vJGiNsO;DS5*3-M3IZhTF_fRX0{C+sNPviK0cxSmyPj>8MAC8QtHfeC|N)rJ0Xh7_ATRzbIK{U{uYKCZz?_`hX zUeCLC@7jNV{MbG{J+1Hl>`oe~9#GdQ#v(a6`Q171Ihy|#N5B9Wy2_jG!trEkRd~A{zom?HV7cNk5;9>}GF7HunWdOMAh|AF?P`ws?DpdHdQn(x29uwB|@* ziYAAm2|g7vWpwH6em68Gxz-npBYhQ@B+0Fx=uunaoodVMwLRpr7PacOqeW=%u~4FongQMn^q>#$aVng zP>)oN2t0V7OnmzZ-kMGBF8pQ8=pX9)me(_K!_qkLt?j~5A=XO6OtMc|>ah|FA^rfn*>NGS#LH7HPA5z@# zGm_GDnki9ko6I-5x`L#g5iQYVuQf>tbZHQ3Y*9cU3SPtOrx*i-=-r2K+d%B?fSu=; z1EmM_f+KoN3qLeNMg#5a?83jbw!DK}uM7rP{WP6sR><37+QRNe%a?gOiLqqe!(I?4 zN)Gx-4HjpChaSHYPib(%_OXj{wm)2b zXGu=_@LLZ%d(irvx4%;EXf4uBk;Bd0DRWkmr_Szvi42*0WTtuwWiCGwCrk&9YqfO2 z7uMOTGa@dv=l3y*!k96D_&7#v`b;wg&{w=;L^G>dB2;E*lyZJ`{XDzJrfSN`j^pLz znEW@g%;g3vZ;#E)?T$cjpLCoo*Wi~l!dNE~s}N5G;SXsPa$eipGxg3-_IjA_umpMk z`JJ`6xTvSvD&`@;L%tG4kekRU!BsJN%NEl)2-IZhjD+!%!nyrBTLtta;FKiiJQd)7 z5XA!mAWi5HUTcab;Ih;#G;yX2u}=RRnXA$r{Lf*ID-R*To)tK=9Bzzzw<_YiC6Vs!MtpECkf;6*0NP z-(8O`>)tvrHWxLjsv9&=!QPlt?~GE?0(#ne+=7wrpck&d7!afjX&)Q1xu6jJ zU&yFyKzaoTH16QJ)a3vrK*{0K#Ni?>BzW7)?*9G044Ic1E=85oYh{nA^7nT8L^o15 zFri74)6{*68gV=s($Z6PEIMA9r1g4p8-#jRWnOdjpmBJ7vd{Bmv7K8tAZ_pSr$W4MU1a8*=#v!vRn#kt9vNYu;uhuNK4E4 zZv{yfk$UyPxO<|?+@tMir3h&>V`2x@5|aN3;?^dEW)z(JNoVVE%_A$Xg+M&Yaq<9= z?_oIv7#2#z?Kva$p_WvDxb9Z%R=6H01XC&sFPm|66r%X;N9^@*HzJeTd6Zf8hZwfE zOCKGB|B@-=w*~M41vzPnWlQt=P|dID8vH$UJVMD^;#CY{>+4V=+%TP%lKT`$ zm_rFy@?Vw+|A%I_u>hVzq*ClG6{4|G!E>&?;orbodFG1Ouhi4;U)1Zru zbl2v(J=fryi!2I-%Y9g<18H~h7WJ4X$7_V4A@{AzI8m;|ca{hPrLg9I@i*Po+Q-*J zaE9-u@aYKAUnI;a0{!@bDU<{daHd$VDjcWXNCQW8EnO*~AoBFe_w`(3eMFeK+|L`7 ziecF@*aCG1GvnYO1BMKO)z^owgB$;hU(;Lo75o2quiXT)Mw=lS_BCH6_A#k3CWKGF z$>T@rlG@fYq+Ub&2g!37kh&0lI-sy3#^5eunot*kfKt_;V|p2be-*wqVoW5Jc!6ZCutfD*4Rg1kxjHwOeHQUo?;?KrUF?8I?p-)doUqEB z=X)nebha|U9LNgl>C_o8slOT!jIu|%Gr#OHs~ zbeBiqz{`ucM^XTm0!Z)f$I?w=?~dwy@(m?mj$i>_;I@ALx6V?o8k;T5#b})FbJ5J^ zn@(2`h=(bwH~SPX)$8DWj+>wxH$~C}3ckyRuy4_N8|<42!HpX&BO>s$pb|Ikj56}H zz{^zy9U3#;V79OXRp`9`O`r~g(@b-w80pgxM6!HpSSMA!I%7N1sVr@@z=i__S0~k! zbSV06R@}x)(MKjx#wiHplU5Yu>5g{ z*t>1mjoBl@`$57n^_ff&tjTbMV9L+@SQ6hFjS;OR&Q>#s=-LV|RTqnXUc>Gy*>KP> z5$7U}0CvfeF6QOM3~>bAasGi|F0i-r`lF9=$u(LlmmZ z-D#e9QO6T-nRv-sr=qW{{8&C?Q;|!MbU0Ei*k?cU=ciM}lTK<@b8~a>8#r1d-~}>0 z@$DOGB0Hj|FK|_Pc=na}$QsFimh$5{4W5Z{B45LDngG_N$gb&NjjV%pbDeo3{6Bx2 z9a|wg3y24Ivvqvl7u|q)t0o*TpE2?=Zqsj&Ad9}eXpu|a|H zok}_GtN2q)CD@^jN1MK*ZCJTU?CQ^#xsiLPW)q{MqcE}2A}K--nb*c^nA`Kn=VfWe z{`$q^1&mz8x}=D|Tu|=u{C^>?76T}+1L%WWJ0Sqp_ zReJ4kXh2{@VK3l!xgKJ_wjiCnP~*{fhN(6j4b(#+68{y%9GF@(41NTl(FH1I5{XNG zX1-FebXE>*s_A}gGhg8OMEURb5CgHSp3MA;DFa z3P8WTNwuC3q0>CbShKe@M=U6q-a_-5V00#5siL6;agmVI0^3N)*@~>pz(Z`1dv{Bx z0oGNY4kZaup}`fp)+Pwab7Dh;!TI1>9szl!rQ%N|%NkLlE{(8i=gFY`1HSBSpPfGw zr;n`B@9{Yq)TVVGrF6W_Aj976*XO>U2=U+ev_I;T2h;YxS}bb5(kMeAB>NFc|eDBEgc% z3f`bY_nn6bIDDkkA9-zet*Bi3-fN>P#p3sM2m8(Bx0#8%sbS(dGjHRiIsrQ(sRa+S_O zsKueor>yL84Z+FtleM2cs(yd`KQ+!;i&VR#T8djcwI}bxs}LZ}-~)sSNZ)YGvw-B} zcxO@cNS(zXbzrgLzGax^dLW&G>D6MhqQc4K=hKOj&5*Ngz&}1ac?l{`BPdz4`})mi z{Qkd0DCz_Vji#jkLlE0&Sk7rMS?>UJloOLhCwzzbU*wsCY(at~x~8V4zh=j1_6Y+O z^ohUTuc1A^{orV6nbYBX?ybv*FU9MUfR#HEcM}OvlHrqXw>Tkc0(w1*9?4 zk=Tjg#;^^gv+sFgtv(|v^N)i6YVtjMNX&yHDV$R)rY^AU3%k3#^j@5!=Q9a;b8pIdpBROqrRPE`Me{U%xZwHCa5vC~vy9 z=7E-sP9Z(!Bq{!TYIMPYCUcumFI6;oSdGFtAy~*?K1z(ocDkf838046Qw|Illg zGtv(k-NIK5Mqx<7U|R_}N*2Bg@9c*#;H{)yK0hw(*{LQBMFm@xcGW*_A@katepw*| zC))2ri|H>Z4`1J%WNLk~xf&6`p*GBVnct(HC@|^k#`pElSJb>Ndx|zfQ}L4Prsey zo{jVbV8;?wx?`$KJ)T9~mMaT)UvtyWROC6(5UwKdt6k#$xARdTqKPw2TP?EI7j`Y%a3BT~y%Li80wo^HbN>F3bd`bPpioyVA9x=?=*EoYW(z&pxDT56VV{T4=7XRz5B6w6ru` z;7RU<`IBlF`F3gojS7MilzqU%5Mxb!Sxub5KYJiuco~Gdi4*fHyGsN6<{V_)jUG1x zpu~_)cy>y0)@U)}w(9om(+jENH8tLxLH+Kks}hmYRZ-Se@>wxT?k?Q3-U7SL=Ig*& zr8TAkpC}ho@l9>BzoWPL0?90{W|%W6uGa24H%!l5@arMgM07cc&#W;n>Vmhjk%s?W z$Ui)qOc8<^;yKtDJ*Y$!Wr{PR;=Utc+)v%gPHIm@1+Xn9fnMoRF0g)i$3JK56wX!8 zWpXo4&qPu;tT;@}#|Mf6Am&2gkhH+_$O|jid5d97dtqu6qM~OB!4HJND{mmto`g#^gm%6l zEo&uADmEGxWz0p(tX=A6>@EFi-YapOujwWlR`zzf)*X>?8H?B~^!|_{#KD<|@!;dk zjIKztwvh<%?OS!bKVY}NR2jTeyMBF9b9!<@9t8tkd**I-mjLa*io^SY z|1~4h#k1xKIvNyi5KAh_RY?-XFd2lFbDC?p{ppIJ;9}G$C5S-O@h|7S)8nHZ?^(}@ z@!Z^86mFOXMg%Tiw9_wCuBd?U6XRy-!Bik1{`5Q;KyaTBJwk$$6OVgKlp_ZwvI7pT zd|&mbzf{P!bQSvW%NpOrl91c(%xDjvjl3LQhK9UO&M92epCzQ^)YP&w`80z}ZjsNA}lyvY$5`IVjFZ%F4>JG&w@vyrodD;(q%`mfIE0NDSis z)YV#C6a&4`|Hp}^!nVXFFPBkc*@_P}(_^pn-_ z@Xz53#mAT_^qNK}9Mbn4!{z71#>T#;5v}$fy`1$*Tv8$N?U%y(GUCq)n_K%|^z`C22w|5sN3W=|igB36U+5v3*3sA>{ z61EW+Vn)Bek2HDq?6EjQ$)|n8+M0JYs2Yw7UZ~?OCUM$S^k*AUVRtdCyQT~upw|zA za*ymA<;GL~7gD4O+vo6;)4g?#*os&0@|Z*)xou)c+5=Co9&U*R{rSZD$QmOCQ$<=3 zavE-qLb$zHsi+B3d64d!q$P1Nz+xwi@jo3%GFAy$j501!hKqn!Y(Yz%t?hr0*6S{Z zTki~zPue|CV56*9&(Qz{;#-jrG>I7rIzEt`fh2B{42C-7fJL)?iiRNymAB+3UM^vL zNP5dEo$~soA&Syls<1s0cE9atzG+LJgDw{!s#TJ?G9slsEM%11h9gwMo(Ojd2V+4T z{lDLz;wiqq2nf(w2~>hw;SuaB9R7|1y=LyNsT>%XIkS4mR(wzY>r@48_g5Q}qw(Kg zWyR@J>!MpV8#P>P=_q~s>h4F6m^n$`CJbwU8WCYJRLg7iYzJETdrPA++1F+ z&&YZ2?S`Id0X1oQhiFFgFn1Vik^z0%5(tLv0XPg#8)!&?#iA%Ci~TPIt83^aQp#5I z=^d}4k>vx&ZPTsy?S|4HN3x3BpiLpnq=pWqp@q$b_)fY#kPL-`^nP8Y@Ct6N5|qE= zC+wJYx6k8xrb1|OYv6|L`f}xmbIs+(gHl{754@kI4AREXnL_q0DejpB#stKD+Sz(w zZ0Y;YABmil0E8lQ4&mP^K&}k1BoW~vAS^8GiWlX+xEuMI##Xl~*qo$>_MyvuFFk+y z(RoR$jav$XfN>I}xoHIu`1_rIV-g@vJa#m404X8T@Dch+*Dw-c3ed8oIJ?RaTX_2CTjJ3Dsbvy`2_U#Cn;JOm&bMm=!xn_) z9&k)n2Q%MYtX>3|&odmB~ucGB%e32tl1K=JD3Tx1kKVhO>_%aVS~TkF1=vN&&KMizW|l`j_* zaIuqKguStfV1QE*c>EpZhEWJ>ifUr;5RH5v74le5BIg!!Ys)KZfO-fVzD3jdoL-O{ z(%B!@JH?02BEO*i+Ea@ph|o4QI*geitoI44`Quez!LnAjl`h;Rwh%rBdUFQ0;M%;Csd3z z;;0K>ofqc1f8qx8aPu5L+4~2Xv zPDcfKDysUAj`YcKAbv`|5d$5+fh{#r6cPIb}HM@GHCAHPbME z^*up0)ja|x=U21G=vS(t7c^Le31OP%KLN0@@`%-?{sr%dKpE{sE5*oPG5$>vnd6P+ zgc`-0b`tY92nOiEcaHH^$?JA{h*i{{Y?ui?qtm#cI+k_%9*1RPJKhFV;Iw02&PLYX zDq|WXKoQslxS#^4p@9|t3UiZXQ7HPc$zGmd;3P5!U7kLO3)t)RSfF}Dv`%EaVbS~Z zD<=%QLQELXhNn+eF%$sI~y zh%}6Eyl>f94b6Q379lf~)hxg7GSgs2pZEG;Q23|t9l8!}hd}nVjr5D`fZxUO^HiY{)J%*&smS->3zPh6{`9dP?X9VFbebz8!ynbz*LWtvEKBa~mW92#y0G#I zkmkx>c0ZM@J!+p>485y3d$l~{>bkSD!-_c*2F}I2VKY@7;mw)B@j8ljyD0NR^&>2} z>(j~iZ@=L#bmiiQARC3%oD$1$c)=Cu!Q0vi2hvqenX!>V-o?&!?T*I`xsAEq;+n6- zH!A;i=)kV`*0a%gE9BHZ*;Y6ymSv{vjn2(vzR1GfHg{ZXBoqsC%{(C+slUDFd%YeU z^viGW>eMxyddgAW)4Zov$Gd--or2G|M`OV}p^37@OY8OK4!bG}Q-FxiH|mrG&;CkQ z@d8MJeZ@d4!{kv{x`$-#!juSmcsw--*wWHRzdyXgzY`X}qyux5{8E^SS2Ln9UB9|? zpP0tVQDPCW=%|jQebhSPYzFq~fmCIia()$Xw|+xs!+7FbV9&$g>3Y|jAjy)rYz~B` zupBal;+1m1dyJ)Qn4Pk(8gEy*Y4p>Fy0_7;)HEQ(oQT>7mMGe@AG`~b`qEW2_fxEY z=}UT=eEj)*V0}2PvgCcP{q99|RoSNkd9HBeC{q~8nmK@8q!t#A4;2_ilOe^x)xct6 zvgX1{Yae5p#N2o#tLWbyMU;bY(N<>7uX{H_MrPks;!%%!@+Ya}3~3MIEyLl#AR)uU ze)i;N7@wAmtQRbWatE2x*9vh~jFO?L@fI)6KR#AZkL;`RX8JWGcRySSIS!X7uLJ65 zVvWtQwOv*<7u#O`=vEos^2$aLuKSqMF(`>SN$%9IxMlzZ1!wg5v-VCDTOH7!ezuOPdfAW^gRV1Fyi}5K>+8$!>s13J24?< z^uXhwj^~Vmwp8Q5hDW+i5+P^%;!=C0npQT-9hXcAw?|Fu2;x%{Y-ca-M})n;ldD~& zt!rW&EeFRUqCiTo;a}OGN8;Cfdd=;b!l5LyLD$Z@?zP7Y?CgPGcitLV&UL^c0ihDk zqWGby#}sZ9CrN`BbL{mwvMdv9%_^YAWX4doV0Q3hm|upZ1$xXfoeJ-M9sJ%eOon`pbQJ zcKKxSVZy!YD?abpa+&()YDoB~306XFTekD}9lU;dOqs)w8YqDf0I2+%UmxnjqTUjG zaRtDhm{b@-?GGb z;1rum-$Jz0qdaBJB?L$W-D&IYnmn<3K%{29nhjR~NBT!_xu<{Q1T7U=0W$_z4YIMhs$n1U|DvUH^%>0YHQ!E15`ku18;B&xaPaBn7j+|j0zYAbnL-fgU2y)At& z)#S%2{WN{+Rmv>b(elZJuX$sg4{T`$N1PV>4AnY96Xt_O#@8|Y!)xx&*3BXk2Z(JH z7;gX<=(0UV&&>eSfHsJ+Yr7LUOKV)q6mejOVqZwRm0#yBoq zYwm`3lt!M;UjN9h_VV`b8SL^%MkEWM-;zaFvC|4NFQt$iY&l9Odw#BC4e~ z&^4E#_dW;WwjySa0{4y;VL;WX{mkjPlbOM`;7RrL9fvpSwX^! zudlE6b!OzsF7|ihe#;)S7X?xq(tgmcL#}+QH8VKREHB!`6ugC)L!Qs6cU!{GF!d7&FqK#x24UDY@Q7c;US%i`rPz7#7x{zS2t zA;~S|GvN30-?fQ3_}*#O1P(z-vLx0udGr;QHNTV(nEmsjn;~v5@FM6;x-56;n*G-! zJ$h2Qd9RC|Quw@2sKS(L3h^^kZ2*6D=ktOyLcMbgQ<}n>%@iEOnFe%mRp*q$q=l5= zrKjk2YgH>hFTgxI;?8}aY3^;WI;O^;z02y~cP5Q06kn3_7gm|wL1)>p?egOuS%fiM?eatTD;= z+~S4oEX~$a%F!d(+0KJ-=$l+Ti-$)V>a*_4K@L90xX5zTOPgg$<9i9U!&rlK2(FoaSbiXAY|_ z8y`1@Q%@t#Kx=aA%4vn9-ZcLV$*(A*(s8|)DYtp_kL@vk_c*$sxQ0C;cL}!)JX$B2 z6*XFY4tcbtbDsm>!6y#%v~2_z2y_Tb2A_By*MT?SBMZm>)(2N_C=!3nXw^qkjYc&NFFWsJW8Ti-a36wOUsO4>yPJSqR#!>bH^C8=1 zNA~sDN&lxWiBk5;xJm4r+f~N>##%M(wC^6c<^AEehaK|9|NJI&slfh(r+1Ki`}4N` zYV^(iBgIbnXZA{%pA}kS2+$b_lf|huLb8zEv`_)$O)CB<%3xM-v^85AFCzY#{o#eb z(tE?Kp8<3kG}1)Gufl7S@U?V>QMQyEkMR4CFVJXPzQcV-sV8~>LRifRfu8_kY4 zGv+xzJNzBTS->a9R@b1o86@k`-@$2YNVihYsNh9fYRqLIrUb3)%=KyJq{ zjPaIkGlRG;wiR+Phdsk0k||Ryo|hN~zZ#;G{=N0ZK$Bmik$r*xr5n`B9X^VF#*Dur z3uXIWvx*HWOT5qVHLa;%%C>%23IW60= zY8f2J6oPU|V8wLgH~~nc8aXsew)<-I$z=M;Y5vC##G)2%5)nRiL*TWiXRBDDFA6DlFppZ3eh4`(|sJk><9QfCB z;_1b>v$RxDxJsBG6ao$;%Ee@b#8HEk>`+R0a%FqB^v?SPRyg8$xA@+EgLtbDjEK!Z>@-pqX8*( zbcWf(%1Ar#Qm$Wl>d;S@lut4=ang5xIz>eBHt|FhXm41LSi2;O(tGWGAvX4?K8k#vtA8~QolzTI|Rpa0We@bvvv)4ri^T^+Eh zu&UMue=0&9wKf`1zxt!B-ubrE#xLABUBTX-1(;qwfar4ZsKrqj|7Jw(VmGrQ9VOTl zzokjXRfa_2_?|KXc`oWxGdkmtckmrDFD8p$i#gon8c^Y;tj9wB;ANoATp!^Yi&g_1 zv1y)2bhgs|Fz>%;vuERf_I0+euyQ?P$TL@yFSDs(F>l@s6ha%)dUZNmNu%Qf+ekFO zev!V%6~(%2656-1XzNkKc?@5PWxz#Ar%k+Y?Iq?wGKc@gBJ9N_fekjea1MwxIB8

`+Cw*IT|sDZ4^Jc?7=v*B-3_Bhcm%lSzonKXm^>g_dLIk z9SlQeH-B#1M&2O-Hj80a$>4)fTp=FdOjkrmo%UU@-)?!6nl6|E)<@*n@x8*Vz`uHI zLJukWnGIbZlBXDizBJ7qxN=nlh*7kdT?DsW4L!R#9JyhEoCsql)#asNBb*D~)CE!y zre8evFn72K)OzYi>xVC&p5z^Enx(U(bCeJj z?Z_kKbBxBngxUK`;TNU;J01Rb^qI%3Fc#nQ`*?1B8kHJNs$N%;CHq6linW|Si7mu0 zF?atPA(tX<-P4*C7fx1(X?Ia^SY%K_Z_%zpD#$wB@oa=ZQVBNtDEt`*G8Rz$J!dl- z|LRB`uOK8@XFS|&CS&G@Af#Vp)hv?m`#ITv{c<9?n(8|(5#AuI$D#d<;==d&D-tu` zp_KLc%TRV<$Yz^u$)asJDX^surl^Tw#IoG?a@3oe0&>qOVX_3Z9@2>d77r0px+2Op zDR>qx`d#+exTAc!>G8$)b2fNztMAcpsP!WWZ#gU<=f6w7rT0{LC0_k;*W&Ap(hY$jp*%IgSb*UKo%S`sqBBx)#?wFB_J6y&wqH9`10p-Lmd zX9OUfHP3C{H*b}4kVsgWER+`5!KZ8fnD*&&C+Sje9aqzEz%ynINnp0gW!kfU)g6o2 zjL>RO>2iN}Ym@hU6J(MR6l9O^Quk)cn~Cq%5k4Hi5#W8B zp_G1Qjntr%Bme~Mrinr};!$6%Qg@j;uP~EN)e*?d;J;oIlFAnub#a12&Je zRDl1W$#(Ju6Q1oZeCJ8Q;6|L6>H>gr2&(u1K{>`mXefi5Ec+b8bJ`Gq)S4&m+nw$ zq&uXM?vzFe32CIe`&-`MIo~<^_s-sX=gvI$nP+CdjW*(D`gD?vX^~Z8=k1?=tzpkJ zII}9R;QMba;64z8HgD~4J;z5GZf0r1qdMjafBc!SNNi?yHVzK(HfwJ!3o^u^g;9j9 zDRobb@%}>#Z^rHV%7VO9AYCL|GRomkU(wIk{_E|;_|7bd!HVjcTod0nB)&+-8iq;* ziX!cNG5ba(oHAtB-h8T0Mn$Q4e=PGEs`q$@b7Z)=u->veDz;MId}#Oaa4U`%kKKw$ zM1&YM;s z#JflyP3zyE&5lN=v5mpdU%lV`+Hro6*f|+orXLQ!|KVH=?uqWLa`!*vBN~DZSc^rF z2XGLA15Tj#pp<8j+Si!C#1F~n{<2INt4&%P07e$~kEam-(d-PiE8ZS9G6ayWU-EaG8|;3VhNWI?}jLPu)v)S;%ro}UqCFRenp ziGYM{j0A%K14N)RHJ(K1ay?Xei)#JynuNG164b*Xo}DQ_WW!uM$wx7UKngzGAjkzV z7CvdnAf5AKiy_o#Zh0Fb;?)m$P-~3&il!5V@0~{D4{P7+o21;4O|G2uj%li7D)Csa zKSt(}Kj$kVou%X!%PN76E1(0bes*!tb)<4A1$C@S*E3a4H4A){MnpNcTRzCLK%TDe zxBN*xObfwujK~*}zb~jBu2wRaH&&89#@-#&7p6O1%+kc!i72SD{i~#hFt4_G3fjmpF`e}1HXqsSpbeT4tqn?oA~Hg_mRqWUt>)n(oJVd z%8b;31G8UFx;}k-7KOY{>-^?{DhpFTDt10mNOHV`X@wM* z8=%~t^&a&y@@X`5%cUos%&C$<*#i0n{HN94p|?4ES~}Llv$LTFe^1zuwXL^)xMQ^v zScEGW?#mCiD$kf?p6WZU;gaD;BurVb0XZIkrY2hgE4&@SCXEvl=7ZErK$r*mm7n5j5|nrsX%dwui$x5uh5b4~5b#44t{4ue z4)cKY{6lw;?pS_)Wb1S&9|?usl92aElYDZ0x&TrqCt0*FXl_b;9De2~E(haqbyQ85 zlt_lQ+xwxk-CeysnxCiDrN9iPSCu%QBpQc-Sn4MYw+u#p5A zKYw}svFYmG+p3#epTac2y~g32RWc!nCfA}_>;*aS7pJrAU(9#NREy+>LjQ|d9(ddQ zXDNwe9g1lN0W$r##Sd5ZKkmWho~t%TD-Bc5mojA(+s>&RXbmF-A@3o2 z097de#1oMEq%82O(?-lNv^4Vub;0Y6UcA+$CdBsOLPPRx@>`Rl^&?nae+ZJ5xKPcvC5sJ?V~zfTuix?Y#+U_ z#i$6f5*YeFbMjPtW9d$ulQWZr8^__rS92B>p`m`K%f+Qy<<3&ZAuufuI2MSI(HzYf z%LWz6ufeQfR^Y0#MsQd%bU6};Afy3$7QNe3B-WUJ2Ia)dc>$6&h_(3K`|;SGXNim%e$ zmiAMdA~%TR)))YNH&8B;h`*r^{z_1=0(OrjMaE~S5vxfX)F>R-szQ18j}&pZ9{Ov$GvMzG9A&Ag9fYA&mdBf>gXl7CVBtlen^{nGtz(Td!ifbw@;R+YNnOa;L1n zBitVWOKMc7_~_SYTc7BfOvC&F_(?=R7^SH2Wc9$K3O;Pi0eV6sFcQ#yl7Lh~O;mzw zT0WFY`baOgG;aFW{fWpFeDaWCMz!CT9~$jNzO75LBJH#vNVr0Rog_wx9u*ZqUnG_Q}g}%c}th~ zo3^L>h~ogqDMNb~M*%(VLr@W0Nf#dN(=NV2sFbc%g9{<5uZPwi&!RJ>GQTffKcRQb zelhH-xoAum@>ML5ZwOow17s_b`fQy%%;PhMCz?42q&7-X7c#I-5g$ifsr%i>D;>?OUZi3CU+4_j{!dOI%g zMQ=CjOlj0uZ!Bepp)<5shKv(V%P`#IQ;B@pnY&sn!F~Vc4 z;qF0<#~W9XL$+w;3(1U7u7zFP`=sGT!7QaO{Wx~PE2(w_duy6HMGv8;+b!}A%N z=T)D~Kky3t=ipEmNT*)Eo(eRsnofW`ohq11(v_G))WrXBI?dhy&@~He>W=$N0Ir1@ zC8+1Z)PNtx0E{F~KacTY81}KqGRQc`lYh^?82C^xL~A3g<&?Jj_sP*!pTB7X zCWZnmpm~beN@$nj8r&L?EdS*5-uQWuung|uOePpJdk2O;VyWGfS9p8DuvPN8^zxm@ zrimQj$=iOhppyub!iA|q1omw-i6Lk))XR|0-`bKQ_07#*S3e6g=6bPqx{*yO`T=2N zVK_`!Qg=bdaH*^SvM@qmmbe%~8m59?`42-r0k!HGHuEsS(XDr6ox%6gzl+&7HcTI7 z#!{Sc<5MR%o`3;tn*@UO7mJPvxASK7yaY4g7Odchg@`OSL&PL#o4CWH9wj6m`fX3HbLRtK@(MTIU_* z^>zMNdoptuTsFkZSoofzbXqXhPYz({e4A0T8*>yzpQcZGaG$hr={AR5CD~JCgr!6p zl!lr;n2j6RsNGjp_*{shXAqs;t^b%Okv48tZzF@+h$xKFE+=6DnUFwaID{-rJ2||w z4V4)hiOkY50Ct9sLn_88x%gWG^60+7ot+({&>F%J%?wW4Ny?SsKE6)%e;xK%PsU7v z&ss6GAlitE!NQ%jFXWIU$s4nG9-YPhhsb)YxX~D_67H?TFDYgOxVQsqnFCPZC6GLL zmRHL&s`*>U$r@&{dr0J?nqF01rJ?4=}g)S z?TQcc>c|3`r5rNfCXuXx0(m{Jnk{KJOY`*wDBIT9&6s^laqGe;`h{Sbz1nlKn<&tR|`G*22E z&P$IVAn;&>tW$(+IO9f`p)}lxhW=fAsT)SnU71<~8Bo;Q)4_J4a%w=1@_Di_i$hMJ z00FX6zxisRn;9&yQYSF;(C^1DbGHYa)3hbPhZu(#pW)>Jepmnsuqu0eK=iwx^w0s7 z@AWarL$*hyYE@z7{6*E(zbu@lhX3yTEwIK?KOvw*>T8w>eq~@Q9{!iRgpkQ{RUyP+ z?&?d4MugwP0oO`-4da`;aM*XWiX>X0Pp1<%+pm6rNWful zL`81xnxc@uMREUq?t42OKzQ^U%SQx8UJZDQHra&-aMB8Rfdk1?3U zqx!i3Nm_&m9UKB2C3s@l;}$|qQIK(`Yxxh%ndU%q-%)b08EEIea(k3N#EDg|)BMBD z**X3K7kz{w41R~C<~}}0p2|OvIt)EVAKx&^@Q`?j8OHxkX_&cV4AmiN>g`+K(%*9p zznclA=PIqa1~eVKrL*VmL!UTx$ZM|c2w=vaBa1&8zw~c^&)XY9!rOp+J*v#+E@T9Q z*jawC1Y-m%c2UtgHI8+Kb*?4mj!VoQ*EhQ8$w3hRS=;iHn^whny=J3H?t-~phJSQ# z__j(fR_g!DizjgeP8ge{nqH`#A1fAdFG!kind|?`QAQ-xQs%#pju@rwP<@XabYw;~ zdc4tKOF3f#PrH>9P|oQvwYM9Geg?GK@Ds#~f%)TiqqPotruiBU?SRV*5a zAd6_fSf6s3?zKQ|znH3+4y?>hUW(B#>W12|=mfwz_7L2ja*W~-5+hp9J-d%gea(Vmh&n@Cm3dXIV@f-pkMfYi!xuhR}$-1PGOXHHT04rUURMW>NPtXC0_qlhX8!j21jCSGI zA~netJTo8VpG*8XrPJm;J71girw^;hh_e=Avv>eVYCy40xn*Fluq#16jb<_;NYL6s z9ZdqNRYhzNCzF7fdV5_%e@nQ97UDc}*--{E*7;lTX8=h8Q7->Oc~Yy!O&+5jdgN89 z$0zpF;@Gj)%>J$oKct!F z=vud{tunW8HLk?)fN7CwA&F9P5TOJzIKv>!EnuD{xNXm;Akujt(z}7`V}P1q7F7s0XvdZW zq~Hw_4a*GcXTw`gk4-i{f~KxTY#xiBd*J@OCgcPN>6*qTA%7GhZe_(=BS%BL-u&VInPVXxAOnhO4;x-|482O3z4dQSJoBbnnzk(;|U>#p5-_sN~TNr9IWnQEu#22GEnlU+)pl z0gX`Vb^ox~)beU5EN(3b*c#KuHH4DzC;mf~V9p%@T~n~79w{AikcmujZqJPRd~w0R z3U+s$SzSZue>dg}zh^p)*5vo6KBp;~uUBZkcZ2&!Q|uLa_h55*TLHEWTI9`1y_^Mp zSL0@7#QxMP2Fn!>o01AcLYXA=UKiYmH~XK&HV>Waq~uB8?APIUb3dsykRNkQ9-<2L zay1u~3HzCQ+$a~hO=`*OpP&pFi)k2$L566H2?9*SdL8cHu>AP)jH5+4vDJ@vDA1B2 zLX%Rx%_@2R1GTG{iQ5Pb89!d}#hh)v;JY3D!8$_O|GxkATkopzR<)_**kM}XwXWay z+P)j?RoMQ?DanRy`hc#l;oHevhZB6D4R=F?(jh$219d$ftx6&2YC}qnhi>`Ob8{Cd zLu)I!FKJ~lCX+zY{hOp6(~bXmP#(b>mnRi1Qa-7l(7#K&9r}2AR=@m{R{Y0Sg0_Lk zpQ*nim$>7KVY*$DU6**4g+C^GLhG+Zyx{CY#u*V;{!BF07~vAVlwtlhO_$%5G0 zZ?&4(sfauEV_eTQ)3wG@yye-s|J$gz*)V}8psoX|dpBQ)dvM=>fAn{^A`=|WH0$g} zhn(}cLEG_(E^e26;B&SK?_l87EI>=E0|tYv_8_LLacXB=JA!A*&=*OvdHmu#jM5tDCHBHH(%6tq?66THM2`-HyaKc;`R*Z9MU}F^ z0+S5!LZd^e_>JQC5fToUcz2;cg2fk2gB)hxps?@l4jKPLbk=Y-0$e4G^ZO`v3xOmKp1!c}R|e=#bx zikRc_`DQi5`gq_*5^m*GeEO<>LAsCrbQA9=t+CP^Z-A9_wLcOIItkJ;;MVT>;^bUg0_{cI& z>M(_2JxY5u%{S9k_;{_+8Ohl)j?&dVpahj9R4CDt2Yc8)o5mVw?QzY4C!k`~QjNej z1_v<#VR)p3?05<+_@A2flt~I_|7x`=*3HN^q2hz_en4g8W^u-+JjMHw zk>viGzgLZ`7Ll-;A@NOdWI_C`R|{!<3*^;c%)7z@!r#y3HsY}`a2VG5BdgqnH&rFV zJW=`IbV~Zo5079XkgYBwgmDC*GX&2UV#|Z_MR0c?{*(c!<58(jZYXS)0HPxlazn};vwk;pX39)9;F5Kp$*0`A=dMXxQXRTcKzt0uU?a~jX<*h*(mq5JU^>MbdhR5mBC-^m;!x*6Na;1Z7 zpSOFK{I;K6b!|!>h9aA+|5{H%_M}XmT@g%}C!pR8pw{~dr3-9sWLF~tT$Lh`irbu@ zY*62B^IPmb<=fKp=lmpHZw}v_VZd|a`ORXV<_o5{cEk%WB4yg1%t30QVRm%4&JB2x2* zh1#46_0G1j?lv>sG6+|ju_hM%ll>61hgG^mSczC0I~LFO$f2jWVHkl**U`~Pot$gV zooo>@@GDI2ISW%@>dPJ+l)NZu&FY(zdpjb69^j7|V0z#NU7}{x;Ms{rvZ6t0!Fi~8 zdSU1RT)rz2SXMgcGR9Lqp2@w%8~bQREhR+qjJL3E4db<5!c@q2)7eh#++1Qnfw zcSCaj3ww+2o__-e)T)sEj_VzWc3yN;%9O`~)f{K3qvptUqGq~I>7NEYwJ9B-ZKO9rrt?~z=>9wBkrQ-ZZt zpZsMQ6Ila>hv)ujZ7xx)BbBl~q}sr}dn;v%a_3$Em5MXH{QP5S%CN%yi=$kR0&)4;cLl%@>1YF{ne^-7crx`!iN9G4v(3jVmq}tt7{Zvz{ z$*&|msn}B4_Lf=?nx4tq@(o_%9VrGIPtl3?(VIRSWj))YMJY*V(WmH{6a1kp>Nm6+ zj7YXh-XP8z3S51Liw5>b>Av`U;ya}7B0=`uS6AJHed106UNgO^=YhAQ&!`=?{=nY# zhT$cK{|-Q#bJDRvCZWIi;hJ)Js?^Z#ru`Mo?BCzNWsk4WRy)6z08b=ACf)0v<0d@*iokBU?(`pKSf z9F5J^e6obeo@_>bJG~V($A>b-eae33_0@Vq`YC~MX+Kif-8@{TT~|>tx{~lp-+8n8 zTF}w)Ija1iNVvcrV8Iv!i~%04YUC7t%k*9C=LJ=Rej5Oh7^*V2iSU`r*OC^pFIo&6 zQs}4;WB@vOnsAgmeVI>0HdP6P5Nl=Tw$1OiS!Pr8muCI*(I-A&=>YhEWXB2gsB3Yd zXidd#6cMK;-yf@L%&v}u?uMJw3s{ox;>Ag8p;6WFuj%m3I?H0K2tC_i+K>{~!v_0d z8$%(%(m(wAkt0BPM??(i0cibQsk-ABfMozP&yegV4~`;+e?ub($q9I*k?puP`89+J@GKFQU(q(0HRAI?@d#A_28;n!7k z`p0$-0I%CvINmWqzo=)Msz`x)tmK%qPIMB2|Zb#%6i9OAv2*_z&Zyb%2! zqcI#DB7Ila5lDiHi7cgzx=CXBS*XL-NuHV=)Zb+fnouJjrI~HVd{-wMNoXv{YPJ#w zBl^{drKPI13T%gbTpr~<$Hpu2dA3hf{n)Pi2OS%xuTnpuoo# z@hc>nW=8w8Q%{E9lf?&*EDRRIC_(kRTUI~fIu@(A8`KVn+oD_^qh3x6zfKQ6i+ksp z@keKCW$(pmgeU4MMEaQrDviq3wQ(Im{!rk%uOTVY9c#z@TU0lx8LKpJ4PuHrAjl5d zhFyG)VU=58sGnG_Bp&t|J|tyi>Fclr)kOQ$Rb;YkTz1KWwd9_7gVQuEI}t`F-h(UO z-BwNgmG9|MH?>9;&5$HF4>4`u9hlKP$^+f_0r;G2Z=*j)hq?s=nS$>W)#9ktE-e(d zs6rFz(DM`mjSE%?VrO1hY(82X>UVH7m!EXBj{SJ=38KfSL9qWZu3JFZssxA1V2$b^^@pc?b7;8%_?^u>H!NwT$_ ztQa0Gf4+`eh~IPj!K@bN(|lu3aa@6$wb&&tnjH!L z$M%+u=UfENTC29^#%!)xMcna{$uw^c;awtB@MvGzJ^1)1!=DTY^}yL?mb2n38f zd(3a?z7pTS>&v8oRyJG~);xV+trcwEZHfJeG{)ME22HJNV@+f-lg)F^ez#G$^eA}T zYVX}m?erH`lkC8GCE_<4$({V+K_8Sx+{&Y+{*QJo*kx*LJN(W_^nr*qVm4Zep zFB{5^L2Jkx%_LqS5oS(tKPhpy^Ty@NChxURsz2`SeWq;Y{LcFQzCDZGQ4Aw7yk83Z zlR&b6a7XF2Q7oM~=i91jm|6djUO!zx>prIvuMIfHg*?B+cpFfaLs^)tjrc-9-GfCX z?tXN|FmxOcqT%uV9sao&4q)6H?0czOA-i0^N~G|DR!dFuw4*8R-De?TYfEk-D>t#FfzIy z&t6Nf8{PT+IUuC4ub}5I+964G73wRm5BC4t?GgGH{L5L}WmjhA-UZCxX>#*Y!XGy! zACgwRmX1P9aya;OAt=-kC?kp*BKCkTl6u?=mCOK$561lass!x=oAf&s|1yiLE#l;N z@AY5YY$Sx{3fyVi`?|z(&BWusZ=qakXMNh(5Z83u7F1%g9A5nXOKMUq4J`G8%g)dT zO+CZLw!43{w^d@nqG4pGxI`vsa$REMeNlcGthsiZ`tchwXovHeudlW5FFO{2b^$z5 z^qSaYqriZ*{+QOIot?VtNJ7$FeowaIy2jes+s4lX8(ibFeltJ*rXJWvj7^mvE^Q52`&1xUFXQz7;YXJ9sxwJKD?Rf?t7gGTE6k9t@)swR4S`@fV% zke4{62Di>~>*a-+qo?|}KYr5Q2S3M9+GkP}EqaRbh?s>Va&5lpD*8YJEW<>GL@UZP#1{(60H zn+2!U&#wKC-l8o4P7Q=>r2ayNMYA)6f0>L6g^`i&FPYzBxC>QY%T$$mjgGP{`+@eP zl1F_)G^861!1N}yQUIo|v3x@CQ8F;_GNJ|48`Yhx4V(91Ldlj1#ijOgKUSYeSjnB9 zf89*V&b>%u4}gOK{~5_=^>X-Yj{vq)=}6Gy4pWDHs<`yIxa`R$rPjMWIJ_xW_V34u z!fGA1d{e0rIw*!vh-5QC;s2Gp7$K?!qvS%MV3Tf3i5zxx*3~hXl$xMrWcZ3IFwp7= zvrH#VUn+fre>4U}fU9+UcdK}WdT+(C-clUY)Q8wA{AM=AN%hd;wBkOl^6BrnX5Z|M z&N#7Xs786ey6<WXE_**e+M92;Y`JdJKZjFED;_7?NEhr*5OF900mcpYukA#_KWZTat z>fuHC%^OY1<9q9j50HN{H7WvLvgR2A>0h|4BnqY)r&um;zH+r0I^()%`Cg&<9TjDL zjdOv}h{Yw4_u^LACsBBzMVX*7UU0GwY;7x??u943R`qwZwq+Z^;q8!f#pA2FnAC+i-E z?ndsu7+FvU0!G4nY549!uWES(&Ri-AzFu~4)6_YRyW?MMeQK${Tx_0R{aM|9Kek9` zaQR}%>E*J4KZjY7y&DNQJoJ}X+}1R;*2sMywgXWR0R&wwyw4MEP*C3nmKY$VW>YO$sS*sFZk+vp^m;xg zFig1Hjj+DdkefKNkGe15H*v5>+!pY6z_ky=9V|2tJJJ@`dWl6}~?e6+*t7*A2Hmo?mV5+ng3JoFt6=o2HL?EF(4gv?)+`s_<&W`KIk2yN1ha zcBbXTe`72n?fcPe$R_hEuO!Y6?T+^FFfqTOLdw5YwRNeuKa);59@iXwL*y;yr$Ve^_LI`voJ zo9KlPqWVR{Fl&|ai}(r2H-&eC8}eYthoq>a}72Sr|3F^6J{x!Aod?Ptir zAeXp#p~JIR8ZmBJMI4%5hw%3`IU9sA+sGoUIc(mcsRg822CrEA_0B)HKc?-d+le;( zR~9mfuWk)a%z+UKq(cQ!EfbQHX&xFOHIhccn{sQif50ZBB@OrRb9>W1ZO?&JRKlgl zt^3Zy^P|RBJ$^U4OQe$5gp!V%^GnAuW44bwx_v)d+Dx1-rh;z*iG79Wp#Aq zFOr4G&9XJ@MRZ;_(};Q}$B{5qV+B6D<-ST2m2HBepw}AsBeB5W)Pni_#8io^9CA1)o((x`_%DW`S3OCi z-mmpqC=7^C^!<*VR#lhI9!MW(C2wmCn_PCM>!_jQ^<0s&;bO+xpK9$ZT>0RDhyvI2 zIpTZ_)+LwB8rDm4Gs;m<)M|v09?=PA-qTNt{d<43m#a?UWM-bv%&aS9@*M-6<`Z9u zxel+5Si!1>O2$mYPxSK z;Mm)xt-RZpEyspmm6Gcy6jyK>vjunZH~bg?j3H*;(W5Q49a3OSHn!5!($?-7vW-p2 zv&hvE`-iIL`F%kqzSL-HwO$;eQ``kkfzRZ1k(H^e=}bsce)S1ooo6Ouj@7=AIs;R^{<<sh%`W zs=#gRGt}%^Fvo$Q5>bxUubp1pyA2sX@;d`V(Ob18F^5gDrStMJqyk|#<#M&tS&-ck zAKMuVI!8FP*vdHRX>of{*+Vi$9-;fa_nrR_5Hzm}#GH}gEvIMKe~h_M=c#RvIAG0N z`i6wm8;HKRg&zi9IMhK#(A^F;jx{zJyJ zMx9LLF$TZb+QG|}J>47>P)g6jUBYtwU$DmGe z+_3tI{E?ohiwl1jq<%VNn{CTM*xb+!qR=vOOxXE3=0HTHBF8cEl0Igr*0*%NT0Htu?&g;km zqBK_XQjUoovD03^Jr0>^J*XV8U>u#x)P(Y&fUGyD)f6Mm7hC(WmtXg>RKV3=uqYA^ zdO|!U?QLzTuJ86pbNH8c7OcnEp$uACU)%vHvzTc)_J!8iS@aeSO%{Ufb=o($K3~lN zLcx4wod-5_TEP(wYhwE__8mmQWW{%DN^S0G3PR?KOz4<_=Z~axVbklLV$}$&ucVvp zm**8rcbDz=^V)8AbF-G3C+UUbKq7Y$Xu5l8NBqh$>qm}6BT)Z)Hs{G?$Kr&vfES)e)fZA-|o_QFA z?=HR+V> zYAwN$=M1mdkpD?xrEWU>fps#CuuIRitI z{Kq^CHNvV4;GWQ!sFS3(Ffra>d0r_%0)C|>j60k`NYyXqIAP9x5@Sc7X!je%TmxP2 zUtHOFuGu60`@vcr3Tq*fk^;Q^D)7+nq1D-;G1PW#3b7-wz4zM0rQb4Gl>{J_$Tm49 z@2$9AEd3smht@S*Zs#RM7{$7Xa$(=*5!{P$W~jp`Ta3Oj85Bb$;k`Gp{VJD?V7udV zJJtG2(9~Hi)AY}I2gsRDruD(>*N2`poA?Z-SuDk{-|n=j!&4J8<$We<{Z$6V_q-D+ zP)bEg^@D_eRKgEa{o3sp#1((E0pK=$R;EpC2}ZWo;A^1$=Dm2S|gl zDb&<@TYs1JAhTEJVGR<^{-wR1(lkG7U@65k^BWzEBmqj{qiae;B>c(|;X=S#PzE+R z3aW@2zF9^BK>2r|{#a_UhpoxiNXYIpyNyspGXR4q07lKPr-=Y$loSjmSK3B#gD;K@ z&m^q>GiX%FEY*2-RV!TUz%tnCd+C1}VSh7iuV-kWn~L9Tov670=fTiHemVGS6Xqd8 zOP44C`Zs<1>hN4c3%%|e3o#dW2(0qhwfRMz@6~t}p3;L=yqqH1!sMU$gdh`Vk8$%4 zllJ-kLfxI;rC<9Fx~m%SYlei(b9G09t^NW>bP$(6K2MEaQq*DySKvaA@T(sImac{P zi?`Ko;lvsa4l7yicXw;6zv>jF4xKjoh>zcAUb(F*KOWK2JSIur{~p7bV~=aQ%$JMI z@Nb*6d~PaNXTe$&WI4eecimdOpbY~3@lc&+fd7p6Ck}qvos0E#D@TS#{Fcst&o({5 z=sK(t=VitLE}wdun|>=N zWcstl#{5M#EfX2qGkm3VWZ`kLYITg3`IyV^x?IGf80Gp>$Cw`rod80#ZoB?RGh5KD z3~-vx(bBO}76C;?SEvG|&2J2@CTuJ2D|S+{Z{(e~f`-{<}UMF8A47xM|U05-nG~uCEM2_Zsz$Q?A5(=+Bgvb+arsW=CZmNW}9Om^RaZa zu1b2`J~UaO*@R}EdUL7Ir)1)@dSD8>1*bGXdh}LqjQV)qQ zI{CYI7yO0rBONS@0aGUw&)$y4LpVSiCi`t0pvWX!`m*gU-A%U0-?(ghLhfso<=>BU z8Qx;w`fz{#lyLVJ7+ZFeXpYWI^&$xH!Uah>#hY3vFFTsK$`-Zh8|ohZj1J+<6h43L zX!h^=THEioo|Z`XZIL`7?`QI8QF<#Y^^s%f`RHBA>t${d_=3$|!p4S=3H$zrMPC;) zIi*c>_<66(euo{rW9zxz1fau!`{4!Uy^JxLkQw^?n3z17ufy^!cPjj0=OA$(g(fo|_~aV8bL{y2X?(T7_!4`*-&)f6y=M=&9O2 zInw<0&i}gjI^!G5Ki6nE3~Le=?^4W(Njg3N+NYkGmr8LYA&wo7#)%xn1i-t~t@NyPsP5Our$)-csdT-#-}(9!NbrApnf))O8a+IF{5 zI^W*(Y_JL}^fKl87r~7;c!EWSQCZ$}Nq`*@teQ(EydZ5L3y;f3kB*Lw9orLYsP?rM z_x@6)^-H=HG{GV@@>=$r0GBB=trZP!BR;dbzI4P`+x7L~ACX_Jl#H2=jX;LYx>VRd z0rXlsp>99tJt*yuw-ieveE1S^!phPYhmz;CJ$R4fc+|x1CsoFKHauYsThs$7zpGln z82!51y->@}ZXYIGqC}&p95geA>VCe%wO6rJB6sV8&;}-Z6#G2eWrzP_ml;(WIgfK0k3iy<|Y ztAd!y`cn<^L47XR^JSeLNAL7eXs{C-Y#EGb{5e<#Kmqe?(v*~;v?=1`ZT>&d-e5vR zzpH>ja!?3_@5>9jj5@vt9GtAaW&1%WICuvrjnje_;?(ry14p=+wr%x|Ev!h+u5;Jz z;zZ{-v;C-l^>*lInLE+6 zY~5Aoy}o{{gx|-T#%ZTcN){C0tEAWq8gX4Ez}`wP)31P4Wz5Ma(xK_wF+YrweYE8n z0l3dAU%>&>Gi;Kr80=We5}ohZoA{cuaHBVTI-RFIpV|KIR)SX-I`i=Q=huuM_Z|$i zR$(VgDJS+4$M07STUIh@uiGE@+kNtk>J3Z)0na~M46pMN6l!K`Fsq{a0EDd6|8lhB zrC&95e89xU_LXo&_EM7>_-m>-FYQU7bE?&~ z)_(K+c z_IkbKsn}}8!|^M;$5?xhAqy_U#*-G7n)gNU)%WBuggGOwGVvS5$WMDsN(je;_wIH; zrPt`W=)~YquMGeFXs^{6F_neut%k=1kZgR)n;={++Jjc1{KY~PWDD%nZ?Ia>e3Yk0 z+53H!yPD3RUTr>}SI&*aewkjG413qZdbFUust0f!I6CFS++%9aB|)A@&a?h!fir7e zQ&_8yx4TQKU*j4f1f`#FAp(?VAre9%aAm^5Cdr72-_Jql>!8pXJZe$*A5L0&D&_99 z^1Vy>{@pqv69tnt_+<`G6_S9k_Z6O|ksq-i3a~HV9pmQgV&ifkq?k+?|M>m^1Qun% z-UctcTL^m-%D>s+<~QT^F`~M~@_kVa{-r;>l$$bloof7d5N~_`WWY^?jC?A8)M=1< za5c_^6m+s<4OYuB8HoD+AqZd;&LHdvboi5nq{j0`00=4(Uc3;vUM3024$?|R=Ffk%_f2? z#T#QKecQ<%M~{P(TGp8q@x+fhPC=L0M1f&77e|R5Z-v)NFtV3nVqg(Wnaj_ga$W>35WuQ<*P``ci>_wOQ4 z+}rQBAGPlS4<8>GjFV=+iMWXDyKIr20i-|_WZdn?-hPBr^kEnKm2i4jQmeI zX{u2#wyA`N!zBz;bhgc??cneig3AL~ajv<=d;l`JH9wZE7c1DhWE0xybMBhJ()#N` z(U)Nhc#Er8;xmmvlx`Hvo6vUT{=^^S=iVKF4~Z-Mx_4uK%Q?pbTv&n zesIe5VLy83x#jAY5IiCd<>#G~e>9K!MVz*y zuEx9lSldp;+Sb(iVxIpBitz8zxfKp?ZK^Bw{h$~@GUT%t)!l1q(wm13R;z5Ot>qxu zSh$|{CZh5*FDe48s z1UwU;bo>Gr`1pf#6c;w!A6l^uWt~LVNp0NIV;bWlt+NJm7%4OT34>LI&aEfVabv`@306PX-r^Z<`6|{hb7uhBB z5*dPfu}v8&`;q_p=(~=ORe?~J{)|L{FAM(`_{S10^((qG~^(sOPS z?s}@N=Z9*a3q(v9*1c0%8zbIyN!aiv>Kv@wO@GvF|Q!`!-&B82hW2kn;E=!7g<)Kmz%rjO~#aWsM`wMO=vYxyz|TT{Z-Z z7-6+3SWL<7;Heesf|I!7&NWNppCOQs@qCN}?}k0RSh3%)Y;uSGr{mmP^CVTU}jxl8scmf#sBeq z_$q3VxM^k!PLt^d!(q#j|1lkm3i&1qsR%7>qns27`Bpgl3$2X{Z;@T3=S?rSxKNE= zr`i5oZlx(T0W>bjrEW~7LIhSW?1*h@>mDs{_&=O2#g@gpBMGSzn=v+vcbso@u z>5j32aYSq>AZ`F4YbhxSER={OVeFR#35p)qNq)F+-_bAZ_RG8{EPJpcttksgVa^VC zASWr-59xfeL%dCpVs54KB+?qoFEWkd>jW(@s86vkc2-^meyR2D9{Gk@f zwjY5%-{TzBtx}^2!+l3O2D8rnk(lp#we|;!KD%NKl*{?<^Cz>v==Op-_t-Cfuddh% z4g>D7Y(Dd!y=%&ENO+L`5*21#*ApW443*(fUe{dXxn475>!A7Xp8NT;lcQE}0GZwS zG30cUDbWOvVcSje2RPC156C-uEAL5N_-c4rC-jA+RodRW?7I#n5m8nf>`gZV+uOllSIyEnrU(`Sn~FVvY#TQ zFBkTLPhPsiEp6)8Z}1yMScv)5NEg5Lj_D14`yNi3Tns<@Rl^Q$&cqSbTX%)|;J}3; zasgliQBQmij~9WqS9^UiaD4n7oUx20vQ7o%L3z38rG;jdNidoM0;QZu9(IWVrUb z8pglw6)7WUMDJ3+k&~JV@|3%KY|zLZCE1rn4dRA=Fx7|E}5xT70}O?5M*rZStIIV=X`6?!+DHu)lt1TV6};pW}Su zUiTJ}N>W*^6|Xgzc{f0-v0CY+Fbo`X~lKkJlh%%1X9A$uA)*TfGg>{YRe(i%;&*z=T9;i z;?LQqb`%9s`8FQtM;J_t8%djpZB>~Rze8;1x*ju**u;ol>gzC^-3>W+w=Y#KTd~zZ zkI**BCVp(fg);|jFDzOI3EA%5bFxyQJplkqyQlFGqpg%roB&y#`ds)~jCdn4ukm)7 zOo3;HDl^_+l6-XS61?b@F+97gR&E|j{y-%9`fp!U*UQ%929l89FGEgJstd^MmSMGZ zKm8&M$HG&yq6Vy!;m8G}aG0R#ftS}oMa0ndzm>rK`~QI`#M?mtsE<753uxpMJML*H zZ)PGGDR!P6hWrk{S&|*G{1A2^IlUd;F87s_vKlj=ST43S`3m71DDc~Zze*+i_7{$+ zHl(*Co@s73(erqtt;vjD=hNh_VfSO&q30(<*B1+%uO5Va|9G?vYck<--NsUvC8gg| zpPRJXM3{YjXC(-Q`!T8SE|BkFPy2gm%nREvVQyTfEMxTX( zuf1F*#nc=Mjwdj}NPmp~5Z%b5hQJZrCJ%LXiAvPT`7DcH+?2pHTg9hP)})`eLzN_$ z6WhK_ckITF83cs_+eQT|c}V1*8rY{fHr+cMS15{pmx29g4}9%IcD;`p?gh{mv1Z%& zo+S;(^%PKv`Q(b&MHl{iU-_$Lw>$UU8M25h=y0XC>%)I)eaJQS)xz_RtL|1Xu@t8- zRh{R#XXrS3^+{!I@ispmg{4BoeRIz+(O92dd8k~h5}V==A;Kw9?)&}<8h@XQZ!Zwt zFnac_;I)CoQPK~I3%~p+9`D4IUD3DPDZZF}jsE#TpmWma*b1`hTXp}ycq?=+XPp&m z`LD&c_5tJ*=k)7`N1r(e^CcCEyl%aT$F##|Y~ZJy7adGjqG`;Jne4LBnyGY&3}G>J zhVNIR4C%Om0FJvzh5-l0ZZwL>MvTa{HaGjo%k30-dGp3IY1tJWbHmrEr^-}N2ml@c zET95xzQ3?lIjRxsFB3C&u4SK)s6ahk5aj{nCkWniiQs;TK?lK}>CcDy;!%=#yj7!V zcKpme)4quzBA*b9x~Q1`{H*P#+m<+u?SB`O!-!C&C)o9yj>5EEP{@ssuS>(`Ch)!FXi*Y<>W4e|ZH_LfAZ zkAeig?+c>$8#iW+okyYK0yIE?w4)+B{2tncNxc5}lKEms z(NQHSJ<0C}lhMPIC$z2qFWrvH9#q8CM(fic>Y@5Hf@9%tc<+6m&?)~*#UH6IwwNhs zhWyQ9uI#%{==@rMkwggVu=0-?)07F7rv;NdCWJrvvyMtJ`&pVwR;Xq9?8Wn2lR@i0 z60@aOCZ_l6MFMj)v)xu(Unzv$$ZmS#M!i2r*J76ZVZO(F-PpPML(8PBS4eufcviAF zP2J}PJWVn^_po=FR#0Ew-=r6nx~~013%9Kam-9#_Oz}ZWRo>^*RN3hupCxDOKe4Nc zze27VItFC0-83&Gq?_!exblha^w_6g@fs3LhPpKL^vh5f20!T(Usb_rX-7hRm*N-w z(WH?^U!4w`(9(4PnGjRSTqNZdqDJNKDU>SUbRSn3aM|G-ePpF1Nt5o!6Fo7pc_9l9 z;j?aM^a}@SRc80M8B%&5r}@2Dnkv70A2Rw@8mIY@Wh0lD%>)(2Ib<)2OY$e9-P%C(3OkTMz-IxNhRafC*!|G4$+y%6=)`uzfCuY*;=}{-;oZB zF8tbaj{zcke;WqzolSKD0=}@)UB!n`_oP#Yh4{V{6H}#C4en4CO+wHj%}s{L1_R3O z3Z2&sv>0>6e*i)mZC^$Y^l$5k1S1b6g7)*3BOU}_PVb2Ta0z&Zh_mY+0PbM3VhD9x zO9ZEHl&Z!sR|K!9s>)3%Mjirm?>3p?Iw|28;mS1aKM!-uz2-g&0x*uE;WAf>GoLNN zo`n=A2-rpR#_Q*}(2UI}5IkW4!-FIG6|LXt<1-d~q?c0lInJ__{&f|1b=-6&KR?;a zWAx8Pf5JR?%>nw}1oVb2eNJ`YibU1;*kqT`-*?!zQ1rn3vgXZ$Cx{1NFlp5}=FWi!H9fnm2j<_|L_>_wk`5XzMcNw; zThS!#D+@L&zTRE_arV@th}k#`G#qW@?DWWKWWL37t|XY`DVw!$a@5p z#mF}cPf~8ZSYPM}vhN!2z@b>lYeXB+MHf%oZaIKKaZJXpw^0!QLgv--cvG#Un+eR+ zq@Z2wP?KDgf(->HrTPK_x1VQ5-kZRN!sxpMUF4gW4+?W}?f>F`RnNJ76idVk{$ai) zwmI?T8B6p462*wspn+iiL7&e?QCC*(hM3BQWK*ICf>gEGc-vSS~a$gRzB%T zl51%&s~kEiSiF+y(~jzDUVY)kN=`}AO3Ck|!%z7U**Q{oMM~-?-qI{ckqiCnJ5j=dOH^Ml`tQjj&LV`gUnh#LHgYXwwx5R^8Hwn9#xNf!tR7-*0C2!6iEwPCO} zWj=ngMSI2~*_vNGI$QUI?!|WPb$HJCA5i@L6YmFiKa?HS z$EI*_1k~20u6FV%bAMh;tNI~wXoY*%FJZaCKI!EQ_>G0Q}}}Eb4QNBUjrM{&JnR zR9()cW=t3YKyiMri`K~>pb0}LJ%#7TYs^S~P}q;Hg?zQ|m<568$(oKyjm;EA^PNVr zsvpLj-bhB*J8QwkUm7!qLecK4>uEeypsQ>Adnm7+xcYCjk+7kX*;>Nj8S|dhPIG8?j~|la{RpE?TT3k! zooV&x@z3if1%@KqFyrveB*hsV?Ml%EpXiM2x>*2d)rS@|(=%>tL1r?H7AcQFQBa}PD2Qf@96$199Saq|hYm4@5B8h@qwhSHrcc!g*N z$poDw-XT@^!<=r5F9LwfUgWDc^F3(ZYA#k0m03xTuxiA=@izrH8REBwKdznD1oppxy zM|+iS&7a+Of2fWEXfQ1SfIdG^Y+w-4cP|t&$;EN|3*^6P0F#(;L~6c!VPD1|^iy@E z4G0`QAt7JcbMd`b1fI=(u9X->IJ^hBp_>lCyIeea6UXy)|83m4e8=mW4~jpu16w!Z zy}olQ#J}PKlFl|ekWf4&W$t4pVEyQ(RASW>VI(T%`Xr)CgE26&r+d#3D_7aSp)VNa znOBOG_8s)11WQ?0iCm2DRnNf{Q04uNVN3a&cL))G{_~Vx{pTt1s*uopSc1ihoC9o{ z0|dnYBwr{Hm_Hyn_l~Qeb4FV~*s~scpS1`q6kM?w4~R@uzIw3#()#T200c3@dqYUIe%^E(xkNO&ogPJJ;4)#LGU7;V z;EtH_>Rvi$gf*5Brf@6jRTiVXQlQ~_yila6#i1&Rs*u>#6 zY;W1<96#g!!%cKS)Eq-|v&^RLzPZCoEe?*VvAh(WR zxC(!9(Moc2^lm)K4~l^3pa}-X@vudPr&4M4k_s-*Q1?~myk2nEA)h`Hq&eMd4!jFN za|x0(3sT%)y9_(It8;^_LLMSb%h#{0dV@55r|{=pODam(SV|e$&-44g>OAgENj`YF29YsCcJkmRsAW&|-=^w#Ygk1-R`j=DQBF+*SY2Q-<$6Jc$h4F-xx zGJHvM@^~EZfJ=8Mi<8;q=m%?3#1G}`R-EOf(gDDi3K02apz>FobzrZ|9_KpcX~W;`?g8`sKZG_h0_ou=?n??)nyAs@@TqVM9%(!L`~b>WfzziDga=`v}^0PLb0g&8SmaF?=11r-lO zSuXz?i+*Ldox|3_kiGHM=evW|5eZG}XHrVqR<`rq&aNAU0Z>?(8s%_jQ4gNbYqjpw z6lrwBsIjWvkUhl$ji5m|e7~jhgW&V;aAP?7({78i%1Bm}*h9nLE4Hqtnhps~CB8uM zVZz+z<`|1FE9j+DRbk3Ifovf|t-?HS(t0)Kxc4uHgFalus?`ZBfo8PLKu_EgHbV`~xJ%c)&^`3<}#Rc#sHMZpJGYf`caQ_8n zAPLj^@94j5k(lP`P(O}|SKDy4Y8sZ>Zy0zeNSEfQ{^k^v(I}w&Nzz=1{*VjF8RufX z-(-D|JC`dzLHW%7?*0|m_Qc|_XYDSLu<{MCv~2fQT#r3o7`LV;p}LWom6w;-mdX)B~#9Rpqx8=z1j3sy_U&Uetf>JFk@NMshFEEa<{fQZ0mF(%M}o)+CjTGh?7&-t9=)5ouZA(fwJEyFZzxyt2;U z_4JCiTh4V21B6cUeb{~9z5n-y+>FR?xqcMxa%!u=)6A|$jVOJbdW79&D*9vG3c^S6 z8P&Bz8~tX^%lRg`+N0QUZIFu^jj5n=DaP)*)kMN{yjWTIzXrsTrYRe(I}*n(_zNp{ zUu%YsO~~vH2|R^oqnwyd&5f|{d>g-=n#y4k%d`)G1jf}n@P%n>q~hBkAZE5qYF0E7 zfN3Ws5x)vzyYdekt;*lC`H{oY?Cn2_pFW(u1jD@B(vTfCeavAGe=Pvob6;XG<^o=< z$$8$sA~?|0=K;mrhfw&oiV6}%Xop+ur8aP{_QT3*IRuL5-w(j5~P3Jz+W>GJNW52QM2oD!C@NXe4ZIbPioeck=Xu-q)G z#aJ(VLrAQ|UtD|0Dq1HQ_KxZ(rHXYtve0J>H0=jmb8S)F?S5)6-d}b`FwP6(3|^!j zBA0)LVo<|?OaElzf)jusIK~rHi?!0hE-Y+r*7hzuv3u~o@(n%3A*_x1D|+0JcQQw< znxcyI9!+YRZbXVVKoJgbQqhl-=s1&zmCC{mJjY+G?Xcbbo>Q*Iq*X00UYK`f#;n@o zYAHF0eKIJpmCAp#-jHZ+#VFJ{9Z<+jdlu6PTyN>R1F)dc)i$~70pQ3XfBaI#BEdqG z#O893es{yG%mD>lK1U_8y~+gnTmNl-G1E(@rQA$9K^M);=|fv67Ew!bl)J8Xh{Aon zaxqr&+76U(?&_*@y&SGYdsz)4h2HYgOpVl5(2 z@R;EcL0ddkG%nPxU;Rf=hk!~WnM!s*0W0?`n8}MFwYr{pk%Jtg7KX|k^*f{aEmze2 zTe7G9)fejfM`9=bn-gBPO8vi|T5BVhM%lum6-MXqGs=BtecK^kRo(D3CCx)4m zjhX_Y_eVt-9R2|Ud?$`rU;%8qSw5=)Gynhzkx}l;zls;DBxswH@Qla1qMw~ceb2-& zB($eu@H-0x53&727M|1T>PI^^3ZUP@C1U*hPpd6<_G-X!X||sPNsW|{*qCE=$+D5+ zyovQ-r9I@GZjBq; zw|d%f8wd1RAlg^FNgU5;5>p5Tm!ki!WCchLmp`9U;>R&%G0HG5iZR9cCk71T(xQt+ zvIA-2uqO37xbCZS`rg+1QmRj;9maVoKCZgoTiIUSd#d>uw8e$d8O^SvbIPxI@KR8DicrCzLZGN#+duXnmgkGCEDo9s3a_=gMy+E z1;BzpnJ)pl*d#E?Ruq+R-cBwh2}ry_&l}?^PJOPAWW23qZiYY(#*vQ%l1zl8SMD%L z^D`@cCBtaZnhM|m)|)qTf9Lg|%2di`VTaophBga&`l=WeL_?$fV0@HRY1O05NUiNo zI}bu{r@zO75WE>c@$^oy_5+I|%&a0@j6!~%RMzb0aJ_1R7BLiu(j4XV4ePB<(2*AW_l)w#s zvG*pp@$s^j2kDzmnox1}FCSkbnBPnQ-xJWjfE%xvGc;_G&HwQJsgWJG@P=y%fS6fZbv()@4g>D zJ_CE?LLcQ4?ErA5ic@#b7Vc=)BUBnFZpH^AFD>2Vu#goCHHHo}te&SLU zeT3MjVA63P4^j>{VPTPBWw5Uf zI!M|S|1nH3$#KN8hE)LG2Lcv_RplWy$*P0Q2G(pL7vh_(#_saKw1<*TPNz)Pp)I%{ zYMR%VDAZ=dgIF7Oj4dBcIDBswa&qy@Lh?g6iAd zQ$KiKz$Jai#Vakm`JZ8H_7-e@?<6*%oNO7l2QkhY_IYRJzW)ZS8hI|DG_Q-|StgV( z8$TLGgI;kGKrAqoE?ZmMWr>6F@!xsM)Jm{oCk*oKQ>QI5wyz`EIKZb4M>Wz|YS1=c zLysB1yY$8V!A4fO<-Bncd0TGmTj%?i9sI6iZDWP`(sB2KCt-eZ=P#Z0THp0h0OW@z ztRUea9^DKnJVU8~#)4O4jxVQ5U3uqj%hU-YbBzx>zxwPk46R@fG3X$S|Fj#AN}a9( zd-I#s)>_@UWq5NAy$Gr(j4&Jx>!K8A9rKH<3%%nSIfqv926&3G=b>Wff-FoOPD@hy^{V|ea>MVI+<#i#c- z<3NzqXI)g0(Cw5NPM!k`r?ht-EI|}a%R^4;yY$?h6}h8~91~Hf$w9jU+HcdOpQjlc z#n=SWQ9n-@#v`NE?Dwz>9rhgbzx;-se?uyHCRDL1Q&vo0x`~-g9QSp!5tSemQMLQ4 z{j^-kcZPgVE{(n@G^)ajL{wi?)$NU`KUk28_yfhVrGG6=b7VkkqaT5FGXH9x9hpm**F~T``))VM;^)w7xdO}%e6F4!0tU(`n^zC)l|&Lke%Cz2 zy*j`|{n0=ZDs@98KO>lnvV2r99bI8$RpsS_c@g$pl8AL2&J~GdadN(cA}D0(cpx!D z`S!P{>PSG)+(N&cSzhw-v8kHy$F0z>@{E`Ox~E_uIH7VS>D!)77RHw%$|8Wk6fz#_9{S*ao;EF#* z$-)uXorwGd84+t`$BX zDh?=o!4PVt0}am;a%rKKbGq;yJ&tfL)XtVf}?ugte-% zRU`zO#qjG{;?%#>u(z>yEj~Q-1%+LxNiTmN)E)Wg*>cqeS;GR9pS*~4}SDs_8ul{-ctjcuFO~0Sc z-4HX>^x(ZY0x2qvL|*5#!9a0ORc;bVO8~ZbkBB)ZI-iDZG?jFHrWE^(7j03HDw1^e zjsBI{0SKMAV_~*{iN@l}tjPR~UT-qP*rH(2qavzVgCz^Cr0kex8$ zqs2oK#^PL@O#4c&y+&4~b^Rx?NdvA-T$k(p0d0^YeL-doK60x6@83W{Ay!s+pt&c?1BZWV$xd{|jX3qQy|ET{I_Lkmff-B`X+>Os-l54fcak|Q9 z_LUv82o5jKB$PLhc;QgSPkc-F4q-a=C)>Qfr?Z+}i#Ky5c6>g0ZB13YYkMno@hDVZ z`hA=I7xUxlS2_^p)KFH&jPz&2FNY7_?c9jeYQY>^N z{5-i#y>TmJ!$0fMM^6TB>#ZQqkK@rM#e7r^1+l4kCq3x4i?$Mv*zfFAv~hWF*G?MEa8%i;i!{3QD4BEws|YE0wm`lGm`Pvw2T-OwU+k-*fg?d5 z3q3$*n{!>`S^|$X<=xA%-?~6=C5xyP60D_DwNy;IRd>LFK|gXiARJX1RPdYzV*~F| ze(0jDqE}F*py7rR;|JCdD>WubLG{)0PM5PJ(Lwf#SOG+&QFi1X$d|fJwCU_CTe~|6 zX$`Vzj2a!-FGKZ?AL|tYcWFF{Baa^9gh>4i>769_L||klawI9;-QA_m64jqNgA>}A zuem6$`=+1thi&gb?A{NzxB2OAeeHxrj}4f6N?OHwg)-C?PEJlkAX`d#QZLdvdQ)8B z=)7U<27P~J9Y25HPiL77!1bWExQfaj(KrC~y-H8|Khi)5vokgC&H?SjEk2yzl+7oC zja?-$5xbyk&l&oF^RiJ6XB=LlPEch&4V;U6i1Gu)GW2n!H%v}Oc>VNZ%vv7AqAdJ# zamO?BAP~pvD5xPRE3w5o%6ZKMKsRL=&Ts4GOp*d7`cGftcTDWor$t_6RN;2>?@M8U zF1_HHw-)Ch_^g~Q8HI-jhMJ-_qY(?Wne<%+1T#j3EF;r;*Knu-hDX~rOjOl z$1EcOQ!pa8t}#jB_yhYy`4KQwb4Za}`nsp5p8q#X-;FQi*{tE0R3;b{gMy{{4Q53L znO?%u()NQErcf|WiFv(Hk}H-`{Wd87bu_dPiW_}u{6m8b%FF-6xR_9zsFEd0arz;} z@m;mT4Xqt>zO<-9UjF1aDtM1CYBlk`^ho}E67*D#-5Z|Sa21SVP22Z;%u8KiR}$om ztpH*kfduYPc&2ljq8)E*(YOIRd>#oH#kOEpL`PZcvq&qf{)}{4VrHf1So+PvzSh^> zqH~Q=>bgM^c*JGUuh#gF6fKyRF8{QV=JysKWwG~-iAWE8vDC=F`uyB?BaN5MlRw9X z!6X}_MF0D9jTrB`C0KAHWT4Pi7LM*F*D8O0aByHe{9+hJ0@|>i)9!VUp?b%t&b(?x zJzl6}-aC&@F2UI!Qb_+}CFUo@F-^tOX1M@?c*RF+{jdw4C4U_qFAbf$Bkza0vVD#b{Wxw6QP!;Pa8Yw<{Z&<;d$<2uP9@G4Nfl zQ2a47{{b`BI0x|9ovt8$B8yJ}dYcVB!y_`j!e0%B25zGLG1GQ_q%UkWgEDP{{fGb3 zs(;l+^4wA0#7U=$8yRJvrOzyV1M1F=M0{X^)PH)rT2%DM>-R8I8(4n%7y13ZTN~!o zh{12)?uV3~CnbKfCe{o_DGU|u7D>dJ8f=K9#-3am1jc54iUyMD57e9cnhi7I17MV| zJN_}IM@og=kxYpUy1j1$Lh@iQkzx>16+kG72l`EzyayfvgKo{knCV-gKCZw>Jm7rD z0~dUGqkksO=EtVG$XiW%27RK##>$NvApzfGd&P_Ny$~{pzDrypyw)CkSTHQ; z;>jhcqiP~NM+QKKTiu6~KU=?SrG&lzJk|zy(hB@!s(aU_Rl-&w&vVQUfQh>B3^dDc(l4sB>?a= zY}hFQ@YUZ%?Pf|O9(DBA0t>pI*$UNnM1=-Nn_!0wyU>+Dy%Xd)8tm7 zA1Ps?{z^SlVn)Hzq{#PfXb{nMuK)e}_j?h`rjdp{Sw+Np7!FtNaC;Ulp!1tsMV!?6 zcj4ebL~XCNKngrQ4~2!TGuqwBOm2=>ul?(H!uK|Ipfa8mFGG{_E%wOI?R;ewMY#lk z|NQiZj8tMxb^5avC40hqS*aMb?GQ!IhN_V%fDF__wVqdZ#{p1y3{S%QPOlZvi{r|M<4aM1V9m zV=TWT3nTK{W+rqAAXS=)$n`%@Xy&r!@(No^>`@+nh4{LYJEQCoNF?+=onZefsx#y_ zDUZz+?FB55f*zh<4F76kc4%}$o2a=8fcU3rr+n8@t)UNldQ^{$G)h`B7+d3*HwjHT z6HOV^Iz|dV9)Drk6-|<~W(A<*MM_8X+qr2edqsIa6w+ayCA2CX%|Z%v7;1|!Vk(f= zbATQcZvPgx!>d*izPeyj*G-}KNxc?_JF9zWs)HGg){^3mMsYnqq^}-sWF|4%-g-{) zI3fe3z4i6+cY-dKpQ`(i)`TczY~0py)DjTcq(Lb7Uy1o1^?bZfF5_o-a~PHUsL)G} zz9`;8Xkb8sX;E$%g-Qu49^dU-KmsI|%HBg+>{vd6fNMn2VLIyx2xzqo)Y3+~iS8!> z0c^|4NsI2bhca@|GANDw2w^hicPNAu_Rgf+9%X~5Um(ykGw?x*~Kj=^01`SAJBAxb;7H&v#o#Mvu{kKdG!*iAtV}q@Mey z9omLe9Amw#(QA_<1D=XKv6q*BNN!gU>rVG1QhAi9{JoWLV=%uZuRVa2?f;blrjI^0ZCK`L zSzJ~B2grv|G5_+?6?c4QNxe&?51LK5Z$MvZ-kiH6rO30)u?Vd|b$xYm(cw%vYsioc zE`4H`Kl573A;w!@`-XUp4XUb_C0BaoVK9AM{Au7@qwJPeS4H4V& zF&Q8Ueg?2c-~mOXr73hJpy;ALK2-=YPo{nGr#~u&ZmY6S;wqIFmg zbR-OLg1Co{secuq3Y&-&07V~Is^Dv`;$r&dxDtGqccJW-m@=oDYxE&PRQTjjv_%Hy zMtz0BE({h)h>A&wDJd%}`}|qbFa>y;nex-z9_jkYbL zY+zilvJU65_M-N6`iD}MdncAsZBC26rGWRx@Q3PEvT z`jL#;qkXXl%sJ&-TnEHNip9|4m4Ao1#JXR`!@Bj$z!PmRUG^$qy)$QXu<@2+gL3L| zW}x-Pv1pGHOisv>b@u~Vm>E@1TH#LWkA?$=B$z#ok*wHhoU(O`_0qo)!SUetQ4)%x zN$$NElOL`qWCFXKxbPu;e%GO-wkF*>vtY9L!;${M!$WCi-vloZyr+Wu;B}QI&79%Y zz7C~MY-$5wHvGOgsqP*8;9?-&DXlG7-%zt<`Z52WOK_P@wiI(w%&Z{T^PGWnbpefg z{(=ec;ZJG-(DOI;_ESl-s*4NL$D79183tOfN*~}Zw`tuGAtqdoIRi7^AwQNioMM!G zDkYpcHTC;&A%3Oj@bxJJzSXxW#b5eulcXXuIlv4JvB^8kwFhzII6DJq(XFSMld{+| zM6WUa6FAWB40|rk7il$I7)1C=x~#?q(bxqkKX+ zFf>(uWr>37DMyWwHAGV|nIS&9?=ij*VJG6C%GK}o49oEsLN0lXcsls)E~ZdEHHh&W z*E1M`S&+(<-je;MbB&`?sJ^qFO`|3p<#D$3+9oI{NM|7z@cIq7XzW%x6B!)-4g}`S zKlWkCS&w_%{Je;b70x4$tJz6_LqVA+!Y3I5JKV!`mxx%YBhdkf>S-Vfviz%iUqVzWWMn*-vIQ4X>wrQl)N_vw@n#MNCXU|Brr#u%cv4)o^;tr97-g_rbj`J`3YR~o zyuPr*wF<0Ha!P+Xk&BRa^YqXsUpcB!@NzPUPY6QA5Z(z!-SSIFE#-7ipnMDL0T=)B z(xm>or%`NFu{)21mIVfM)B2lZjd0;|3?=PcZ1D%>aRSp6z*~S3xHwmSN>7h65H>rW5UU)(+-!8V_*ePcZ6z>m(}vVvAKjSv^`Xno&*YBDFeqR0 zzm&PwK3S7y5=Jlj?|oFfkqSy{ZZUwb=C{)5saWhXV_lX->7%gkKY3Q*`yJH~+Kwgr znWZ=UFB!955!jHj2R~Rmhd+PfqghrKnAwQwi4@`G7`H>F$FgAv_=f6gQE$>pbs(q| z=lphGrG`LFBCJ)rn@sKUXPq+X!e_sdmgnEfUU)uzCk!~~W9thF4FK|ZanB|^Qs?bk zX9+5$7*(;(J%(8KT=C0sTINC(8a_?FH}KuHtfl&13d1?!2IZwMx>>{jFoz#7j*y6& z7d#cLYPAYc=Es53cm&{8{c0{ExO=xI`*f4!HX6U_iqh9}4gZ6u=Dr(reHr26fFgj} zvyX%RHjgh66iIGD@9ZUVjF7*#3Ke{YLNIj)bC}q;`S|>OenJ}#16{_XnbO5VAe$QG zOM*~RgBl=g9=iwx#)F$2Ud4JFI5zY51O=?^|K;H zYZ;sgxZ8a`PP_KYQUn~(oY`29HCY*rcZ@^gv6Hthd_lIGNmA&q$_DA;cIjfZIy~JBhea8$0 zs*`i%&?J&1sVss|04jpQEv@yEch=2u9V3j9v8wMeSR*>t*7wE5eEKi*$fzK0%C5CJ zC*KMYxG(cdU}oYX)cpqSujtZrif_+o*0f%)IRRB4(7craydY=ypF&pX19Zvn3J3_+ zR>~XMr@nQQ49Skv3Hxgc)LTUXALYgrsH@q2a4A_yRhj8&zf)Izd#^tZLssB7blqYy zJV{2mbheeODn$u-ztLH)iG9N99p4II7ggcAqIJPwMl+tSVO$>_od7ibjP3?KsSnoD z19FM|jHrBiBIi@pN-ywRNj7w3tl;~#)5q`8 zkAHI_ESvweHo>MX{>x7Iu4UPq#HyC*aquHYv|rg&LhZiP&{J6MS{;)@`o{MpW4||< z@UscV*Y>_U7wGy=cuWBgnPX6|-)K!!qS7Kk~=;~Bu1^@_J;ZL%&vspil1#zf?aVjL? zP|%`-ic3H@5T5BkB?|xwAyAW5yGZJk2K4XFLO}>Y0i(u0aYlyx`|2|AVO2G~`k$le?+=%Avn zub-eCa-f4iqDB3`J=L(2EAZg0&6my!SJR3-gCiIdQju>GOK-5npw^}S4TK?LtBbeW z4#j{Gilch0FBZh3Dudy66we}#Nm|BVbCCC63FPpUH{ld6HJ7pdfj%M0}j5=Y-nSD{Cd00f6Pc?Sa`zOLZ>tG$N*zo1@8FjOqB#U0zHx#Tz~K%%zrB zCJzjmvqsvvXRS6Y#u#qP8Qt*K!n+oi$ib;K5D--(s?L8el#_9RJcb6W$WlLUgG^Q8VlL{+dAd?@jW=fq0yK%_1IPCT{nECBl#us#_ar|~#0 zKIEtDq0OP@?dQ>Ll!&{**c`SD&whI-VxRe@qtS*-NZ1fvQkHcJIRy`xIaLDYT=^=1 zyw+1$9)mm}fd-N##}p$)bYq!uL62B{mPwOd9iP0VqPe3^V@6C50DIntkN{!Xm4dQ}$#7%+zCv0Wh-9N~#9^Y`-s$;+KUn`>U5&(BH#( zF#iJcBHTN=NM7Bpvzx-^Q8$+{sgZ#ksST8|;2&H86q@c*Q_FA;fEYaX*J<4+kpGXQ z>+q-Q|NrMs_g?Gb+Uwfa%ATQf?NzQB;?pIvWuy?f_ZlH9D;m0HMucpQOSXojWQ8P} zMmE*&ejmU8;5^Q`_x*l7pRea|)|9AI>IAeqm*0&AZusdaJIP1)uZR$O>JY z|NTUZcaCZWLgITZjW6lF>~S>~)@lV46{8sEC5NEZ+UeJzOseC}yU(lO6w8>pN*Fqc zqr#D;nS>k>+R>kOcL_l|!zCvun^rVw0d_ZJ0OzKMZ~qF0Js3}Sf?AW$A4SSj&zC|L zz4?L1XCo#sN#CW79N*FJVYBe7^h;h(DLs#X;ZeEFNTY(G2k$O7ux`0$Ia)-w(2xAO z$$Y^cfeQRfO>~2#W?SA76GlfiZf8P*hXJpC>5Z!%brK%erqqVg<@l3J*<+l9tasZc zT&B3s#L`z$sQ<0)pRWgEg8*kMkBUJpN+w=*2P$DS5?co8@=bayPPCtq+3kSF3}uRK8Zs^l?{r zh4x5%zQXLlmM1){v6tjFa3_U&YC#c~wj}5}3&vT{PxM+iMw$or!QomoWZ+i}I_FT{ z-=s|GGBp-G))nxG?@`%d^gZ?(&HU+do%T?g*ik2h_Irj*_KJs;qr=rXgb`RrRC)9w zw?#mxFq=n;Vy^`UB0K%@EdQ*Bt2b-f-Kx=v3be~AEvQ16%wz~^}{{Msa zYjfC#FFGze+d!);*hQ#`5~M~JbZHMnSO8}#!yI%!-|`vLC^LoAl*2xyoJ_{)nqsWE+yWdi@kWB$6FUmd;Gk4mcMd`|n)QX@lFwN#gFJ$sW6 zC&d%S*cHOb@i}4GY#$@`Wtj1|1PaxV0RC@Wf(Y6ze3BWON-Ae+S|C(x(oH%yIMyyM z3J{57vI2PBgyqMsMfcWF@gG$rn7WkT+ou6QVj>*YfBQaqkZI8UZBGFemhz>Gi>T7{ ziv-7M$IAC*Y+5Wo$uDhEriC8JHbJx_N<~`PlW{($u12mzqAd$;tMjKJlPBiX)~=en zEC+jTZUB}PyjKKg^dY(Gg^jqT6_|M|uKaV~^QgDwx=%r>xb>ZccSXhn7)oc)m*Zb&YcjNA;gdOPJ+J(%jZyi85gc!gVtLsYLP!FQb)l)u+xxC-yY}y{prUpv=*%{nd zlnnACo@2$XvE(imy}kBL06r#gxK;f^<%xpc_+7kr^ZW<~R3OpwCE0N{lot7*I0@P; zIVVvdhL8I}biUZT2IHrnP~!qF%6Mi2+;|bSv$IpJ^giNiwXwMx%y{()G;wloFM36< zqwnR_Aa=NQ<~=7V(QhK+jLru1wpl`i=%6qe1+9K9llZKTm)88sf3sM*O6O2o_$0P! z=bL~%)wT~4qfR#$1C~2-Z~bji?Z~{5?Uy*8U3!+&5zFmBY|bzQIXr z7VA3nTd}pON3H8sYtOFVk#<-&L@Mb>zVxz>Wxd4dV(OMWgufwpGtgAva|H|jvY5%p zjb8GFZ#%;#mRD)H{6nTugo>LK*QHhpQ0lC<_ji@6%u$4x0r%yj(EFUwa8$!wmuy#r zVsUXv=-HcrwN^(_CQTM;+ zNd3Y38Zxb6M7khQjA*`?CoOj~{Z#tLdzZe_F?#l|Qp}W7Y_G+XBt3dmD6_oNCu2Zl zZ_|Yd4v$!kQq;4yH_HoQjynSjdCFD!49IuXWG)r3#c%KCcg;8;>l^amxB>E>i z0Rq`d%mBTF@!*WE0iG@n45Ynmx&NPxl%sXMb&l*Y#z!88PM5zO=zR*2yC+v~fQ+^# z1)TU88J`!e`{(BS->-&Sv~|C>pP0M(U*>_Am0=re$;*-~zecL_iBgb?KB}-+?m+6z zN7A9lDLqSQV(v!0o3bl)a5`m3Ae_6#IEKA%)pFnQ>rs>~NVRHy)cd<8@tUth39#?c z?6@dK2rK1~&%B_g`ni$=TRq7573Cv{Z8SJ0+ai&iuK>lofL=F=MX@#9E$HH8|KBBf zO60?{1dnQ-OmvT}Zed}Y_iDH&M`C(LW@hWdwC_DskSp1l4Ia15salTc1R(OZ-mn+C zyH)x4%h<-5OHnXLmn*~qOHqWpLjb1Qe-nlNjK{LM?ZNsQd51-Mr?i(ubnDplH8?qh zrS||-;R3}*UXn^2?tL$mH0AprJKI*4S%`}_2KV{Fun3~oj#$G&$XUjpGbjN^;&PhU zqbvi&IUbKXT$jlo2>zn)-*D1gi6$SC`cPZ*A_cUrd75Pbt{=UuQ`OLT%h!^QMZhhy ziMOYsl_;ueMjxMET@qrVW;a!=rxxX#c4>pK>9!lzw>9ewBG*Q-RV|axKVhrbGVGDY5G_R^^K9 zB@fv?gx^QYXCweFKQZ%p1K-wTy(CoC*!ImkUa%f3SP}W4tRUSX{`ctIky7`;{(ZN( z%ATkge9ypv&I>d4IQJXxgGdJc5|5ET7#@M1l8+I{sjxQ{zY{y4pNuNWOWXv&Fy3Dn z`vD&Yz4#+b0I2*%D%N)j^r^Z@`75fry#dajP5&M?kpk#k5)ClPeJTn^z$>q)I;B+P z$IjRzP(zswM-Of`cv|x&>l>@c1b!Bze}e0(mv`=JQue;J1~I=cA6p*)?fPy}j*ywo zJO8W&U-jmKkW=jzGQYw&^Ebqw2wXN0P=wX|8xX(k&}gbvZ#U0w2x#B`x4fphBogxX znC+=UneMw4CY2q;)rdV2h!Pp*aW(VQx&PEW!Q2FLB0O!7qX+^INb&Iff)fJ^Dv-NE z0&mkO2Dq_kHqcY?Pb=MD-Z$QuE`1CiifSq0Gp--LeU0Mhb6bHu=Hw~!sfu6_oc_CfwhGcGsEWsdAmQpOPZ1ma zDvXHBoYSR&f$2%F1wj-NKK|XGLD9hG=#Q=Ppj>MaO;q4EUqvdr>K3vi5!i|>XN7(M z7~F7E7GNL5??<=`ETpR+OQ_uu9!7tbc0Ia5ldV3OI<*sxckcs)D_gL}uoa_?+N4-39pev=d{sj}b<9c7*>aReAw#Nu&gsb1;mcO!J8^kHk+0>tcU|> zD;GSt9P{!*y!gcF8KV9{-~aooo~|$3-owb8A>%Pvyu*p#R0HU5cKMfylnA8{j#TN(Vbvi%Auo_Ml%>xQRbiW8R{OyB zhyeos(^LB~V$UU1zuiq=j#Q;4O=xO1ewRZ0vIj0s^C~sN^?IEEc*ty%&@$A|aWRIS zuK5~GqWGO?E9J5x{3IZ8k`A|UjjjAJM52nN;qcH)i2 zSI{GdrMui={wAr@IoFR?2@331!@La$IB*Kn^*& zrgro)<8)->(%jI^hz{vwAntxVX`Gg{P=~S_hM`@6QpJLgu*!McW(uV9O%agzV|Ee( zQ~2IAO}{B4>;&ziavUcxG9s0us^^6S2&)>CNIFHzr1rWDBO^v8H0-q%S>Z$=j|Bq) zU)7R=KvSwSMe*QB!R^!i6SGb>t7ZvKcnYru8OjlR;Uuq&|dZ>Ba-+s2|_+u~b5%(57J(#yk+A?-JkZ z3FYc&pDfYN=dJzK#tJc{VbyQIb{fp^_s}DgsP~`YFG(-$l@<{y>JJQz?v|yh*qGSn zzO3%;WMq!y>>Z8Q`vgYWKlM^^<9{G0vT$#x2!@Kk&xuV+n;@`I2$}IY9%|?2rZOTx zHK!!-w_w~~?%8cNc5Fq2DDwGA-%fFaEf`bU>tn?t9nVX^ubPM${%a_m^}li8I4ht5 z8Ss7jhY?VfEAeg(&5X}nmOl|FJe;L1t=S^cKV(0YZQajLB&Zuv$$&l!Nb0)gWAIEF z5B?a)m(6buPcnK&31!W5Q^kisz@5uAqn~7F)1h#sr(vn*H zf@(OP_dS86eH6wgkI9O?&E%bXKB}%xH-xC$BiPHg#}RzOx7je9nWtXL690v+KpIv5 z*59-L_MPoWp}NG1wz$=zzNP4g2&beb+W*>moO>fWgRR9$q>98U9jiRX9sp)xFm*+e z@koK6R^0WdFlcg=7>s5vUCAxL=8vas@f8`}uNWZk5tJ}J1KbcqV(Tp^f)XvHyX`V+ z35|LoZDSs<$LJ8DT#rV>m#_^FjyV}E%HghgBwnv?=2MI~R%7>jIHTVebCbFBWyj*y z-UPNY;$F5ePsF!H)EcTEC?h;lkR+jj{eH|fU06U|{KEX|$5b>t<5Yc1N=OKm;^&^@ z6L+>Nk)nhp)xhPSa?UoD#YT&whSci-atGDB+D-7SLgn(>QE4#@k~Ep9|Fq z@yqjox;smR0!`RkM=&dWXz*@<7Zh3*Q8CU3_opzh(J&`S?-e+FVt|#z0xV4K?fUN> zYVTdk{C!qyj3mG@j#N@5LcdrMVDN+mK>7+20YgsjLHRFGHIYWVG$^62{VPbEG!4b6 zx488s;uSZ!i>z}7(xj@P%rMJ8`Y@X2YsS{r#oMZXlgCEWnqjF3e)!fuLp8mr&W}%i z!J)PkuuIH8`qRN@P9ZGGJKd%{iF*W5^}19gR4T?3S?N)DKFjx_=xQ?U&YjORDa|Ix z@o>&=R?`}-%jiOfQaM@8?aGXmGFw9PxgVj>`1bSdvunqNAHs`*Y{;ssXP7%>KmvmkWs5rEl*fGdW%E<_=wMVlg79J6 zfj$HC8Dz`Z{hS3KJ`REU7tfrP(2bcvCJLMyeDxLl zC+=Sx7EPkrNMyXmcX(kQJNS!H&3l2L=y@FvjU5&H|6fkqXsxMeY zRVP%#V^ts$Cbjk=y_`Rf##1y~gp!X4*4LUfGnlzN6(>N_G(QYNv(Y)$GcnAs%ln2_Ap{SjP@wR!*E0J7u^)PRGBSFcDZn!Tg!L&v z0g23npywyrdQ>cie94DO5+M9tHd_t@g8Hzbr`iKCR^;9qF{8kE9#WA4KvTpHmDqkg z=o9~>6d!@{Vn~PrEflFa6F)leJFEX8t7?_6Worz&_ial4Kx2w_#i+Z1Bn7YFYx$(u zfo0b{z&^AL`t3rla@$WX6hMcW&2@-Xm=p+g-eSkmMMke2I^iV(i25I+<&#zAEM3>_ z1TL*yDlN#3OBYm1Tt9Zka+4tUxPv(?Se3ad{Jsoo5B?C#nNqSBv{zUP^I9Q=3Vhau z5FM%2azdJulyA}#aUd*CgPgR)BZgm#*m8A?l_$HN>a{^(=|E{diDW{7MU5(xh zel^jP>arCtlhKYmG%#L<`mT$tLobS&fcJ|-J!?~JesDl z)ZX&|X-K@~iv=$ltl_khzA7O4$Kne}6cZ@2Pi>(CqMW(}MsD^EIzF%CL9pK@$b>TR z>F`l!QOR@Y2;{$zQM>!P(oOmN-H6cT7Tgv@_6)=LUF&9r2k!& zl`ZU1VJWr0{?c(KTW?PVECClO1qxuyZd{2DR>zc|z452Sma?gABfsqybseOX^W`Uq z;qz&$tZQR;2vr{`%??I`_E(J9rm^X5M!3lfcgFMT9oMG9M@U(x@~3zx(*W~Kd+{Od zyXM>5!TbTI@@11kcKrQ(-f>cp9_bGukriz)P>QUkJL#jTO;#BAVO>oWtb zZTl%5Z$p+4ENALa#lyxM{ucD0w+$%@P9N@86Z@=H?+&uk4Q^wTgNHmdle^u0QKej5 zni2>@LIQi#`A{lCI4C1z=#OZDsEoSMn$U~DWr+oL?I=U5D109!zx!luneQ7=`t3xL zA=FH)?#6TuYY3rLt;@+f%CJ$gGeO_z2}`Af1~_(T-rjgQ8P5Es@r-#7S{6G z>f1-2e;3glRR)mpVIDdL^WLaPK?S&VhA9@$C0Ob}fCpb|+RCVrZq}HIYU>wxudjRY z;>fs=^oOzg0B@}bHkAu18(&?D{8|yK- zptJM~8%M$f-uXEb5c!B`cfug@zw@56VjD@UWgvwWyUqbM0H{o5ghE&LF&8GFmqt=P z2m`4;N8O~9IH5nyR+{8l4s8ZiA816NyE-7HJ5Ihm#HoYPkE|?6r7$v-E%(K8m#q*N z&1v1#Cx(>6g48A8OH@P%;6&mBB4inNo^%a25aE_`vD+x%iX(-5|5x%AK4!KOZw3_l z;0dgcYb&G#hjWEME9SmqP#pu0Ek;Of1r_~mdV5!9qGNRA)2_6U0~5a*w`+omEKtk^ zkc4N9ijtSvQ!(&bBt!&HV!$q_N#vyGbuf8cH03<$ks>vT}Y2V`eytPS0U{Y;TU*l$MymQrMy*J$1V3Le|3g(Po z3(!LdWukAnUj_Rdt3v5A#M)V|oIR*V6>ftMZ-cDW%pcSTT$ZYHJOu*&^R%TBXtcXQ zm%9B8s8}BZ;?*F6@cr=*VHJ-y3p0mA`%4=D4;l{n<~TtYzy3rnx)RNPsS5>C9vi9miQ*FP*x4qIq@+_? z@SkiIxl%q-`lf~HwyzxzZszx0%@EEDPR950(0?4io1XXS!3`6{r&>tNI<(q3vEs9* zb^l@2Q*Ud*<`Ww%^P~5Ec7!!WDgp>{OPq}ur4e8c#h0$iOpr2Od_v-OCG*oM)P7%plu7QOo5 zamP*aea_27Vrjg6PQ@-a!4O_8UAxX>F?L!gmoHMR#-!!5j}ZMd3eUlTio4mit7r~~ z=Dsi3k`TqT9frg4*bKf23Pk{q2Y4+{eotowa3RulT7U1dCCDoeJgW3Mdrp9y9aaGh zEZ*CK<9>ipb2W!(PUdqfz>%m-LXfYC1kVMpL$5@dfhr1xX^FugIa(uT!CO&X*GK;Q zsJ%e=MtZ||FPO$;0QD7B#B3T3xqtshyL+$|pwrMIF)Po30qIl7Eeig3bQ^`d!VSj@ zWZbYOm{_0t$cuGiM^4;+tZA%r3Iu@gd{7Wot#SYW3(s6`WW06$rYQUG_vGuu-Ijba72MOtaf;onDBp1SzDUC)OTW+8VO>XDc^# zc8&pE!{@0**4$2IoB&X2F2Cqj=Oisp^45?=b`Y&s6lEzXsxhuPo z32EnPJ|(FkPk)Pb>s0Om zu5hydWYwGh%yR5XEsi>p^2EH?X+?RA1^9kYdXam8jZd4MtxfAlS>w`eQLWn&)KcXP z$A7bqv}L3OyWJ5rlIA$HRSIJf3gkjZ@Bf#Wd&841PURNB_Vgun+5N&9E8Dvp(FG__ zgXiH8xoRIKp~IK zXHtjdfs@rv0;kCDIoWb6ouI;Oj{zQ$52W-vRH}3+Zh}XS~|sLuX6rLINN>c=X;OMe~)(0 zzijguEOtGAH*MB zxm>N)I<0cG#fM!v{bV}qJS8zzumc}Py+S=+@<=g$hvXcz+!EpZ?xUYLaJwn($_}YJ z(D|MFzVDaa_}yO_QeaB=Cl@Mk(DcTI!qA)=tA|nVI>C%`@r*n~!Q@YuI$#C>X4w8( zApb5w{|d&no~lvwKl99{d`z$d5(6hVQIfcTo(8e#g2Wo<#Ge4H-96{?)Mg-6&MuaZ z2&ow_O{wsY0GyqntT-nZG@K-`libQ)5G`aVcuP;?(Z+)U@i`Na-j~LPWs~#c0I{T` zS?f`fbMQ|C4!K}e7DQ@`Mzd-|@r=j8+hx>;M7z=_6HME**kQx&$+&vA+=BGY{c0WW zb8gzWXx3G{uysoCYUA3EKP7||k5uQin`gP`l=Kzun5>h6D^x~R7%cV2+oqDo&S7MQ z5yB z^Fo$;=Sl8k|6mXKyBC!yAE&vWOe9>6d&^3d zGfeN=T6LOwgXg>$3esgZ0$x;$B6W@>{_FC2{Q$)4$vY}Sc~3UHKM3;Ey-mu#sLJX& z;#*J)A?%!a&5aSXd2pJw+4K7K!LE0Obn9d~0fm}Fn#GWCOM#j56$*fU2&lzPrv?)5 zNMTUzP$WsfW(@?&l>Qe(_^9urj4g{ov6_B5DfCL4BQHpa1>wMC zL$oXOtEWOt$ckt|qE>ezqq;HJTS^!k{It$0yU^4#KR(+!`;@bwdkgD>sfSF5wbf#CT6T!m8Y@eCxiwchwQ4LE1J%LTVx zfFOz zSy0>seg^)gf|ey+a=Ex2up+5G4osv4TkC7k8G)j;aspS1Bi~=;U6&cFg}Y@Zw1imx zr@2kRYgVa&jZe4E{O(4-*W;nkC9?(=d>*>6aNI)jh1gJU6xrgl8uK3Q7OGpYgf;Tu zf$zEGvnnDI;zDmdFISl8@Yh}aOS;K>QYd1m584WnJAT)EmVM!C!n^YEs(R~e?n?(( z7HG81bu*k3bfUsAZ6e&ncRo2obbmo60PXOa>%8G3rJC|~-BMYWwCaJ?PrX5@ogQTX zN3AIKI+pD}s2+c|zm4jZ0%7S3oIq3>N%Ijxg!_iz2?vS2!CcK?54Tj=mlXwW8}fe+ ze*Th2YA#-%F)=H}&ma6krP)8!N~Q6`1ZQ4D_uuQ-x%oY}PEl#&i2Il;U5hw>C1m<;G^h;`q;*1mf~8-Hk4wqy$iqmM+S~+M#Tro6<{M zLmQetHl8qb;Ul)d`=Qu!2aN_hvy7|&+R;-lt zqAMv&fc1--=H(v^C;f$~PoFJ1hRO@|NTp`=2h+Xk>WxnYVOK<4?G4fc6Eix-uZ%*G zU;j)gI0Ju5EHu1w+60P!5;6XAFQ7xHDS>*cjH8TytJXwo^{Tkc917#InzmDN9Lu@W zp)JkUB#UG3Prewhprex0w(Rs>V8sAMwj%tjHWr_6J2<%&5Nwy`c5 zT47elv-^Ijk=v`tH|@Mptg+H)3ESaT23nZue_@m&B zljR(}DNFSab0_e3ow3*eM7j%PR(eGqO7UNR82oEu5Aq0kC`CI!ZfwO5VRgV#4q<>5V8hUELxKo4bNM_Y?yRQj5@ql|7mO5Q3^7BnV^fLt%4&?$xab z#P74=RKJqSwFn4={V_;hH(NMb!2tc)h$F=0J_7ZCGJu2+?`nYyW_P*~aJUSh%fnP| zg^6WlWozA|T7J*bw-85OYJuZiUiUYjL~&N-J^2yi2+y_goJ{z{*0gcXK1iGKAVCnn}Z?X z(_*?su37>xw){XUkBVN1X-q3)i7g)_R#Dq{NF;k1R3fcbq33+ILM`0H4Rk?&`7Mp5 zn)gbP2E$#z91r1R*x^v;F-IoLkOcg@24^6z+?lhx)8{@WkN z{T7TPC7OADm1TB zx$u}PPgI*mG!KY~MTH|+KMsCfhosEEy7=Px0{*ouZ4^fT?^N46lX5oG)fh|DrS?be zxg?0p&&Y2-DG0ZPXynr@70Q3JXHF$f?jEg`f5N^KGcGnImT#^4Z&A2-+n4k56F19d zp#V&PP>!vZJzp_LlKyppV*IShpNIQ+{gaiUtmggkd>PUFj$xMQ&&+1>&*qUOH;3gG z9!SF-Sx$H^<+JwxIDl>rdaT)H+vK!eZ<}3u_;wC2B~sg?xWq+**yir_1d8=U%(X#? zv2L|%giuK_d>C|`QZguB}E52mtr(d=>5Z`lhxk}}$M^O1GP)(~TQaNPFpPv%je zXP~3TvvOrPO!tZ4QKtgbXOPR^XZVsU*E%k-EQAP=XI>cjAf>RAxug^;!aQ$s7;ppz@|OPtZOuPX%Qf$cr)H8 zc$dcO=28DNWR*uBd{YFXUSWN8z)gtUjk)LFMz14*NA_wArN&8GwNsXB%vqUj{ogE( zl4V?vq5Z$j>TtnXR?-bc2UuN?|Dy<0_V7kM~KKe;R)XXA?1hpCeR4`7VVYQNIGfCl&%RSi)!uk^)*qduw7*i0$`! zqR^|FZA*v}fgLtND_js^u0$E0$ z{&j{YA?Rh+SS8)CWivkj8QV&Kb}!tzmC}w5C*?fV;lh!0{MyuWUramsJj`p%$e_`x zaWx-rXYY@nk`Q!&8s_W}`>HhLjgS3$A6jlrN9-=ez{O!uUaZp6n^eaQ5z0ad>+S-} zWW$EG#Lt?SSB%+G@eQ(YjKGj~^zVVpa#j}p%SgEYJN^q-vNoGO$ydBi7ve80OHO&Ypd1q|{uB&56@2+#~bbR-n)8ufI0D!2dMQ zpoVTLzieM==ei-K^35hcH;RQv;~Nx-Nx{2|lv;ZV)WQ*NHu4sMEsz_Vv2N)toJPLg z*W>qdWZ2Ad54>E^l!-Qp_vf8+@t(35aC29iWp&@R3MjFBw;uFP1!&8ay&n<-ySBfT?F!{aB9%eVbO$J1ZZr#Sg%4Y-~VaDZ9i& zeheh0 z`ONxd)l@}QpRsfIw?C@Yx)M4do@O_usQk7|0dhguVW_{qO=5CR=UJ9c=<$*uweWXU zC$H9fNT8rlkBwtzG(rN}Lu3w*!|+Ac3ZbR%a>vg=;QX8_O1uXAqy}id_Z0}T%)OFt z({)EhnPZ*IfhTd)Az@kBVpu{uB7_sQ(9(vl(?VEKC>K9v(I|_56tMJp{>Vg1KF$Mx zXw`ydSd#yg)vjY?j995ci(k))P_Nr>6Y2t9rFavibsNI(; z4s)#^R=6$-i6kjBMPCBP>Q5Z9p|q>csonpS<~-j0Y7U{(Fgr1wWWCX?hZc8vHGTfV zIE#2(*kM-U@h<=r2Z4@S3<~ZEprq%~3f1`(#%dsA9TJo=%wfq2G9ZwMH%h;u=2Qwh z_QMsdYAJ>eqg?Fycmhzpyl_^0%Yt#)jFMm;J`$Twa)pi`=y4v&j8))4E^L#mY3T9Sp_9- z1cpK3gdoon7HkpY+pFJ~KbgC0_VQP2i$208`56@&UYP5Oy13GFH!MCp{yRwC*A2}M zczf~KN}kaESno~kbl8`uq%pSsw%m*UMjU)r&e}!in@fWwzaM^R@?U?;W$gUQBr!LJ zQE}!P+JANXCO3~YGHbiqZx#r-q*V(Mo>J4ozd1&^nmgG{j9W4_!;Y=Qrp&9w{q^#rNrxTQ`GMNiujSsjr+Dfp*n|G+2%%DeM7*DC+HtJ)Mm2X3P4yHP*>9!?jQET|<9!W5{W35} zd-Txr4C7X;-9jXbF&%G>KNiFJ;0ZEx&VBZchk-5x))Inme0LNTx0jEWjAMUE#EHmh4~17zwnlf;IWur>$ey5Rwd87@}9hOg7+v zpe|Z!TnRe!jn7ajze@l2;?3~VC$zu^ZR~1WE4|->4JB|yaifB>$0_fq=UzRR>VWv- zRsa8eux&nMhkt=XR^xPToiU$y#ib80ER|fK6i>uIM`*(D?mXDvXi9?1EUH?l1;>EB zhap6zgVFd5ILizidF!{@saigP`0rf*^>BcYsL05gsG$&;5J>Hp83U=yWTqvG{TSqy zGjw)qV>CR<5Unk&2>-JRq{OjTOYqqN@M+hr=kLedAn=fxs(U;Xa;Wi!A^$IG-RXy7 zf=ykcYpt>)&yBJ63MVRL(hDB1-etM`p9l<2=SC@sUuR|mT7O*=$F5J)9{f4RoyLpya zC`RzMT4PeO0GevjX5NF7n-Zri3K$*L@@Cx3%ekrMZ`6&x_wKMZAWc zAE0@Ekyx&pRCyYDbGbk=62AGwM+_RVC>i4Qyre?8*UBdYQ^NV{!Ty4T$wN(XnomOZ%sKWY6j_s>32}}L!Ujb5K^}X34K%;P%$a4DnX_ZQ)rDDe zaba&PzO`XdJNulmQ^$T~_nr>uT5NUy&4n3f#2VlB!!${dz?I&!bJ;kkNY;sM{4gA4 zYcpO}@D5t{@UAmPvH-XNESB-yUG$wPb4HVLWwiOk4wREp$uBhOib91AN4lG2GJtnJPh_0ppXI3??ORCyB>Wnw& ziejUAX=XFIN8fgUo_PMX#CDalPZ1lJ{z~?)PbWS27kKYX9eVC*{6&k%a5<2EIFj2D z4zP&Bs2DtB&;S7~pP|val>On@YH3tAp8VT-2}-^`7}15tlMsY($m7VjMbDTPNnn8G zUjgwSPLssyPyQ$F6lt5^+I+ek!h@+^%YdPN(-P-^L<8OJ3bT;V9sv^l{e3?;;*JUy ziij@&0<C`TZpq^thGe2ZN6C zJTpLFds%wiOD^Kh)u0?H@h*AiWjW1Go|b;|5OxI!B&VKOv{Q=vta5q^(i|Y*p^eLX zFKnZ&x&PC98|1_e89gh?Y0fYC-;5rV!~IU$^bu>4-!)e){LdZlNrAw`;Gxu=N#gCZ z9HP(oWf+UrT$n&-tDIY<>|c#>-8P%lkU2+k1)2-<*E&rR#B2YG2VxK+u$ai*4KW zzXuQASr$veJ3oB4pPUJ{-KNKZFJAjGDK_<~-0wnPU6CWbO+}e89JI=jrZf@O*j|Hc`R>T@8V#-CQJ4-v?@J zpGgVkerPel38kEO3idcJF;NK2DlG7cbqsQsYpSr)tbbp7ms{ak7zu$xII!j9LIO$6 zvL}gXbZV`eO~7)e-m8RHRr2?28gGrQ3>R4*OT=KJF=eAWwZqu+9_MLLTPaO5Cd$`$ zB8diSPci^Z^Xu!8cjY;F>)__=eswI#?^2KvAz$2sXQEd7K8aw1MXoznN`!gdc!%kc z?Qp5oMd;}+VhIhe-YUR(E4-CcPe5Qk_dQk+@ZI_F6LIT*4+pIm=4osEd|%jrzJu%+ zEAMvapY4BGJm=rSazn78fJ)K7Kc3z{ca;s^3j+OrC)*I2Q0OTw1}EDMDnP0BsGj8Z zsg?7>!h^FC#ED??Xc!9qf*q*x`4`0VRbaZZi=NQcMYu|EPp;l^g)$(60HSW&-vBHE zID$=n*F#~;*Dem8yL|>5DObXeTgL>-5XR&jb0co!0z@&WJtdPj=L0kp$oAFqjfbicoG4HCx$ zWSy=E*k>oC@#~<;hPkJ8osq&IgYEsn=8HB8B`56;KZ<_yP1XkN5-Z#Y_l^>PrzH43 z1SvYl90721svbgli}|b8SYJ&0^XQYfs*YtTDl800eA{Zas9+4>ZJ{hZwLP;8a#moE z3kZ?#aZd~_z+*783Petf((~qu@aQiJR1B&D9^g5XW67|x2&kO8GgYNG+Egv zU+vw81dRu|XjRY1NMmR1f;xdfuOR>vOY+%}&s|f55Aa=l1ulhHbf#=CTGLPyXV%TR*S=xk;{1!@A;>Gr_VM9M zSH=TPYxAGg(`XJ0oVglwxAw}l-{OViMYlHs>T}y=PJbJ9{W4e!AYV2r$(krgd%jzz zjt4mB;mw*B&KT}|3l}ngIt>85(27?p!&8lF&mU?8NB7_jiCs zy~`WEq(Ci39vkmNUj-dv=U7p=>y$zLfU2$NnfQBiz`P?8gQ)VI^z~#%weCEKu=T%v zy=f_s*0AW9_^)RC&P*V$kno2ku?gN({|U=edpV;r)ey8Xy4u4qX90LZpL_gj*k4Ya zH;FCBu;UXgD75OrXpjU`-OGn z1o8)WG7>2vFp4AQ?+WL^=%Jc=;|XP5@Z9cg0_LiDO=s?~lt9c!Jur*`(Ia*j9rz)c z8-^MPEdERz&GmtMSUR0zQ_w}Hgu_%%-U)&)b+85e(x7)Tv-QobMmba?!V9Ly(u*G~ zObCID**ljps4oAt=Ma>;%i`wK6W44uo?kY~SbMzp>f{(Z1ro>N4S{yuZPbNvWl>y8 z{4dNtj$vLd-5Vnt1@G^^|C4+i4(~F3Hxfh-FbW3gLU5q5Bs!n^gy(?*@fX_>AZBpy zT_A`+tohz!Q(rlB z7^5qvnJ=VVIXgy-08)dXSF_J0t5}eG5t|(#=#14oClaRccFs`}5+pOihb%$TDTQpP zo=)EDY9}Qq2)JQRagLa1A~9onEu|?j?JpQ(|BG_$8KF zKd~uAaF1mwg0_f+F&Ljgk}F87Mw9|n?*?FK=eq=gZdW<|47tJNG|>NO)fCtMK70>z zNosODc=GOK%ju_XauE_!uSV1N(mhlyNu?fz>O?Txf$qm}Zcv~;^=zIHzj5Ta)-l&y zRUJ8nveC`S#t<>oeXO%ev+?8pcp;btAX{VqAl?p7$Eo}6JYD7SaKr}LmMxI55k>Bn zR9`m0LWk=9OB>JsFT7ZQ`;KZ{;FcjT!qr+KB_eOKf172M&(}B%ffM1B)*Z=$T0L zH?iPE2^vJ~$^p>*Ip99ILD$i+KDV*~l2=o-(^KYoI>h^jJ9%LA()kYjx}=;{Z)v5w3x-m z{c@0)G84Z!B>u#`6U9k8(reEHkXe8V(xBhpv~+?|wIcPQIkmk9N&CNJapCD&LB*J` zk&^f8)6H-s))527a!a$YzhGoTmoB5;1}EAAB~Wr5`p82&(}yvQ#~kXfwASchN07$H z^Zln8KcdC6!HHP#ecy-ACB>R41+O6$ekF#y{V4`nslrd-Dv>X0Q+;{M&sDS!H_X5v zr8Kgh)`}{Xol{pV12jwJQ>>x_ApJcqKk^G284h_=Ko9;7nkhlh(Y=(( z!4~M&LSSWdFWFl!s6+l7O?hJU*K?ng7abiTs@<`0Dqq_?&Ael$F zLU5U)PO)P;kI^h&Y8r2qT}SXrr{=B+-`n7TUtEc(&F6MU49FivcO|k@Uy;Nt4aCTl zhtWBl6pyn+DF~>y4zD&#m0s*N5IcVr79ql9e@RR1*a^O{M9uNDj&p0f5CNLTKg6ja zKg`;aE9j^HWdtP@8@_rPI}rWMoal#GNxQN@7QMFM!<58JHgoiHW<-Tdepvpvvx+tb zSRir|#>gtyEQIJ=nZvoTk&}`H!e18F>A&oE!A<}V?Hxl-JmoiHFNIi~AV>ad|NP3r zV}oDHW*kM-kDqzgB zCWuW_dH#Tf8fGzHerqrB7ipzwzxlG^{5vs`bM3Y2Oip!!yYt*HHrfJlDrC~Ao_+B| zU6D@fU{k)dRn}@I^%D!2btQvq|eatN@0l8oY4VIWMIbsqGvKu3E);wNyKt*0d} z9UmHr?4zl(zA+T8^E&$nn^9mSCIAs<_m24Ij#-g{^x!W@IVMN?C^!P0(8wX0rf5+H zUIp;yrAdF3iiEz#V{bAM0m+qB$(0dOmz!VHBDk%K;Vq?&ud!y5*OrQ(H_h(#zij47 zsu3Da&-=p%n)Og;H5#)ODMJ=!>DHELNv(`aT~inA^GWbVgnu8%lt&?LVxE5%OXt@? zxwhy4p9O2pqF1L~JyZwTWOY1X^>Fh2VHt78WiiM1tf|=N5+i9Z+u_Q|HEN8euaR;_ z_F!$HCL!q1Y5Cd-@s{=++_6sHSb~+zMb_mb-3ts(!{@M@7U^{r`McS3p}mznm{A#6 z!h-9BAPX7Xn~_!RCksb?R9&(3cHpBpz7)iod^I6yOP)1$9{|s8-yuT?=-Bn#N|{u#jl^r*H(vu#e3cwsK{pCcW@fS z(1#A>h%j5)tFh~yV+^)ebSxAqL?6{e1eXcETQ|B;1{1iyKcAC>0sDY=!tU`X8qnKD z=x@_vePxZ!I6LUIp0fTchjz>w);`qzMJ*5p4IPUU0AT^r*N3jRkTrEb4KuU&U4Y!VRtfiqT_F_9t3Yf%k}s(&Xg#f`fS-rvwAW7 zFGv$!wV;cKfPb%84#mmvORd^LKq4gU5=gXe3>-N|s{ujbA~`y&R* zA>dHk;NO)`sdB>sU906*3_e)Q)nWp>juRY+p~-&#n$aXuf8^etEck~r1LDU61tBQc zn-OnuLjL|MX$rp3$)L4RfNwk_tNuT_%d}^o-szPWMNJI7daW%fS6aX!HEL)QyaVXn zmA@5jt8?e8$l3_6liezXmK`eKkCzyB^RoeCN{&>bvt{yB8WD4YI^%nQ&q0zHR-D;3 zNF=VVFn6a0^e5pCsy1z^erdqO)nc8x!~-4OdUU<$Cwk9;aD)y zKko(%0^&b}QbC}(&>7a-YF2_UrZ=r=m{t_N1!cmjR9=91@~5-}V4BjFonTGtsrYM| z!*KJK>hDQu9crSFhJ=#oASRlx@0zlw8D)rpWq4V3*A^dn?FW zS-EKu^u$;))cjvz^t^nb5EX?l(|``PQio?2jYeJ+1dV)ujXHm4uQhoSXK`CzFefcp zpNl+`rXkInc~0g>Wowi&J3+2vbjTlva&@>`pv}8_grFKuCNlilhMb6IJt-h!5U#B5 z_qkF?#8nwB%=hXvplo&1*!*zZ*K=M^2y8wS7OS)umv`Mja`q;YP3MdKZ_PP^DzFfe z*a-I^gSq2Tnp|%oAX!!vAdCUb0njkmhK&U3oqj1fL( z5Gdm7d-;ZSkqoNBo$Tx>Jp>Yi|5wk%QvJ6%BV~XEhNgx&t#tRQvHM*!??3!~X|>_9 zHH0SinfE@}XC=ldb^cY5{`^>?=Kj^R%*C8i(j)%fD1Y?;M4zPEY&99#oeg-|s@^`?GP2Z}>Yx7j!7*a(CrYPF zlc5`bm2S=}?>&5A2prT= z0!{6dDr2ch(LsgMBaK1$*DoIOb{Y&^#?)V@E#Fyt4G+02VW#rw`%x`~-W(tI-NbHV zlLf!HPN3C#aJHftJsihI1w&475iX^jFUzN=r;W_)-on+!HCAc&XLY zhcHg#P`2i@Y$E5}r2J>K5Ukpw(WoLG$=F?L0RuE>U*BD{X)3;L^Fz1T=~7lb8W&;M z?oJzg)HqdDJBZfZe3##Pb<*#(D2q+Gdwe3$!+8*gw+az)c`Mmckv6BW^lDbdgWVg_)dEGVXgaFtYnG1cVhv5fi^(KSj#bbo^R z_onWXU3T6aN|h{t82C=2|V2=^Qzl0CwjA;1`!4q$m7I zrc3Ip!`&{=j}HSBU^P3+H9H#lIZ`ad&}+*X%u-St2iC$a^oV71z3a)RPA6FnJ7-Mt z{9BfUqI=&hh!;Xn=ATl9t#ei+BYJ!$$6qx3JRGQk$-euQY%}4Sob*5)35R~72a&fx zsqUGWGS=~k|91^yM~EvuHi!Ik)U%+rlJplQdM1rGfsY?68B>gzMz95aGv-Bwa**9k zC?{Vn2S4e9F9bCXmFc5IU7c>izmW#_E^!!Sl*9#|tNoHYw*PorTV?P}78BNjg=rvolPKCU+FNo>69o!F5!#4+JN&0^cQk zOzAGvd;?b=i^IWS!PSvaM5-{<+HKMAYC?`7g-0_(;&GmA6%^`7_mZ%qM#hLKpl)}b zF8lo_i6|#_ovFlaF;QJggT2iQ0x#YNRE4ko%%HblDT^K;0xK9k6o%jWZ0~z2ftUs( zVk0oJ2-Hz#+oF0r26J?T{Ra5xA_06V3PKkdGG3)%gMyr^hmGMcD; zMsY_EfT??-OnB6PV?ewoS%lvCMwH~6lxGE308uod)RfM!StGMjH3D5hu=%xE+V{ly$$i6uIbo%Hmf&|u&yaqA2Zhb$r2r{!faw*Uoihymt z8K|?i-}F5RWmpI~_{yrY(*fiu=xO*Nh0WL)BErFWg{XnIhiTZUM}+P|rM5i-339?= z9@;R7uZ#IzBX{x*1de@B959N-IN;1lpiNd3d-0zKk$Bb^!tq+e0@Mp&24-%)Q(ZfP zym)W_(o@FF-scM#b|Hb=V+;Wjh214H3O;b;)&#gzO|9;QbwtF3gHU{n3J&A6>V7{jkNSI-RHt35DGDT z$BS2H0|d>#UvdN88-H&^I*)rHFgm@q5wOihldu{?=NePU=Q8)`eTwb>T}tr5OMGlRkjLO|Wr7=j3TJyU3)XeEL& zN**O0CN;_|%#Tl}&#zE6-(20WD%go(ap)wSzpJg+Qc@`q8->(2F|AzCI7M44LI#M5 z_&KRFN7g3j5B+oUF!hB)_$_O+A)AgiJKF zLyQeM75U+NGjx0UoPBrPTLP4Vs%=&W6TYN42b2e&g zVA9%&B~lkTV6`1sZ6TDL3$-HRd&24#9S%C+(TX$jA&-T2scujUd~wiT<{eMWAEeMq zhNoeFud!j||j4;w@Y zP87=$7@k20{Pkz0vW7a!gHzIHgcuQP3XKW}wn8U1=dKuh5&B6Bg5%CS}N>5T+)L!-9+9W3T z6(;Ma3@jjqvRO>QW1TW)Z7)M3X`H2tlBq<^Y;3$xR0#uJAF;mS*jI@klZ{kXgR1jv z(~%Jo4B_U~T4piBLdv=82wy9fy>l~gX?m(T<>U;mkV2<~Vr`@+R5*P?2CA{xwQjxB zKmmeBN|tU*O{;KYM=3TFR8P2=%s5@)7_?qA3Iu)aK$W`kr$u*PXuo~IV?Mv-&Q-i2 z(|Otpr8m{rdlSEjkccO=#wT~m_*P3vl8mb?2}|aSyX^8egp!@Oa?V@xf&{^N;pH%P z0tFPHfOQC1CwsULg}W!kltw<0v0aM95M9<2kW@%RD)1*h8&fcFe9;C5?h(R4(CeN@ zb5ClzDqj{bQ*lbNSKemVv>}2i%8r#2>j~Ux4f_C&4Ec937n|v3ogdwA_DKGrAtH(E zkF)yyh*}F?L$F<(E>0FthN_X9NtI=MI$ju>*$j_TB8I*I!A?7g0OeV+1}H?;84p0~ zg~&l6+qr#vFRHJvNYKK;|EAlIPXUG*Tm10QW z?Pr$-^F#>C_eksCoial+<-{;Ff!-TK0%Ou}P=t;3eSkq(depP{KP9_ih@oSoEsu%7 z&!mwfWT#BfQ();w-Hqk<%DQq)cpEuLJN^x|s6U*qV*hy=d=3KJ$#pL&a1+19^uv^F z`mu*$;@bgsEVx<++4Llkb`!et$CUJxDZmW89l%*mb7=kjYU~7qQ;LYvOpNY{V9ULr zJ|#T9$BL2|WNWSq7-}x^5eglWO*zUnAcpc@;~Cjc6%=nik?nr)miclk*3T>-HwsiE zfK4X{WB;cfYa6ZN7@KW;mf{3N!cxO9Yc29to|Py2ol-A>B65$nuEz5hEKbUk$|9Y$fSf zf;nT3q-PPV>=I%FQB?${H$5+o?#ryT(TX{CXaBJfi^sNm*FuMm9li!|susR=UBaz= zB#ER)CSHV50u`ghC#55zS{FCkJZemD6_;#56_hg61tTU8Hs>-~PQH=uq>k_Z)o3V05^q*_=JL?h&t6An_Izto18>2EOyH&m*u7h%ITA%xUk<0nFk2 z;xz~8u7GdvlMb64OA*g0Ggx%nrCFnul$E|IqHA;xB@;-wR z{eQzNN@1z01t^Hv{73C^T&d{ftcccv>z>3zF;akn8$U>P*IAwD(UPRQ{_-=#@r+l@Q-oULxy#Wc>c#I!3?D01a8)+vl4dby zGv<-XR?HO8NmSvwde=;n|4k<9^<|0d715ay8;u$dTQawfY8h?e9@ki}izD^?`&gf7 z92uBm@F&)2g%Od?CbF_I?`Sk!tw@j!UegMfM39nnevbuz4E@pkB=_h{dvXR7ntl9{Wc#(2;Bf6kH>RZuvF zJEtpa35`@V({epy1aiU=9f;(!`N8j*bCE8k_)5PM=Iy+Jz9%hRM;>dtTW!%nDxBHI z<|q97yW|I!?qRUuHa1Ym(tr(8q<~ zTYnlg40;8g8Z3N_>uvFzd?DhjO7q0i+1-ckeg)O~27Lbk(j_^9)fPo}u<9WrljP(j zk(3|jdU#8~yy8Qn{Jp;FEuDSyYHrfVLPD;v2siQ{TF#=%ItD>z z7NJP_zENk1<*DdYrg>7ic}|?gmt_4p#0DX73zdATw;as>UX6{9!7-Vcze@!dNS#=M zU|M&YBgjBk6sE9g7WJ)0-N{|7wtyWNI}$W4!(0CTM>j8B_&$`p{d8RST}6o*FGj^d z$BU#_7V*?Wh3uuJ`M-j@i(Nqn*aNDidz!lqz5wWMR#$8N+qsn@?dLCTlJ2gl&K_%V z8R=K_{y40U;hgRQQ5OaX(h*LeRM;>ozbvOj{H{Y;PIGg1Hh^LRJ&YL>Gs*arZ093m_*bO3uzq714_ud+8 zt~^ctr99?Ldymkl2Q}=}s8_V&=HZiy_y!=YU;&vTY87|@klVM_0iFr6+uSWVBag+2 z-mDE^l|T>R=ialU1~#U>f9?i#dd(3N8dbD{AAF!h3b-l1%v1NFn1TXwqxk(hV`oHX z9opA5(KfNqAE4e6`9P%nlwgfJE~6B{lrFN(MKm02lJdy5`SX5qJ1kX?N$~Riq}caE zep{2>{vgOe0LZTs6LSA-zJLR}CV}3Ap&bW%6iW(U6ft7EYmuT}53;S*+Kku`T9g>c z2Sd~(RuxEaH0`(QYys6rBnUbMn0)@bPihLn`KP*6VYNZ$p1G}Xxu8J%FKfI(Mt&G7 zNQ$R^n;|hG?Cf}MH~f70!(TZNL<$Ug-T_TFi(PvqkB3xq;fOZfo*GueSInR+6);6G zJt)=;`eR3i3g+dQ^qAPH(;?BEy2eShFR~E7(xM-wmNVk?EZk{srA=pNr`ditRP2k{v#}D13)w z1U|bO86EsgGFLAFNGt)|mb5i7F?l;>v7JPivgCc2UW{ege`tUX2N2c0#`K3PXxEnD zP+k!HK8-*LB`N8MLV(!&VDFyG)Yqz9_@4X$Tw%#)9bwjKh#-2D-6A~>+4 z++ze~;rE>m#oD2rpfdS~M^Q*~&ZUQcLoVHfpejdN=CB6^5MtO%I7s-{;j3GeFgQJ! zmw?`c{uxkz&suLifjxuuJPKKgJLSl`sTal$qF&vt3BJ5M+t7Xx=?yHMQHo4=S&Zst zh=uMAkR{0cIua;jTNQCAy)LJMdR?G^BZhZpgc~0OyS8db0Zr~4DMcZlQqL2d!(dQD zFBLBW#k<)jfIyMJo`GMnZZ${NABB?idXxBIS@(5s740eH z$}wyDdM7mRNp8^J)^g-MZyk2D5H_<>phOWujb18+JM+fhT?{$c-sn1u9#ty`b0Q68 zpA40u+H_jKU@^fEA`Hr`*h3fvlwmRS4K8=zRth*a5fwSo{UUMYb1*{UsJDSP-<($b z-c4Y>rD2?IG|a%_=`BC~=<(&il3v!$#|ovlL;pPQXD&);6Ivk_-FPEfVyzqAp?<+X zZ4P!Bd->r%ai>5;1ApXnF_$zsV%V4y z{YOQ&zLsj?YH59<+`{wyWhl8EcKU#2%q7A|5yD_U4FS(AR<|F|rY&~twdq4)KZHnv zx^3DN9C;SftUA3o7Q(Du!t%&bJkqgH1n~$<8

IID_IApplicationAssociationRegistration + public const string ApplicationAssociationRegistration = "4e530b0a-e611-4c77-a3ac-9031d022281b"; + /// IID_IConnectionPoint + public const string ConnectionPoint = "B196B286-BAB4-101A-B69C-00AA00341D07"; + /// IID_IConnectionPointContainer + public const string ConnectionPointContainer = "B196B284-BAB4-101A-B69C-00AA00341D07"; + public const string DragSourceHelper = "DE5BF786-477A-11D2-839D-00C04FD918D0"; + public const string DragSourceHelper2 = "83E07D0D-0C5F-4163-BF1A-60B274051E40"; + public const string DropTargetHelper = "4657278B-411B-11D2-839A-00C04FD918D0"; + /// IID_IEnumConnectionPoints + public const string EnumConnectionPoints = "B196B285-BAB4-101A-B69C-00AA00341D07"; + /// IID_IEnumConnections + public const string EnumConnections = "B196B287-BAB4-101A-B69C-00AA00341D07"; /// IID_IEnumIDList public const string EnumIdList = "000214F2-0000-0000-C000-000000000046"; /// IID_IEnumObjects public const string EnumObjects = "2c1c7e2e-2d0e-4059-831e-1e6f82335c2e"; + /// IID_IFileDialog + public const string FileDialog = "42f85136-db7e-439c-85f1-e4075d135fc8"; + /// IID_IFileDialogEvents + public const string FileDialogEvents = "973510DB-7D7F-452B-8975-74A85828D354"; + /// IID_IFileOpenDialog + public const string FileOpenDialog = "d57c7288-d4ad-4768-be02-9d969532d960"; + /// IID_IFileSaveDialog + public const string FileSaveDialog = "84bccd23-5fde-4cdb-aea4-af64b83d78ab"; + /// IID_IHTMLDocument + public const string HtmlDocument = "626FC520-A41E-11CF-A731-00A0C9082637"; /// IID_IHTMLDocument2 public const string HtmlDocument2 = "332C4425-26CB-11D0-B483-00C04FD90119"; /// IID_IModalWindow @@ -40,6 +59,28 @@ internal static partial class IID public const string TaskbarList2 = "602D4995-B13A-429b-A66E-1935E44F4317"; /// IID_IUnknown public const string Unknown = "00000000-0000-0000-C000-000000000046"; + /// IID_IWebBrowser2 + public const string WebBrowser2 = "D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"; + /// DIID_DWebBrowserEvents + public const string WebBrowserEvents = "EAB22AC2-30C1-11CF-A7EB-0000C05BAE0B"; + /// IID_DWebBrowserEvents2 + public const string WebBrowserEvents2 = "34A715A0-6587-11D0-924A-0020AFC7AC4D"; + /// IID_IWICBitmapDecoder + public const string WICBitmapDecoder = "9EDDE9E7-8DEE-47ea-99DF-E6FAF2ED44BF"; + /// IID_IWICBitmapFlipRotator + public const string WICBitmapFlipRotator = "5009834F-2D6A-41ce-9E1B-17C5AFF7A782"; + /// IID_IWICBitmapFrameDecode + public const string WICBitmapFrameDecode = "3B16811B-6A43-4ec9-A813-3D930C13B940"; + /// IID_IWICBitmap + public const string WICBitmap = "00000121-a8f2-4877-ba0a-fd2b6645fb94"; + /// IID_IWICBitmapSource + public const string WICBitmapSource = "00000120-a8f2-4877-ba0a-fd2b6645fb94"; + /// IID_IWICFormatConverter + public const string WICFormatConverter = "00000301-a8f2-4877-ba0a-fd2b6645fb94"; + /// IID_IWICImagingFactory + public const string WICImagingFactory = "ec5ec8a9-c395-4314-9c77-54d7a935ff70"; + /// IID_IWICStream + public const string WICStream = "135FF860-22B7-4ddf-B0F6-218F4F299A43"; #region Win7 IIDs @@ -61,6 +102,12 @@ internal static partial class IID #endregion } + internal static partial class SID + { + /// SID_SWebBrowserApp + public const string SWebBrowserApp = "0002DF05-0000-0000-C000-000000000046"; + } + internal static partial class CLSID { public static T CoCreateInstance(string clsid) @@ -68,6 +115,17 @@ public static T CoCreateInstance(string clsid) return (T)System.Activator.CreateInstance(System.Type.GetTypeFromCLSID(new System.Guid(clsid))); } + /// CLSID_ApplicationAssociationRegistration + /// IID_IApplicationAssociationRegistration + public const string ApplicationAssociationRegistration = "591209c7-767b-42b2-9fba-44ee4615f2c7"; + /// CLSID_DragDropHelper + public const string DragDropHelper = "4657278A-411B-11d2-839A-00C04FD918D0"; + /// CLSID_FileOpenDialog + /// IID_IFileOpenDialog + public const string FileOpenDialog = "DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7"; + /// CLSID_FileSaveDialog + /// IID_IFileSaveDialog + public const string FileSaveDialog = "C0B4E2F3-BA21-4773-8DBA-335EC946EB8B"; /// CLSID_TaskbarList /// IID_ITaskbarList public const string TaskbarList = "56FDF344-FD6D-11d0-958A-006097C9A090"; @@ -78,6 +136,9 @@ public static T CoCreateInstance(string clsid) /// IID_IShellLink public const string ShellLink = "00021401-0000-0000-C000-000000000046"; + /// CLSID_WICImagingFactory + public const string WICImagingFactory = "cacaf262-9370-4615-a13b-9f5539da4c0a"; + #region Win7 CLSIDs /// CLSID_DestinationList diff --git a/Microsoft.Windows.Shell/Standard/Debug.cs b/Microsoft.Windows.Shell/Standard/Debug.cs index 97d86f0..88ac5b1 100644 --- a/Microsoft.Windows.Shell/Standard/Debug.cs +++ b/Microsoft.Windows.Shell/Standard/Debug.cs @@ -1,7 +1,3 @@ -/**************************************************************************\ - Copyright Microsoft Corporation. All Rights Reserved. -\**************************************************************************/ - // Conditional to use more aggressive fail-fast behaviors when debugging. #define DEV_DEBUG @@ -20,13 +16,19 @@ namespace Standard /// A static class for verifying assumptions. internal static class Assert { + // Blend and VS don't like Debugger.Break being called on their design surfaces. Badness will happen. + //private static readonly bool _isNotAtRuntime = (bool)System.ComponentModel.DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(System.Windows.DependencyObject)).DefaultValue; + private static void _Break() { + //if (!_isNotAtRuntime) + { #if DEV_DEBUG - Debugger.Break(); + Debugger.Break(); #else - Debug.Assert(false); + Debug.Assert(false); #endif + } } /// A function signature for Assert.Evaluate. @@ -84,6 +86,29 @@ public static void AreEqual(T expected, T actual) } } + [Conditional("DEBUG")] + public static void LazyAreEqual(Func expectedResult, Func actualResult) + { + Assert.IsNotNull(expectedResult); + Assert.IsNotNull(actualResult); + + T actual = actualResult(); + T expected = expectedResult(); + + if (null == expected) + { + // Two nulls are considered equal, regardless of type semantics. + if (null != actual && !actual.Equals(expected)) + { + _Break(); + } + } + else if (!expected.Equals(actual)) + { + _Break(); + } + } + /// /// Verifies that two generic type data are not equal. The assertion fails if they are. /// @@ -248,6 +273,15 @@ public static void IsTrue(bool condition) } } + [Conditional("DEBUG")] + public static void IsTrue(Predicate predicate, T arg) + { + if (!predicate(arg)) + { + _Break(); + } + } + /// /// Verifies that the specified condition is true. The assertion fails if it is not. /// @@ -360,14 +394,5 @@ public static void NullableIsNull(T? value) where T : struct _Break(); } } - - [Conditional("DEBUG")] - public static void IsNotOnMainThread() - { - if (System.Windows.Application.Current.Dispatcher.CheckAccess()) - { - _Break(); - } - } } } diff --git a/Microsoft.Windows.Shell/Standard/DoubleUtil.cs b/Microsoft.Windows.Shell/Standard/DoubleUtil.cs index 49d1c26..47ec6ef 100644 --- a/Microsoft.Windows.Shell/Standard/DoubleUtil.cs +++ b/Microsoft.Windows.Shell/Standard/DoubleUtil.cs @@ -2,7 +2,6 @@ namespace Standard { using System; - using System.Diagnostics.CodeAnalysis; /// /// DoubleUtil uses fixed eps to provide fuzzy comparison functionality for doubles. @@ -27,7 +26,6 @@ internal static class DoubleUtilities /// The first double to compare. /// The second double to compare. /// The result of the AreClose comparision. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static bool AreClose(double value1, double value2) { if (value1 == value2) @@ -39,6 +37,11 @@ public static bool AreClose(double value1, double value2) return (delta < Epsilon) && (delta > -Epsilon); } + public static bool IsCloseTo(this double value1, double value2) + { + return AreClose(value1, value2); + } + /// /// LessThan returns whether or not the first double is less than the second double. /// That is, whether or not the first is strictly less than *and* not within epsilon of @@ -50,8 +53,7 @@ public static bool AreClose(double value1, double value2) /// The first double to compare. /// The second double to compare. /// The result of the LessThan comparision. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool LessThan(double value1, double value2) + public static bool IsStrictlyLessThan(this double value1, double value2) { return (value1 < value2) && !AreClose(value1, value2); } @@ -67,8 +69,7 @@ public static bool LessThan(double value1, double value2) /// The first double to compare. /// The second double to compare. /// The result of the GreaterThan comparision. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool GreaterThan(double value1, double value2) + public static bool IsStrictlyGreaterThan(this double value1, double value2) { return (value1 > value2) && !AreClose(value1, value2); } @@ -84,8 +85,7 @@ public static bool GreaterThan(double value1, double value2) /// The first double to compare. /// The second double to compare. /// The result of the LessThanOrClose comparision. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool LessThanOrClose(double value1, double value2) + public static bool IsLessThanOrCloseTo(this double value1, double value2) { return (value1 < value2) || AreClose(value1, value2); } @@ -101,8 +101,7 @@ public static bool LessThanOrClose(double value1, double value2) /// The first double to compare. /// The second double to compare. /// The result of the GreaterThanOrClose comparision. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool GreaterThanOrClose(double value1, double value2) + public static bool IsGreaterThanOrCloseTo(this double value1, double value2) { return (value1 > value2) || AreClose(value1, value2); } @@ -112,8 +111,7 @@ public static bool GreaterThanOrClose(double value1, double value2) /// /// The value to test. /// Whether or not the value is a finite number. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool IsFinite(double value) + public static bool IsFinite(this double value) { return !double.IsNaN(value) && !double.IsInfinity(value); } @@ -123,10 +121,20 @@ public static bool IsFinite(double value) /// /// The value to test. /// Whether or not the value is a valid size value. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool IsValidSize(double value) + public static bool IsValidSize(this double value) + { + return IsFinite(value) && value.IsGreaterThanOrCloseTo(0); + } + + public static bool IsFiniteAndNonNegative(this double d) { - return IsFinite(value) && GreaterThanOrClose(value, 0); + if (double.IsNaN(d) || double.IsInfinity(d) || d < 0) + { + return false; + } + + return true; } + } } diff --git a/Microsoft.Windows.Shell/Standard/Enumerable2.cs b/Microsoft.Windows.Shell/Standard/Enumerable2.cs new file mode 100644 index 0000000..c046baf --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/Enumerable2.cs @@ -0,0 +1,288 @@ + +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Text; + + /// + /// Further LINQ extensions + /// + internal static class Enumerable2 + { + // Unnecessary in .Net 4. + //public static IEnumerable Zip(this IEnumerable first, IEnumerable second, Func func) + //{ + // Verify.IsNotNull(first, "first"); + // Verify.IsNotNull(second, "second"); + + // return _Zip(first, second, func); + //} + + //private static IEnumerable _Zip(this IEnumerable first, IEnumerable second, Func func) + //{ + // IEnumerator ie1 = first.GetEnumerator(); + // IEnumerator ie2 = second.GetEnumerator(); + // while (ie1.MoveNext() && ie2.MoveNext()) + // { + // yield return func(ie1.Current, ie2.Current); + // } + //} + + /// Partition a collection into two, based on whether the items match a predicate. + /// The type of the enumeration. + /// The original collection to split. + /// The condition to use for the split. + /// A collection of all items in the original collection that do not satisfy the condition. + /// A collection of all items in the original collection that satisfy the condition. + /// Unlike most extension methods of this nature, this does not perform the operation lazily. + public static IEnumerable SplitWhere(this IEnumerable collection, Predicate condition, out IEnumerable rest) + { + Verify.IsNotNull(collection, "collection"); + Verify.IsNotNull(condition, "condition"); + + var passList = new List(); + var failList = new List(); + + foreach (T t in collection) + { + if (condition(t)) + { + passList.Add(t); + } + else + { + failList.Add(t); + } + } + + rest = failList; + return passList; + } + + /// + /// Limit an enumeration to be constrained to a subset after a given index. + /// + /// The type of items being enumerated. + /// The collection to be enumerated. + /// The index (inclusive) of the first item to be returned. + /// + public static IEnumerable Sublist(this IEnumerable enumerable, int startIndex) + { + return Sublist(enumerable, startIndex, null); + } + + /// + /// Limit an enumeration to be within a set of indices. + /// + /// The type of items being enumerated. + /// The collection to be enumerated. + /// The index (inclusive) of the first item to be returned. + /// + /// The index (exclusive) of the last item to be returned. + /// If this is null then the full collection after startIndex is returned. + /// If this is greater than the count of the collection after startIndex, then the full collection after startIndex is returned. + /// + /// + public static IEnumerable Sublist(this IEnumerable enumerable, int startIndex, int? endIndex) + { + Verify.IsNotNull(enumerable, "enumerable"); + Verify.BoundedInteger(0, startIndex, int.MaxValue, "startIndex"); + if (endIndex != null) + { + Verify.BoundedInteger(startIndex, endIndex.Value, int.MaxValue, "endIndex"); + } + + // If this supports indexing then just use that. + var list = enumerable as IList; + if (list != null) + { + return _SublistList(list, startIndex, endIndex); + } + + return _SublistEnum(enumerable, startIndex, endIndex); + } + + private static IEnumerable _SublistEnum(this IEnumerable enumerable, int startIndex, int? endIndex) + { + int currentIndex = 0; + IEnumerator enumerator = enumerable.GetEnumerator(); + while (currentIndex < startIndex && enumerator.MoveNext()) + { + ++currentIndex; + } + + int trueEndIndex = endIndex ?? int.MaxValue; + + while (currentIndex < trueEndIndex && enumerator.MoveNext()) + { + yield return enumerator.Current; + ++currentIndex; + } + } + + private static IEnumerable _SublistList(this IList list, int startIndex, int? endIndex) + { + int trueEndIndex = Math.Min(list.Count, endIndex ?? int.MaxValue); + for (int i = startIndex; i < trueEndIndex; ++i) + { + yield return list[i]; + } + } + + public static bool AreSorted(this IEnumerable enumerable) + { + return _AreSorted(enumerable); + } + + public static bool AreSorted(this IEnumerable enumerable, Comparison comparison) + { + Verify.IsNotNull(enumerable, "enumerable"); + if (comparison == null) + { + if (typeof(T).GetInterface(typeof(IComparable).Name) == null) + { + // Not comparable for a sort. + return true; + } + + return _AreSorted(enumerable); + } + + return _AreSorted(enumerable, comparison); + } + + private static bool _AreSorted(IEnumerable enumerable, Comparison comparison) + { + T last = default(T); + bool isFirst = true; + foreach (var item in enumerable) + { + if (isFirst) + { + last = item; + isFirst = false; + } + else + { + if (comparison(last, item) > 0) + { + return false; + } + last = item; + } + } + + return true; + } + + private static bool _AreSorted(IEnumerable enumerable) + { + IComparable last = null; + bool isFirstNonNull = true; + foreach (var item in enumerable) + { + if (isFirstNonNull) + { + last = (IComparable)item; + if (last != null) + { + isFirstNonNull = false; + } + } + else + { + if (last.CompareTo(item) > 0) + { + return false; + } + last = (IComparable)item; + if (last == null) + { + return false; + } + } + } + + return true; + } + + public static void AddRange(this ICollection collection, params T[] items) + { + Verify.IsNotNull(collection, "collection"); + _AddRange(collection, items); + } + + public static void AddRange(this ICollection collection, IEnumerable items) + { + Verify.IsNotNull(collection, "collection"); + _AddRange(collection, items); + } + + private static void _AddRange(ICollection collection, IEnumerable items) + { + if (items == null) + { + return; + } + + foreach (var item in items) + { + collection.Add(item); + } + } + + public static IEnumerable Reverse(this IList list) + { + Verify.IsNotNull(list, "list"); + return _Reverse(list); + } + + private static IEnumerable _Reverse(IList list) + { + for (int i = list.Count - 1; i >= 0; --i) + { + yield return list[i]; + } + } + + public static IList Shuffle(this IList list) + { + var r = new Random(); + return Shuffle(list, () => r.Next(list.Count)); + } + + public static IList Shuffle(this IList list, Func numberGenerator) + { + Verify.IsNotNull(list, "list"); + Verify.IsNotNull(numberGenerator, "numberGenerator"); + + var swapIndices = new int[list.Count]; + for (int i = 0; i < list.Count; ++i) + { + int j = numberGenerator(); + if (j < 0 || j >= list.Count) + { + throw new ArgumentException("The number generator function generated a number outside the valid range."); + } + swapIndices[i] = j; + } + return _Shuffle(list, swapIndices); + } + + private static IList _Shuffle(IList list, int[] swapIndices) + { + Assert.AreEqual(list.Count, swapIndices.Length); + for (int i = swapIndices.Length; i > 1; --i) + { + int k = swapIndices[i-1]; + T temp = list[k]; + list[k] = list[i-1]; + list[i-1] = temp; + } + + return list; + } + } +} diff --git a/Microsoft.Windows.Shell/Standard/ErrorCodes.cs b/Microsoft.Windows.Shell/Standard/ErrorCodes.cs index 5adb444..90ca9c2 100644 --- a/Microsoft.Windows.Shell/Standard/ErrorCodes.cs +++ b/Microsoft.Windows.Shell/Standard/ErrorCodes.cs @@ -1,7 +1,3 @@ -/**************************************************************************\ - Copyright Microsoft Corporation. All Rights Reserved. -\**************************************************************************/ - namespace Standard { using System; @@ -77,6 +73,9 @@ internal struct Win32Error /// The operation was canceled by the user. [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] public static readonly Win32Error ERROR_CANCELLED = new Win32Error(1223); + /// Cannot find window class. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_CANNOT_FIND_WND_CLASS = new Win32Error(1407); /// The window class was already registered. [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] public static readonly Win32Error ERROR_CLASS_ALREADY_EXISTS = new Win32Error(1410); @@ -118,7 +117,6 @@ public HRESULT ToHRESULT() /// Performs the equivalent of Win32's GetLastError() /// A Win32Error instance with the result of the native GetLastError - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] public static Win32Error GetLastError() { return new Win32Error(Marshal.GetLastWin32Error()); @@ -227,6 +225,19 @@ internal struct HRESULT /// STG_E_INVALIDFUNCTION [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] public static readonly HRESULT STG_E_INVALIDFUNCTION = new HRESULT(0x80030001); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT OLE_E_ADVISENOTSUPPORTED = new HRESULT(0x80040003); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DV_E_FORMATETC = new HRESULT(0x80040064); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DV_E_TYMED = new HRESULT(0x80040069); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DV_E_CLIPFORMAT = new HRESULT(0x8004006A); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DV_E_DVASPECT = new HRESULT(0x8004006B); + /// REGDB_E_CLASSNOTREG [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] public static readonly HRESULT REGDB_E_CLASSNOTREG = new HRESULT(0x80040154); @@ -257,7 +268,6 @@ internal struct HRESULT [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] public static readonly HRESULT E_INVALIDARG = new HRESULT(0x80070057); /// INTSAFE_E_ARITHMETIC_OVERFLOW - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] public static readonly HRESULT INTSAFE_E_ARITHMETIC_OVERFLOW = new HRESULT(0x80070216); /// COR_E_OBJECTDISPOSED [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] @@ -269,6 +279,103 @@ internal struct HRESULT [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] public static readonly HRESULT WC_E_SYNTAX = new HRESULT(0xC00CEE2D); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_GENERIC_ERROR = E_FAIL; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_INVALIDPARAMETER = E_INVALIDARG; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_OUTOFMEMORY = E_OUTOFMEMORY; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_NOTIMPLEMENTED = E_NOTIMPL; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_ABORTED = E_ABORT; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_ACCESSDENIED = E_ACCESSDENIED; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_VALUEOVERFLOW = INTSAFE_E_ARITHMETIC_OVERFLOW; + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_WRONGSTATE = Make(true, Facility.WinCodec, 0x2f04); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_VALUEOUTOFRANGE = Make(true, Facility.WinCodec, 0x2f05); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_UNKNOWNIMAGEFORMAT = Make(true, Facility.WinCodec, 0x2f07); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_UNSUPPORTEDVERSION = Make(true, Facility.WinCodec, 0x2f0B); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_NOTINITIALIZED = Make(true, Facility.WinCodec, 0x2f0C); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_ALREADYLOCKED = Make(true, Facility.WinCodec, 0x2f0D); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_PROPERTYNOTFOUND = Make(true, Facility.WinCodec, 0x2f40); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_PROPERTYNOTSUPPORTED = Make(true, Facility.WinCodec, 0x2f41); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_PROPERTYSIZE = Make(true, Facility.WinCodec, 0x2f42); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_CODECPRESENT = Make(true, Facility.WinCodec, 0x2f43); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_CODECNOTHUMBNAIL = Make(true, Facility.WinCodec, 0x2f44); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_PALETTEUNAVAILABLE = Make(true, Facility.WinCodec, 0x2f45); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_CODECTOOMANYSCANLINES = Make(true, Facility.WinCodec, 0x2f46); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_INTERNALERROR = Make(true, Facility.WinCodec, 0x2f48); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_SOURCERECTDOESNOTMATCHDIMENSIONS = Make(true, Facility.WinCodec, 0x2f49); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_COMPONENTNOTFOUND = Make(true, Facility.WinCodec, 0x2f50); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_IMAGESIZEOUTOFRANGE = Make(true, Facility.WinCodec, 0x2f51); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_TOOMUCHMETADATA = Make(true, Facility.WinCodec, 0x2f52); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_BADIMAGE = Make(true, Facility.WinCodec, 0x2f60); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_BADHEADER = Make(true, Facility.WinCodec, 0x2f61); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_FRAMEMISSING = Make(true, Facility.WinCodec, 0x2f62); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_BADMETADATAHEADER = Make(true, Facility.WinCodec, 0x2f63); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_BADSTREAMDATA = Make(true, Facility.WinCodec, 0x2f70); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_STREAMWRITE = Make(true, Facility.WinCodec, 0x2f71); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_STREAMREAD = Make(true, Facility.WinCodec, 0x2f72); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_STREAMNOTAVAILABLE = Make(true, Facility.WinCodec, 0x2f73); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT = Make(true, Facility.WinCodec, 0x2f80); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_UNSUPPORTEDOPERATION = Make(true, Facility.WinCodec, 0x2f81); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_INVALIDREGISTRATION = Make(true, Facility.WinCodec, 0x2f8A); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_COMPONENTINITIALIZEFAILURE = Make(true, Facility.WinCodec, 0x2f8B); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_INSUFFICIENTBUFFER = Make(true, Facility.WinCodec, 0x2f8C); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_DUPLICATEMETADATAPRESENT = Make(true, Facility.WinCodec, 0x2f8D); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE = Make(true, Facility.WinCodec, 0x2f8E); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_UNEXPECTEDSIZE = Make(true, Facility.WinCodec, 0x2f8F); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_INVALIDQUERYREQUEST = Make(true, Facility.WinCodec, 0x2f90); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_UNEXPECTEDMETADATATYPE = Make(true, Facility.WinCodec, 0x2f91); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_REQUESTONLYVALIDATMETADATAROOT = Make(true, Facility.WinCodec, 0x2f92); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_INVALIDQUERYCHARACTER = Make(true, Facility.WinCodec, 0x2f93); + /// /// Create an HRESULT from an integer value. /// @@ -278,6 +385,22 @@ public HRESULT(uint i) _value = i; } + public HRESULT(int i) + { + _value = unchecked((uint)i); + } + + /// + /// Convert an HRESULT to an int. Used for COM interface declarations out of our control. + /// + public static explicit operator int(HRESULT hr) + { + unchecked + { + return (int)hr._value; + } + } + public static HRESULT Make(bool severe, Facility facility, int code) { //#define MAKE_HRESULT(sev,fac,code) \ diff --git a/Microsoft.Windows.Shell/Standard/FileWalker.cs b/Microsoft.Windows.Shell/Standard/FileWalker.cs new file mode 100644 index 0000000..a703fc8 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/FileWalker.cs @@ -0,0 +1,114 @@ +// Cribbed heavily from MSDN magazine's .Net Matters (12/2005) by Stephen Toub. +// http://msdn.microsoft.com/msdnmag/issues/05/12/NETMatters/ +// This started off an excellent implementation, I'd rather not unnecessarily rewrite it. +// Some small stylistic changes were made to make it more consistent with the rest of the code +// and also changed the recurse criteria. + +namespace Standard +{ + using System.Collections.Generic; + using System.IO; + using System.Security.Permissions; + + internal class FileWalker + { + public static IEnumerable GetFiles(DirectoryInfo startDirectory, string pattern, bool recurse) + { + // We suppressed this demand for each p/invoke call, so demand it upfront once + new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); + + // Validate parameters + Verify.IsNotNull(startDirectory, "startDirectory"); + Verify.IsNeitherNullNorEmpty(pattern, "pattern"); + + // Setup + var findData = new WIN32_FIND_DATAW(); + var directories = new Stack(); + directories.Push(startDirectory); + + // Process each directory. Only push new directories if we're recursing. + ErrorModes origErrorMode = NativeMethods.SetErrorMode(ErrorModes.FailCriticalErrors); + try + { + while (directories.Count > 0) + { + // Get the name of the next directory and the corresponding search pattern + DirectoryInfo dir = directories.Pop(); + string dirPath = dir.FullName.Trim(); + if (dirPath.Length == 0) + { + continue; + } + char lastChar = dirPath[dirPath.Length - 1]; + if (lastChar != Path.DirectorySeparatorChar && lastChar != Path.AltDirectorySeparatorChar) + { + dirPath += Path.DirectorySeparatorChar; + } + + // Process all files in that directory + using (SafeFindHandle handle = NativeMethods.FindFirstFileW(dirPath + pattern, findData)) + { + Win32Error error; + if (handle.IsInvalid) + { + error = Win32Error.GetLastError(); + if (error == Win32Error.ERROR_ACCESS_DENIED || error == Win32Error.ERROR_FILE_NOT_FOUND) + { + continue; + } + Assert.AreNotEqual(Win32Error.ERROR_SUCCESS, error); + ((HRESULT)error).ThrowIfFailed(); + } + + do + { + if (!Utility.IsFlagSet((int)findData.dwFileAttributes, (int)FileAttributes.Directory)) + { + yield return new FileInfo(dirPath + findData.cFileName); + } + } + while (NativeMethods.FindNextFileW(handle, findData)); + error = Win32Error.GetLastError(); + if (error != Win32Error.ERROR_NO_MORE_FILES) + { + ((HRESULT)error).ThrowIfFailed(); + } + } + + // Push subdirectories onto the stack if we are recursing. + if (recurse) + { + // In a volatile system we can't count on all the file information staying valid. + // Catch reasonable exceptions and move on. + try + { + foreach (DirectoryInfo childDir in dir.GetDirectories()) + { + try + { + FileAttributes attrib = File.GetAttributes(childDir.FullName); + // If it's not a hidden, system folder, nor a reparse point + if (!Utility.IsFlagSet((int)attrib, (int)(FileAttributes.Hidden | FileAttributes.System | FileAttributes.ReparsePoint))) + { + directories.Push(childDir); + } + } + catch (FileNotFoundException) + { + // Shouldn't see this. + Assert.Fail(); + } + catch (DirectoryNotFoundException) { } + } + } + catch (DirectoryNotFoundException) { } + } + } + } + finally + { + NativeMethods.SetErrorMode(origErrorMode); + } + } + } +} diff --git a/Microsoft.Windows.Shell/Standard/MergeableCollection.cs b/Microsoft.Windows.Shell/Standard/MergeableCollection.cs new file mode 100644 index 0000000..3139779 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/MergeableCollection.cs @@ -0,0 +1,628 @@ +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Collections.Specialized; + using System.ComponentModel; + using System.Linq; + + internal interface IMergeable : IEquatable where TKey : IEquatable + { + /// Immutable foreign key for the object + TKey FKID { get; } + + /// Merge the properties of another object of like type with this one. + /// The object to merge + void Merge(TItem other); + } + + internal class MergeableCollection : IList, INotifyCollectionChanged where TItem : class where TKey : IEquatable + { + private class _Comparer : IComparer + { + private bool _dontCompare = false; + private Comparison _defaultComparison; + private Comparison _customComparison; + private Comparison _trueComparison; + + public _Comparer() + { + if (Utility.IsInterfaceImplemented(typeof(TItem), typeof(IComparable))) + { + _defaultComparison = (left, right) => + { + if (object.ReferenceEquals(left, right)) + { + return 0; + } + + var comparableLeft = (IComparable)left; + if (comparableLeft == null) + { + return -1; + } + + return comparableLeft.CompareTo(right); + }; + } + + _trueComparison = _defaultComparison; + } + + public Comparison Comparison + { + get { return _trueComparison; } + set + { + Assert.IsFalse(_dontCompare); + if (!_dontCompare) + { + _customComparison = value; + _trueComparison = _customComparison ?? _defaultComparison; + } + } + } + + public bool CanCompare + { + get { return _trueComparison != null; } + } + + public void StopComparisons() + { + _trueComparison = null; + _dontCompare = true; + } + + public int Compare(TItem x, TItem y) + { + Assert.IsTrue(CanCompare); + return _trueComparison(x, y); + } + + public IEnumerable OrderedList(IEnumerable original) + { + Assert.IsNotNull(original); + + if (!CanCompare) + { + return original; + } + + return original.OrderBy(x => x, this); + } + } + + private readonly bool _areItemsMergable; + private readonly bool _areItemsNotifiable; + private readonly ObservableCollection _items; + private readonly Dictionary _fkidLookup; + private _Comparer _itemComparer = new _Comparer(); + + // Block reentrancy that would cause the collection to be reordered. + // If while we're doing a merge we get change notifications that the item has changed, ignore it. + private IMergeable _suspendNotificationsForMergeableObject; + + public object SyncRoot { get; private set; } + + public MergeableCollection() + : this(null, true) + {} + + public MergeableCollection(bool sort) + : this(null, sort) + {} + + public MergeableCollection(IEnumerable dataObjects) + : this(dataObjects, true) + {} + + public MergeableCollection(IEnumerable dataObjects, bool sort) + { + SyncRoot = new object(); + + if (!sort) + { + _itemComparer.StopComparisons(); + } + + // We don't really want to constrain based on the type being IMergeable or comparable + // This is a very specific check. We want to ensure that this type supports IMergeable, not IMergeable + _areItemsMergable = Utility.IsInterfaceImplemented(typeof(TItem), typeof(IMergeable)); + _areItemsNotifiable = Utility.IsInterfaceImplemented(typeof(TItem), typeof(INotifyPropertyChanged)); + + if (dataObjects == null) + { + _items = new ObservableCollection(); + } + else + { + _items = new ObservableCollection(_itemComparer.OrderedList(dataObjects)); + if (_areItemsNotifiable) + { + lock (SyncRoot) + { + foreach (INotifyPropertyChanged item in _items) + { + item.PropertyChanged += _OnItemChanged; + } + } + } + } + + if (_areItemsMergable) + { + _fkidLookup = new Dictionary(); + foreach (IMergeable item in _items) + { + //Assert.IsNotNull(item.FKID); + _fkidLookup.Add(item.FKID, (TItem)item); + } + } + } + + public Comparison CustomComparison + { + get { return _itemComparer.Comparison; } + set + { + if (_itemComparer.Comparison != value) + { + _itemComparer.Comparison = value; + RefreshSort(); + } + } + } + + public void RefreshSort() + { + if (_itemComparer.CanCompare) + { + lock (SyncRoot) + { + if (!_AreItemsSortedUpToIndex(_items.Count)) + { + var copyList = new List(_items); + // Clear the list first so we don't bubble-sort just to reorder. + _Merge(null, false, null); + _Merge(copyList, false, null); + } + } + } + } + + /// + /// Merges data from another collection. + /// + /// The data object collection that contains new data. + /// + /// If true, combine the new collection with existing content, otherwise replace the list. + /// + public void Merge(IEnumerable newCollection, bool add) + { + _Merge(newCollection, add, null); + } + + public void Merge(IEnumerable newCollection, bool add, int? maxCount) + { + _Merge(newCollection, add, maxCount); + } + + private void _Merge(IEnumerable newCollection, bool add, int? maxCount) + { + // These should never get out of sync. + Assert.Implies(_areItemsMergable, () => _items.Count == _fkidLookup.Count); + + lock (SyncRoot) + { + // Go-go partial template specialization! + if (_areItemsMergable) + { + _RichMerge(newCollection, add, maxCount); + } + else + { + _SimpleMerge(newCollection, add, maxCount); + } + } + } + + public TItem FindFKID(TKey id) + { + lock (SyncRoot) + { + if (!_areItemsMergable) + { + throw new InvalidOperationException("This can only be used on collections with Mergeable items."); + } + + TItem ret; + if (_fkidLookup.TryGetValue(id, out ret)) + { + return ret; + } + return null; + } + } + + private int _FindIndex(int startIndex, Predicate> match) + { + int count = Count - startIndex; + for (int i = startIndex; i < startIndex + count; ++i) + { + if (match((IMergeable)this[i])) + { + return i; + } + } + + return -1; + } + + private bool _VerifyInsertionPoint(int index) + { + lock (SyncRoot) + { + if (_itemComparer.Comparison == null) + { + // We don't have any way of determining a correct order. Whatever we have is fine. + return true; + } + + // Make sure that the item at index is not less than the one before it + // and not greater than the one after it. + // If this fails, we need to update the list. + + if (index != 0) + { + if (_itemComparer.Compare(_items[index - 1], _items[index]) > 0) + { + return false; + } + } + + if (index < _items.Count - 1) + { + if (_itemComparer.Compare(_items[index], _items[index+1]) > 0) + { + return false; + } + } + + return true; + } + } + + private int _FindInsertionPoint(TItem item) + { + Assert.IsNotNull(item); + + if (_itemComparer.Comparison != null) + { + for (int i = 0; i < _items.Count; ++i) + { + if (_itemComparer.Compare(item, _items[i]) <= 0) + { + return i; + } + } + } + + return -1; + } + + /// + /// Safe version of Clear that removes references to this from the items being removed. + /// + private void _MergeClear() + { + if (_areItemsNotifiable) + { + foreach (var item in _items) + { + _SafeRemoveNotifyAndLookup(item); + } + } + _items.Clear(); + + if (_fkidLookup != null) + { + _fkidLookup.Clear(); + } + } + + private void _RichMerge(IEnumerable newCollection, bool additive, int? maxCount) + { + lock (SyncRoot) + { + if (newCollection == null) + { + _MergeClear(); + return; + } + + if (!additive) + { + int index = -1; + foreach (TItem newItem in _itemComparer.OrderedList(newCollection).Sublist(0, maxCount)) + { + var mergeableItem = newItem as IMergeable; + + ++index; + //Assert.IsNotNull(mergeableItem.FKID); + int oldIndex = _FindIndex(index, p => mergeableItem.FKID.Equals(p.FKID)); + if (oldIndex == -1) + { + _items.Insert(index, newItem); + _SafeAddNotifyAndLookup(newItem); + continue; + } + else if (oldIndex != index) + { + _items.Move(oldIndex, index); + } + + _suspendNotificationsForMergeableObject = (IMergeable)this[index]; + _suspendNotificationsForMergeableObject.Merge(newItem); + _suspendNotificationsForMergeableObject = null; + + Assert.IsTrue(unused => _AreItemsSortedUpToIndex(index), null); + } + + if (index != -1) + { + ++index; + _RemoveRange(index); + } + else + { + _MergeClear(); + } + } + else + { + foreach (var item in newCollection) + { + var mergableItem = (IMergeable)item; + + int index = _FindIndex(0, p => p.FKID.Equals(mergableItem.FKID)); + if (index == -1) + { + index = _FindInsertionPoint(item); + + if (-1 == index) + { + _items.Add(item); + } + else + { + _items.Insert(index, item); + } + _SafeAddNotifyAndLookup(item); + } + else + { + _suspendNotificationsForMergeableObject = (IMergeable)this[index]; + _suspendNotificationsForMergeableObject.Merge(item); + _suspendNotificationsForMergeableObject = null; + } + } + } + + if (maxCount != null && _items.Count > maxCount.Value) + { + _RemoveRange(maxCount.Value); + } + + //Assert.Implies(_areItemsComparable || _customComparison != null, () => _items.AreSorted(_customComparison)); + } + } + + private bool _AreItemsSortedUpToIndex(int index) + { + if (_itemComparer.CanCompare) + { + for (int i = 1; i < index; ++i) + { + if (_itemComparer.Comparison(_items[i - 1], _items[i]) > 0) + { + return false; + } + } + } + return true; + } + + private void _RemoveRange(int index) + { + while (index < _items.Count) + { + _SafeRemoveNotifyAndLookup(_items[index]); + _items.RemoveAt(index); + } + } + + private void _SimpleMerge(IEnumerable newCollection, bool add, int? maxCount) + { + lock (SyncRoot) + { + if (!add) + { + // This just replaces the entire collection. + _MergeClear(); + + if (newCollection == null) + { + return; + } + + foreach (TItem item in _itemComparer.OrderedList(newCollection).Sublist(0, maxCount)) + { + _items.Add(item); + _SafeAddNotifyAndLookup(item); + } + } + else + { + foreach (var item in newCollection) + { + if (!_items.Contains(item)) + { + int index = _FindInsertionPoint(item); + + if (-1 == index) + { + _items.Add(item); + } + else + { + _items.Insert(index, item); + } + _SafeAddNotifyAndLookup(item); + } + } + + if (maxCount != null && _items.Count > maxCount.Value) + { + _RemoveRange(maxCount.Value); + } + } + //Assert.Implies(_areItemsComparable || _customComparison != null, () => _items.AreSorted(_customComparison)); + } + } + + private void _SafeAddNotifyAndLookup(TItem item) + { + Assert.IsNotNull(item); + if (_areItemsNotifiable) + { + ((INotifyPropertyChanged)item).PropertyChanged += _OnItemChanged; + } + + if (_areItemsMergable) + { + //Assert.IsNotNull(((IMergeable)item).FKID); + _fkidLookup.Add(((IMergeable)item).FKID, item); + } + } + + private void _SafeRemoveNotifyAndLookup(TItem item) + { + Assert.IsNotNull(item); + if (_areItemsNotifiable) + { + ((INotifyPropertyChanged)item).PropertyChanged -= _OnItemChanged; + } + + if (_areItemsMergable) + { + //Assert.IsNotNull(((IMergeable)item).FKID); + _fkidLookup.Remove(((IMergeable)item).FKID); + } + } + + private void _OnItemChanged(object sender, PropertyChangedEventArgs e) + { + var item = sender as TItem; + // If we're doing a merge of this item then we expect that properties may change. + // Don't reorder because of this. We expect the merge is putting the item in the right place. + if (item != null && item != _suspendNotificationsForMergeableObject) + { + lock (SyncRoot) + { + int currentIndex = _items.IndexOf(item); + if (-1 != currentIndex) + { + if (!_VerifyInsertionPoint(currentIndex)) + { + _items.RemoveAt(currentIndex); + int newIndex = _FindInsertionPoint(item); + if (newIndex == -1 || newIndex == _items.Count) + { + _items.Add(item); + } + else + { + _items.Insert(newIndex, item); + } + } + } + + //Assert.IsTrue(_items.AreSorted(_customComparison)); + } + } + } + + #region IList Members + + public int IndexOf(TItem item) { return _items.IndexOf(item); } + + public TItem this[int index] + { + get { return _items[index]; } + set { throw new NotSupportedException(); } + } + + #region Unsupported Mutable IList Members + void IList.Insert(int index, TItem item) { throw new NotSupportedException(); } + void IList.RemoveAt(int index) { throw new NotSupportedException(); } + #endregion + + #endregion + + #region ICollection Members + + public bool Contains(TItem item) { return _items.Contains(item); } + public void CopyTo(TItem[] array, int arrayIndex) { _items.CopyTo(array, arrayIndex); } + public int Count { get { return _items.Count; } } + public bool IsReadOnly { get { return true; } } + + public void Clear() { Merge(null, false); } + + public void Add(TItem item) + { + Verify.IsNotNull(item, "item"); + Merge(new [] { item }, true); + } + + public bool Remove(TItem item) + { + Verify.IsNotNull(item, "item"); + + lock (SyncRoot) + { + if (_items.Remove(item)) + { + _SafeRemoveNotifyAndLookup(item); + return true; + } + return false; + } + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() { return _items.GetEnumerator(); } + + #endregion + + #region IEnumerable Members + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } + + #endregion + + #region INotifyCollectionChanged Members + + public event NotifyCollectionChangedEventHandler CollectionChanged + { + add { _items.CollectionChanged += value; } + remove { _items.CollectionChanged -= value; } + } + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/Standard/MessageWindow.cs b/Microsoft.Windows.Shell/Standard/MessageWindow.cs index a0eac02..6551359 100644 --- a/Microsoft.Windows.Shell/Standard/MessageWindow.cs +++ b/Microsoft.Windows.Shell/Standard/MessageWindow.cs @@ -1,15 +1,11 @@ -/**************************************************************************\ - Copyright Microsoft Corporation. All Rights Reserved. -\**************************************************************************/ - -namespace Standard +namespace Standard { using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using System.Windows; using System.Windows.Threading; - using System.Collections.Generic; - using System.Diagnostics.CodeAnalysis; internal sealed class MessageWindow : DispatcherObject, IDisposable { @@ -81,7 +77,7 @@ public void Dispose() } // This isn't right if the Dispatcher has already started shutting down. - // It will wind up leaking the class ATOM... + // The HWND itself will get cleaned up on thread completion, but it will wind up leaking the class ATOM... [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disposing")] private void _Dispose(bool disposing, bool isHwndBeingDestroyed) { diff --git a/Microsoft.Windows.Shell/Standard/NativeMethods.cs b/Microsoft.Windows.Shell/Standard/NativeMethods.cs index 980a77a..bce4301 100644 --- a/Microsoft.Windows.Shell/Standard/NativeMethods.cs +++ b/Microsoft.Windows.Shell/Standard/NativeMethods.cs @@ -1,7 +1,4 @@ -/**************************************************************************\ - Copyright Microsoft Corporation. All Rights Reserved. -\**************************************************************************/ - + namespace Standard { using System; @@ -27,8 +24,8 @@ internal static class Win32Value { public const uint MAX_PATH = 260; public const uint INFOTIPSIZE = 1024; - public const uint TRUE = 1; - public const uint FALSE = 0; + public const int TRUE = 1; + public const int FALSE = 0; public const uint sizeof_WCHAR = 2; public const uint sizeof_CHAR = 1; public const uint sizeof_BOOL = 4; @@ -39,16 +36,41 @@ internal static class Win32Value /// [Flags] internal enum HCF - { - HIGHCONTRASTON = 0x00000001, - AVAILABLE = 0x00000002, - HOTKEYACTIVE = 0x00000004, - CONFIRMHOTKEY = 0x00000008, - HOTKEYSOUND = 0x00000010, - INDICATOR = 0x00000020, + { + HIGHCONTRASTON = 0x00000001, + AVAILABLE = 0x00000002, + HOTKEYACTIVE = 0x00000004, + CONFIRMHOTKEY = 0x00000008, + HOTKEYSOUND = 0x00000010, + INDICATOR = 0x00000020, HOTKEYAVAILABLE = 0x00000040, } + internal enum DROPEFFECT + { + NONE = 0, + COPY = 1, + MOVE = 2, + LINK = 4, + SCROLL = unchecked((int)0x80000000), + } + + /// + /// DROPIMAGE_* + /// + internal enum DROPIMAGETYPE + { + INVALID = -1, + NONE = 0, + COPY = DROPEFFECT.COPY, + MOVE = DROPEFFECT.MOVE, + LINK = DROPEFFECT.LINK, + LABEL = 6, + WARNING = 7, + // Windows 7 and later + NOIMAGE = 8, + } + /// /// BITMAPINFOHEADER Compression type. BI_*. /// @@ -61,7 +83,7 @@ internal enum BI /// CombingRgn flags. RGN_* /// internal enum RGN - { + { /// /// Creates the intersection of the two combined regions. /// @@ -251,7 +273,6 @@ internal enum HT CAPTION = 2, SYSMENU = 3, GROWBOX = 4, - SIZE = GROWBOX, MENU = 5, HSCROLL = 6, VSCROLL = 7, @@ -266,10 +287,6 @@ internal enum HT BOTTOMLEFT = 16, BOTTOMRIGHT = 17, BORDER = 18, - REDUCE = MINBUTTON, - ZOOM = MAXBUTTON, - SIZEFIRST = LEFT, - SIZELAST = BOTTOMRIGHT, OBJECT = 19, CLOSE = 20, HELP = 21 @@ -393,238 +410,238 @@ internal enum SM /// internal enum SPI { - GETBEEP = 0x0001, - SETBEEP = 0x0002, - GETMOUSE = 0x0003, - SETMOUSE = 0x0004, - GETBORDER = 0x0005, - SETBORDER = 0x0006, - GETKEYBOARDSPEED = 0x000A, - SETKEYBOARDSPEED = 0x000B, - LANGDRIVER = 0x000C, + GETBEEP = 0x0001, + SETBEEP = 0x0002, + GETMOUSE = 0x0003, + SETMOUSE = 0x0004, + GETBORDER = 0x0005, + SETBORDER = 0x0006, + GETKEYBOARDSPEED = 0x000A, + SETKEYBOARDSPEED = 0x000B, + LANGDRIVER = 0x000C, ICONHORIZONTALSPACING = 0x000D, - GETSCREENSAVETIMEOUT = 0x000E, - SETSCREENSAVETIMEOUT = 0x000F, - GETSCREENSAVEACTIVE = 0x0010, - SETSCREENSAVEACTIVE = 0x0011, - GETGRIDGRANULARITY = 0x0012, - SETGRIDGRANULARITY = 0x0013, - SETDESKWALLPAPER = 0x0014, - SETDESKPATTERN = 0x0015, - GETKEYBOARDDELAY = 0x0016, - SETKEYBOARDDELAY = 0x0017, - ICONVERTICALSPACING = 0x0018, - GETICONTITLEWRAP = 0x0019, - SETICONTITLEWRAP = 0x001A, - GETMENUDROPALIGNMENT = 0x001B, - SETMENUDROPALIGNMENT = 0x001C, - SETDOUBLECLKWIDTH = 0x001D, - SETDOUBLECLKHEIGHT = 0x001E, - GETICONTITLELOGFONT = 0x001F, - SETDOUBLECLICKTIME = 0x0020, - SETMOUSEBUTTONSWAP = 0x0021, - SETICONTITLELOGFONT = 0x0022, - GETFASTTASKSWITCH = 0x0023, - SETFASTTASKSWITCH = 0x0024, - - SETDRAGFULLWINDOWS = 0x0025, - GETDRAGFULLWINDOWS = 0x0026, - GETNONCLIENTMETRICS = 0x0029, - SETNONCLIENTMETRICS = 0x002A, - GETMINIMIZEDMETRICS = 0x002B, - SETMINIMIZEDMETRICS = 0x002C, - GETICONMETRICS = 0x002D, - SETICONMETRICS = 0x002E, - SETWORKAREA = 0x002F, - GETWORKAREA = 0x0030, - SETPENWINDOWS = 0x0031, - GETHIGHCONTRAST = 0x0042, - SETHIGHCONTRAST = 0x0043, - GETKEYBOARDPREF = 0x0044, - SETKEYBOARDPREF = 0x0045, - GETSCREENREADER = 0x0046, - SETSCREENREADER = 0x0047, - GETANIMATION = 0x0048, - SETANIMATION = 0x0049, - GETFONTSMOOTHING = 0x004A, - SETFONTSMOOTHING = 0x004B, - SETDRAGWIDTH = 0x004C, - SETDRAGHEIGHT = 0x004D, - SETHANDHELD = 0x004E, - GETLOWPOWERTIMEOUT = 0x004F, - GETPOWEROFFTIMEOUT = 0x0050, - SETLOWPOWERTIMEOUT = 0x0051, - SETPOWEROFFTIMEOUT = 0x0052, - GETLOWPOWERACTIVE = 0x0053, - GETPOWEROFFACTIVE = 0x0054, - SETLOWPOWERACTIVE = 0x0055, - SETPOWEROFFACTIVE = 0x0056, - SETCURSORS = 0x0057, - SETICONS = 0x0058, - GETDEFAULTINPUTLANG = 0x0059, - SETDEFAULTINPUTLANG = 0x005A, - SETLANGTOGGLE = 0x005B, - GETWINDOWSEXTENSION = 0x005C, - SETMOUSETRAILS = 0x005D, - GETMOUSETRAILS = 0x005E, + GETSCREENSAVETIMEOUT = 0x000E, + SETSCREENSAVETIMEOUT = 0x000F, + GETSCREENSAVEACTIVE = 0x0010, + SETSCREENSAVEACTIVE = 0x0011, + GETGRIDGRANULARITY = 0x0012, + SETGRIDGRANULARITY = 0x0013, + SETDESKWALLPAPER = 0x0014, + SETDESKPATTERN = 0x0015, + GETKEYBOARDDELAY = 0x0016, + SETKEYBOARDDELAY = 0x0017, + ICONVERTICALSPACING = 0x0018, + GETICONTITLEWRAP = 0x0019, + SETICONTITLEWRAP = 0x001A, + GETMENUDROPALIGNMENT = 0x001B, + SETMENUDROPALIGNMENT = 0x001C, + SETDOUBLECLKWIDTH = 0x001D, + SETDOUBLECLKHEIGHT = 0x001E, + GETICONTITLELOGFONT = 0x001F, + SETDOUBLECLICKTIME = 0x0020, + SETMOUSEBUTTONSWAP = 0x0021, + SETICONTITLELOGFONT = 0x0022, + GETFASTTASKSWITCH = 0x0023, + SETFASTTASKSWITCH = 0x0024, + + SETDRAGFULLWINDOWS = 0x0025, + GETDRAGFULLWINDOWS = 0x0026, + GETNONCLIENTMETRICS = 0x0029, + SETNONCLIENTMETRICS = 0x002A, + GETMINIMIZEDMETRICS = 0x002B, + SETMINIMIZEDMETRICS = 0x002C, + GETICONMETRICS = 0x002D, + SETICONMETRICS = 0x002E, + SETWORKAREA = 0x002F, + GETWORKAREA = 0x0030, + SETPENWINDOWS = 0x0031, + GETHIGHCONTRAST = 0x0042, + SETHIGHCONTRAST = 0x0043, + GETKEYBOARDPREF = 0x0044, + SETKEYBOARDPREF = 0x0045, + GETSCREENREADER = 0x0046, + SETSCREENREADER = 0x0047, + GETANIMATION = 0x0048, + SETANIMATION = 0x0049, + GETFONTSMOOTHING = 0x004A, + SETFONTSMOOTHING = 0x004B, + SETDRAGWIDTH = 0x004C, + SETDRAGHEIGHT = 0x004D, + SETHANDHELD = 0x004E, + GETLOWPOWERTIMEOUT = 0x004F, + GETPOWEROFFTIMEOUT = 0x0050, + SETLOWPOWERTIMEOUT = 0x0051, + SETPOWEROFFTIMEOUT = 0x0052, + GETLOWPOWERACTIVE = 0x0053, + GETPOWEROFFACTIVE = 0x0054, + SETLOWPOWERACTIVE = 0x0055, + SETPOWEROFFACTIVE = 0x0056, + SETCURSORS = 0x0057, + SETICONS = 0x0058, + GETDEFAULTINPUTLANG = 0x0059, + SETDEFAULTINPUTLANG = 0x005A, + SETLANGTOGGLE = 0x005B, + GETWINDOWSEXTENSION = 0x005C, + SETMOUSETRAILS = 0x005D, + GETMOUSETRAILS = 0x005E, SETSCREENSAVERRUNNING = 0x0061, - SCREENSAVERRUNNING = SETSCREENSAVERRUNNING, - GETFILTERKEYS = 0x0032, - SETFILTERKEYS = 0x0033, - GETTOGGLEKEYS = 0x0034, - SETTOGGLEKEYS = 0x0035, - GETMOUSEKEYS = 0x0036, - SETMOUSEKEYS = 0x0037, - GETSHOWSOUNDS = 0x0038, - SETSHOWSOUNDS = 0x0039, - GETSTICKYKEYS = 0x003A, - SETSTICKYKEYS = 0x003B, - GETACCESSTIMEOUT = 0x003C, - SETACCESSTIMEOUT = 0x003D, - - GETSERIALKEYS = 0x003E, - SETSERIALKEYS = 0x003F, - GETSOUNDSENTRY = 0x0040, - SETSOUNDSENTRY = 0x0041, - GETSNAPTODEFBUTTON = 0x005F, - SETSNAPTODEFBUTTON = 0x0060, - GETMOUSEHOVERWIDTH = 0x0062, - SETMOUSEHOVERWIDTH = 0x0063, - GETMOUSEHOVERHEIGHT = 0x0064, - SETMOUSEHOVERHEIGHT = 0x0065, - GETMOUSEHOVERTIME = 0x0066, - SETMOUSEHOVERTIME = 0x0067, - GETWHEELSCROLLLINES = 0x0068, - SETWHEELSCROLLLINES = 0x0069, - GETMENUSHOWDELAY = 0x006A, - SETMENUSHOWDELAY = 0x006B, + SCREENSAVERRUNNING = SETSCREENSAVERRUNNING, + GETFILTERKEYS = 0x0032, + SETFILTERKEYS = 0x0033, + GETTOGGLEKEYS = 0x0034, + SETTOGGLEKEYS = 0x0035, + GETMOUSEKEYS = 0x0036, + SETMOUSEKEYS = 0x0037, + GETSHOWSOUNDS = 0x0038, + SETSHOWSOUNDS = 0x0039, + GETSTICKYKEYS = 0x003A, + SETSTICKYKEYS = 0x003B, + GETACCESSTIMEOUT = 0x003C, + SETACCESSTIMEOUT = 0x003D, + + GETSERIALKEYS = 0x003E, + SETSERIALKEYS = 0x003F, + GETSOUNDSENTRY = 0x0040, + SETSOUNDSENTRY = 0x0041, + GETSNAPTODEFBUTTON = 0x005F, + SETSNAPTODEFBUTTON = 0x0060, + GETMOUSEHOVERWIDTH = 0x0062, + SETMOUSEHOVERWIDTH = 0x0063, + GETMOUSEHOVERHEIGHT = 0x0064, + SETMOUSEHOVERHEIGHT = 0x0065, + GETMOUSEHOVERTIME = 0x0066, + SETMOUSEHOVERTIME = 0x0067, + GETWHEELSCROLLLINES = 0x0068, + SETWHEELSCROLLLINES = 0x0069, + GETMENUSHOWDELAY = 0x006A, + SETMENUSHOWDELAY = 0x006B, GETWHEELSCROLLCHARS = 0x006C, SETWHEELSCROLLCHARS = 0x006D, - GETSHOWIMEUI = 0x006E, - SETSHOWIMEUI = 0x006F, + GETSHOWIMEUI = 0x006E, + SETSHOWIMEUI = 0x006F, - GETMOUSESPEED = 0x0070, - SETMOUSESPEED = 0x0071, + GETMOUSESPEED = 0x0070, + SETMOUSESPEED = 0x0071, GETSCREENSAVERRUNNING = 0x0072, - GETDESKWALLPAPER = 0x0073, - + GETDESKWALLPAPER = 0x0073, + GETAUDIODESCRIPTION = 0x0074, SETAUDIODESCRIPTION = 0x0075, GETSCREENSAVESECURE = 0x0076, SETSCREENSAVESECURE = 0x0077, - GETHUNGAPPTIMEOUT = 0x0078, - SETHUNGAPPTIMEOUT = 0x0079, - GETWAITTOKILLTIMEOUT = 0x007A, - SETWAITTOKILLTIMEOUT = 0x007B, + GETHUNGAPPTIMEOUT = 0x0078, + SETHUNGAPPTIMEOUT = 0x0079, + GETWAITTOKILLTIMEOUT = 0x007A, + SETWAITTOKILLTIMEOUT = 0x007B, GETWAITTOKILLSERVICETIMEOUT = 0x007C, SETWAITTOKILLSERVICETIMEOUT = 0x007D, - GETMOUSEDOCKTHRESHOLD = 0x007E, - SETMOUSEDOCKTHRESHOLD = 0x007F, - GETPENDOCKTHRESHOLD = 0x0080, - SETPENDOCKTHRESHOLD = 0x0081, - GETWINARRANGING = 0x0082, - SETWINARRANGING = 0x0083, - GETMOUSEDRAGOUTTHRESHOLD = 0x0084, - SETMOUSEDRAGOUTTHRESHOLD = 0x0085, - GETPENDRAGOUTTHRESHOLD = 0x0086, - SETPENDRAGOUTTHRESHOLD = 0x0087, + GETMOUSEDOCKTHRESHOLD = 0x007E, + SETMOUSEDOCKTHRESHOLD = 0x007F, + GETPENDOCKTHRESHOLD = 0x0080, + SETPENDOCKTHRESHOLD = 0x0081, + GETWINARRANGING = 0x0082, + SETWINARRANGING = 0x0083, + GETMOUSEDRAGOUTTHRESHOLD = 0x0084, + SETMOUSEDRAGOUTTHRESHOLD = 0x0085, + GETPENDRAGOUTTHRESHOLD = 0x0086, + SETPENDRAGOUTTHRESHOLD = 0x0087, GETMOUSESIDEMOVETHRESHOLD = 0x0088, SETMOUSESIDEMOVETHRESHOLD = 0x0089, - GETPENSIDEMOVETHRESHOLD = 0x008A, - SETPENSIDEMOVETHRESHOLD = 0x008B, - GETDRAGFROMMAXIMIZE = 0x008C, - SETDRAGFROMMAXIMIZE = 0x008D, - GETSNAPSIZING = 0x008E, - SETSNAPSIZING = 0x008F, - GETDOCKMOVING = 0x0090, - SETDOCKMOVING = 0x0091, - - GETACTIVEWINDOWTRACKING = 0x1000, - SETACTIVEWINDOWTRACKING = 0x1001, - GETMENUANIMATION = 0x1002, - SETMENUANIMATION = 0x1003, - GETCOMBOBOXANIMATION = 0x1004, - SETCOMBOBOXANIMATION = 0x1005, - GETLISTBOXSMOOTHSCROLLING = 0x1006, - SETLISTBOXSMOOTHSCROLLING = 0x1007, - GETGRADIENTCAPTIONS = 0x1008, - SETGRADIENTCAPTIONS = 0x1009, - GETKEYBOARDCUES = 0x100A, - SETKEYBOARDCUES = 0x100B, - GETMENUUNDERLINES = GETKEYBOARDCUES, - SETMENUUNDERLINES = SETKEYBOARDCUES, - GETACTIVEWNDTRKZORDER = 0x100C, - SETACTIVEWNDTRKZORDER = 0x100D, - GETHOTTRACKING = 0x100E, - SETHOTTRACKING = 0x100F, - GETMENUFADE = 0x1012, - SETMENUFADE = 0x1013, - GETSELECTIONFADE = 0x1014, - SETSELECTIONFADE = 0x1015, - GETTOOLTIPANIMATION = 0x1016, - SETTOOLTIPANIMATION = 0x1017, - GETTOOLTIPFADE = 0x1018, - SETTOOLTIPFADE = 0x1019, - GETCURSORSHADOW = 0x101A, - SETCURSORSHADOW = 0x101B, - GETMOUSESONAR = 0x101C, - SETMOUSESONAR = 0x101D, - GETMOUSECLICKLOCK = 0x101E, - SETMOUSECLICKLOCK = 0x101F, - GETMOUSEVANISH = 0x1020, - SETMOUSEVANISH = 0x1021, - GETFLATMENU = 0x1022, - SETFLATMENU = 0x1023, - GETDROPSHADOW = 0x1024, - SETDROPSHADOW = 0x1025, - GETBLOCKSENDINPUTRESETS = 0x1026, - SETBLOCKSENDINPUTRESETS = 0x1027, - - GETUIEFFECTS = 0x103E, - SETUIEFFECTS = 0x103F, - - GETDISABLEOVERLAPPEDCONTENT = 0x1040, - SETDISABLEOVERLAPPEDCONTENT = 0x1041, - GETCLIENTAREAANIMATION = 0x1042, - SETCLIENTAREAANIMATION = 0x1043, - GETCLEARTYPE = 0x1048, - SETCLEARTYPE = 0x1049, - GETSPEECHRECOGNITION = 0x104A, - SETSPEECHRECOGNITION = 0x104B, - - GETFOREGROUNDLOCKTIMEOUT = 0x2000, - SETFOREGROUNDLOCKTIMEOUT = 0x2001, - GETACTIVEWNDTRKTIMEOUT = 0x2002, - SETACTIVEWNDTRKTIMEOUT = 0x2003, - GETFOREGROUNDFLASHCOUNT = 0x2004, - SETFOREGROUNDFLASHCOUNT = 0x2005, - GETCARETWIDTH = 0x2006, - SETCARETWIDTH = 0x2007, - - GETMOUSECLICKLOCKTIME = 0x2008, - SETMOUSECLICKLOCKTIME = 0x2009, - GETFONTSMOOTHINGTYPE = 0x200A, - SETFONTSMOOTHINGTYPE = 0x200B, - - GETFONTSMOOTHINGCONTRAST = 0x200C, - SETFONTSMOOTHINGCONTRAST = 0x200D, - - GETFOCUSBORDERWIDTH = 0x200E, - SETFOCUSBORDERWIDTH = 0x200F, - GETFOCUSBORDERHEIGHT = 0x2010, - SETFOCUSBORDERHEIGHT = 0x2011, - - GETFONTSMOOTHINGORIENTATION = 0x2012, - SETFONTSMOOTHINGORIENTATION = 0x2013, - - GETMINIMUMHITRADIUS = 0x2014, - SETMINIMUMHITRADIUS = 0x2015, - GETMESSAGEDURATION = 0x2016, - SETMESSAGEDURATION = 0x2017, + GETPENSIDEMOVETHRESHOLD = 0x008A, + SETPENSIDEMOVETHRESHOLD = 0x008B, + GETDRAGFROMMAXIMIZE = 0x008C, + SETDRAGFROMMAXIMIZE = 0x008D, + GETSNAPSIZING = 0x008E, + SETSNAPSIZING = 0x008F, + GETDOCKMOVING = 0x0090, + SETDOCKMOVING = 0x0091, + + GETACTIVEWINDOWTRACKING = 0x1000, + SETACTIVEWINDOWTRACKING = 0x1001, + GETMENUANIMATION = 0x1002, + SETMENUANIMATION = 0x1003, + GETCOMBOBOXANIMATION = 0x1004, + SETCOMBOBOXANIMATION = 0x1005, + GETLISTBOXSMOOTHSCROLLING = 0x1006, + SETLISTBOXSMOOTHSCROLLING = 0x1007, + GETGRADIENTCAPTIONS = 0x1008, + SETGRADIENTCAPTIONS = 0x1009, + GETKEYBOARDCUES = 0x100A, + SETKEYBOARDCUES = 0x100B, + GETMENUUNDERLINES = GETKEYBOARDCUES, + SETMENUUNDERLINES = SETKEYBOARDCUES, + GETACTIVEWNDTRKZORDER = 0x100C, + SETACTIVEWNDTRKZORDER = 0x100D, + GETHOTTRACKING = 0x100E, + SETHOTTRACKING = 0x100F, + GETMENUFADE = 0x1012, + SETMENUFADE = 0x1013, + GETSELECTIONFADE = 0x1014, + SETSELECTIONFADE = 0x1015, + GETTOOLTIPANIMATION = 0x1016, + SETTOOLTIPANIMATION = 0x1017, + GETTOOLTIPFADE = 0x1018, + SETTOOLTIPFADE = 0x1019, + GETCURSORSHADOW = 0x101A, + SETCURSORSHADOW = 0x101B, + GETMOUSESONAR = 0x101C, + SETMOUSESONAR = 0x101D, + GETMOUSECLICKLOCK = 0x101E, + SETMOUSECLICKLOCK = 0x101F, + GETMOUSEVANISH = 0x1020, + SETMOUSEVANISH = 0x1021, + GETFLATMENU = 0x1022, + SETFLATMENU = 0x1023, + GETDROPSHADOW = 0x1024, + SETDROPSHADOW = 0x1025, + GETBLOCKSENDINPUTRESETS = 0x1026, + SETBLOCKSENDINPUTRESETS = 0x1027, + + GETUIEFFECTS = 0x103E, + SETUIEFFECTS = 0x103F, + + GETDISABLEOVERLAPPEDCONTENT = 0x1040, + SETDISABLEOVERLAPPEDCONTENT = 0x1041, + GETCLIENTAREAANIMATION = 0x1042, + SETCLIENTAREAANIMATION = 0x1043, + GETCLEARTYPE = 0x1048, + SETCLEARTYPE = 0x1049, + GETSPEECHRECOGNITION = 0x104A, + SETSPEECHRECOGNITION = 0x104B, + + GETFOREGROUNDLOCKTIMEOUT = 0x2000, + SETFOREGROUNDLOCKTIMEOUT = 0x2001, + GETACTIVEWNDTRKTIMEOUT = 0x2002, + SETACTIVEWNDTRKTIMEOUT = 0x2003, + GETFOREGROUNDFLASHCOUNT = 0x2004, + SETFOREGROUNDFLASHCOUNT = 0x2005, + GETCARETWIDTH = 0x2006, + SETCARETWIDTH = 0x2007, + + GETMOUSECLICKLOCKTIME = 0x2008, + SETMOUSECLICKLOCKTIME = 0x2009, + GETFONTSMOOTHINGTYPE = 0x200A, + SETFONTSMOOTHINGTYPE = 0x200B, + + GETFONTSMOOTHINGCONTRAST = 0x200C, + SETFONTSMOOTHINGCONTRAST = 0x200D, + + GETFOCUSBORDERWIDTH = 0x200E, + SETFOCUSBORDERWIDTH = 0x200F, + GETFOCUSBORDERHEIGHT = 0x2010, + SETFOCUSBORDERHEIGHT = 0x2011, + + GETFONTSMOOTHINGORIENTATION = 0x2012, + SETFONTSMOOTHINGORIENTATION = 0x2013, + + GETMINIMUMHITRADIUS = 0x2014, + SETMINIMUMHITRADIUS = 0x2015, + GETMESSAGEDURATION = 0x2016, + SETMESSAGEDURATION = 0x2017, } /// @@ -635,45 +652,44 @@ internal enum SPIF { None = 0, UPDATEINIFILE = 0x01, - SENDCHANGE = 0x02, - SENDWININICHANGE = SENDCHANGE, + SENDWININICHANGE = 0x02, } [Flags] internal enum STATE_SYSTEM { - UNAVAILABLE = 0x00000001, // Disabled - SELECTED = 0x00000002, - FOCUSED = 0x00000004, - PRESSED = 0x00000008, - CHECKED = 0x00000010, - MIXED = 0x00000020, // 3-state checkbox or toolbar button - INDETERMINATE = MIXED, - READONLY = 0x00000040, - HOTTRACKED = 0x00000080, - DEFAULT = 0x00000100, - EXPANDED = 0x00000200, - COLLAPSED = 0x00000400, - BUSY = 0x00000800, - FLOATING = 0x00001000, // Children "owned" not "contained" by parent - MARQUEED = 0x00002000, - ANIMATED = 0x00004000, - INVISIBLE = 0x00008000, - OFFSCREEN = 0x00010000, - SIZEABLE = 0x00020000, - MOVEABLE = 0x00040000, - SELFVOICING = 0x00080000, - FOCUSABLE = 0x00100000, - SELECTABLE = 0x00200000, - LINKED = 0x00400000, - TRAVERSED = 0x00800000, - MULTISELECTABLE = 0x01000000, // Supports multiple selection - EXTSELECTABLE = 0x02000000, // Supports extended selection - ALERT_LOW = 0x04000000, // This information is of low priority - ALERT_MEDIUM = 0x08000000, // This information is of medium priority - ALERT_HIGH = 0x10000000, // This information is of high priority - PROTECTED = 0x20000000, // access to this is restricted - VALID = 0x3FFFFFFF, + UNAVAILABLE = 0x00000001, // Disabled + SELECTED = 0x00000002, + FOCUSED = 0x00000004, + PRESSED = 0x00000008, + CHECKED = 0x00000010, + MIXED = 0x00000020, // 3-state checkbox or toolbar button + INDETERMINATE = MIXED, + READONLY = 0x00000040, + HOTTRACKED = 0x00000080, + DEFAULT = 0x00000100, + EXPANDED = 0x00000200, + COLLAPSED = 0x00000400, + BUSY = 0x00000800, + FLOATING = 0x00001000, // Children "owned" not "contained" by parent + MARQUEED = 0x00002000, + ANIMATED = 0x00004000, + INVISIBLE = 0x00008000, + OFFSCREEN = 0x00010000, + SIZEABLE = 0x00020000, + MOVEABLE = 0x00040000, + SELFVOICING = 0x00080000, + FOCUSABLE = 0x00100000, + SELECTABLE = 0x00200000, + LINKED = 0x00400000, + TRAVERSED = 0x00800000, + MULTISELECTABLE = 0x01000000, // Supports multiple selection + EXTSELECTABLE = 0x02000000, // Supports extended selection + ALERT_LOW = 0x04000000, // This information is of low priority + ALERT_MEDIUM = 0x08000000, // This information is of medium priority + ALERT_HIGH = 0x10000000, // This information is of high priority + PROTECTED = 0x20000000, // access to this is restricted + VALID = 0x3FFFFFFF, } internal enum StockObject : int @@ -896,6 +912,7 @@ internal enum WM DWMWINDOWMAXIMIZEDCHANGE = 0x0321, GETTITLEBARINFOEX = 0x033F, + #region Windows 7 DWMSENDICONICTHUMBNAIL = 0x0323, DWMSENDICONICLIVEPREVIEWBITMAP = 0x0326, @@ -1023,7 +1040,7 @@ internal enum WINDOWTHEMEATTRIBUTETYPE : uint /// /// DWMFLIP3DWINDOWPOLICY. DWMFLIP3D_* /// - internal enum DWMFLIP3D + internal enum DWMFLIP3D { DEFAULT, EXCLUDEBELOW, @@ -1331,6 +1348,11 @@ internal enum WVR REDRAW = HREDRAW | VREDRAW, } + internal enum DSH + { + ALLOWDROPDESCRIPTIONTEXT = 1, + } + #endregion #region SafeHandles @@ -1492,7 +1514,6 @@ public static SafeDC GetDesktop() return GetDC(IntPtr.Zero); } - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static SafeDC WrapDC(IntPtr hdc) { @@ -1528,8 +1549,6 @@ protected override bool ReleaseHandle() return s == Status.Ok; } - [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")] public static SafeGdiplusStartupToken Startup() { @@ -1637,7 +1656,7 @@ internal struct BLENDFUNCTION } [StructLayout(LayoutKind.Sequential)] - internal struct HIGHCONTRAST + internal struct HIGHCONTRAST { public int cbSize; public HCF dwFlags; @@ -1655,9 +1674,9 @@ internal struct RGBQUAD public byte rgbReserved; } - [StructLayout(LayoutKind.Sequential, Pack = 2)] - internal struct BITMAPINFOHEADER - { + [StructLayout(LayoutKind.Sequential, Pack=2)] + internal struct BITMAPINFOHEADER + { public int biSize; public int biWidth; public int biHeight; @@ -1673,8 +1692,8 @@ internal struct BITMAPINFOHEADER [StructLayout(LayoutKind.Sequential)] internal struct BITMAPINFO - { - public BITMAPINFOHEADER bmiHeader; + { + public BITMAPINFOHEADER bmiHeader; public RGBQUAD bmiColors; } @@ -1686,7 +1705,7 @@ internal struct CHANGEFILTERSTRUCT public MSGFLTINFO ExtStatus; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] internal struct CREATESTRUCT { public IntPtr lpCreateParams; @@ -1698,10 +1717,8 @@ internal struct CREATESTRUCT public int y; public int x; public WS style; - [MarshalAs(UnmanagedType.LPWStr)] - public string lpszName; - [MarshalAs(UnmanagedType.LPWStr)] - public string lpszClass; + [MarshalAs(UnmanagedType.LPWStr)] public string lpszName; + [MarshalAs(UnmanagedType.LPWStr)] public string lpszClass; public WS_EX dwExStyle; } @@ -1786,7 +1803,6 @@ internal class NOTIFYICONDATA IntPtr hBalloonIcon; } - [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] [StructLayout(LayoutKind.Explicit)] internal class PROPVARIANT : IDisposable { @@ -1907,7 +1923,7 @@ internal class SHARDAPPIDINFOLINK } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] internal struct LOGFONT { public int lfHeight; @@ -1958,7 +1974,6 @@ internal struct NONCLIENTMETRICS // Vista only public int iPaddedBorderWidth; - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] public static NONCLIENTMETRICS VistaMetricsStruct { get @@ -1969,7 +1984,6 @@ public static NONCLIENTMETRICS VistaMetricsStruct } } - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] public static NONCLIENTMETRICS XPMetricsStruct { get @@ -2146,7 +2160,6 @@ public override int GetHashCode() } } - [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] [StructLayout(LayoutKind.Sequential)] internal class RefRECT { @@ -2279,7 +2292,7 @@ internal struct WINDOWPOS public int flags; } - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] internal struct WNDCLASSEX { public int cbSize; @@ -2323,7 +2336,7 @@ internal struct UNSIGNED_RATIO public uint uiDenominator; } - [StructLayout(LayoutKind.Sequential, Pack=1)] + [StructLayout(LayoutKind.Sequential, Pack = 1)] internal struct DWM_TIMING_INFO { public int cbSize; @@ -2368,13 +2381,84 @@ internal struct DWM_TIMING_INFO public ulong cBuffersEmpty; } + [StructLayout(LayoutKind.Sequential)] + internal struct SHDRAGIMAGE + { + public SIZE sizeDragImage; + public POINT ptOffset; + public IntPtr hbmpDragImage; + public int crColorKey; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Size = 1044)] + internal struct DROPDESCRIPTION + { + public DROPIMAGETYPE type; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string szMessage; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string szInsert; + } + #endregion - /// Delegate declaration that matches native WndProc signatures. - internal delegate IntPtr WndProc(IntPtr hwnd, WM uMsg, IntPtr wParam, IntPtr lParam); + #region Interfaces + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ServiceProvider) + ] + internal interface IServiceProvider + { + [return: MarshalAs(UnmanagedType.IUnknown)] + object QueryService(ref Guid guidService, ref Guid riid); + } + + [ + ComImport, + Guid(IID.DragSourceHelper), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown) + ] + internal interface IDragSourceHelper + { + void InitializeFromBitmap([In] ref SHDRAGIMAGE pshdi, [In] IDataObject pDataObject); + void InitializeFromWindow(IntPtr hwnd, [In] ref POINT ppt, [In] IDataObject pDataObject); + } + + [ + ComImport, + Guid(IID.DragSourceHelper2), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown) + ] + internal interface IDragSourceHelper2 : IDragSourceHelper + { + #region IDragSourceHelper redeclaration + new void InitializeFromBitmap([In] ref SHDRAGIMAGE pshdi, [In] IDataObject pDataObject); + new void InitializeFromWindow(IntPtr hwnd, [In] ref POINT ppt, [In] IDataObject pDataObject); + #endregion + + void SetFlags(DSH dwFlags); + } + + [ + ComImport, + Guid(IID.DropTargetHelper), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown) + ] + internal interface IDropTargetHelper + { + void DragEnter(IntPtr hwndTarget, IDataObject pDataObject, ref POINT ppt, int effect); + void DragLeave(); + void DragOver(ref POINT ppt, int effect); + void Drop(IDataObject dataObject, ref POINT ppt, int effect); + void Show([MarshalAs(UnmanagedType.Bool)] bool fShow); + } + + #endregion /// Delegate declaration that matches native WndProc signatures. - internal delegate IntPtr WndProcHook(IntPtr hwnd, WM uMsg, IntPtr wParam, IntPtr lParam, ref bool handled); + internal delegate IntPtr WndProc(IntPtr hwnd, WM uMsg, IntPtr wParam, IntPtr lParam); /// Delegate declaration that matches managed WndProc signatures. internal delegate IntPtr MessageHandler(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled); @@ -2398,6 +2482,24 @@ public static RECT AdjustWindowRectEx(RECT lpRect, WS dwStyle, bool bMenu, WS_EX return lpRect; } + [DllImport("user32.dll", EntryPoint="AllowSetForegroundWindow", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _AllowSetForegroundWindow(int dwProcessId); + + public static void AllowSetForegroundWindow() + { + int ASFW_ANY = -1; + AllowSetForegroundWindow(ASFW_ANY); + } + + public static void AllowSetForegroundWindow(int dwProcessId) + { + if (!_AllowSetForegroundWindow(dwProcessId)) + { + HRESULT.ThrowLastError(); + } + } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("user32.dll", EntryPoint = "ChangeWindowMessageFilter", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] @@ -2452,7 +2554,7 @@ public static HRESULT ChangeWindowMessageFilterEx(IntPtr hwnd, WM message, MSGFL [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("gdi32.dll")] public static extern CombineRgnResult CombineRgn(IntPtr hrgnDest, IntPtr hrgnSrc1, IntPtr hrgnSrc2, RGN fnCombineMode); - + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("shell32.dll", EntryPoint = "CommandLineToArgvW", CharSet = CharSet.Unicode)] private static extern IntPtr _CommandLineToArgvW([MarshalAs(UnmanagedType.LPWStr)] string cmdLine, out int numArgs); @@ -2636,11 +2738,6 @@ public static IntPtr CreateWindowEx( [DllImport("dwmapi.dll", PreserveSig = false)] public static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS pMarInset); - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("dwmapi.dll", EntryPoint = "DwmIsCompositionEnabled", PreserveSig = false)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _DwmIsCompositionEnabled(); - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("dwmapi.dll", EntryPoint = "DwmGetColorizationColor", PreserveSig = true)] private static extern HRESULT _DwmGetColorizationColor(out uint pcrColorization, [Out, MarshalAs(UnmanagedType.Bool)] out bool pfOpaqueBlend); @@ -2666,6 +2763,36 @@ public static bool DwmGetColorizationColor(out uint pcrColorization, out bool pf return false; } + //#define DWM_SIT_DISPLAYFRAME 0x00000001 // Display a window frame around the provided bitmap + + [DllImport("dwmapi.dll", EntryPoint = "DwmGetCompositionTimingInfo")] + private static extern HRESULT _DwmGetCompositionTimingInfo(IntPtr hwnd, ref DWM_TIMING_INFO pTimingInfo); + + public static DWM_TIMING_INFO? DwmGetCompositionTimingInfo(IntPtr hwnd) + { + if (!Utility.IsOSVistaOrNewer) + { + // API was new to Vista. + return null; + } + + var dti = new DWM_TIMING_INFO { cbSize = Marshal.SizeOf(typeof(DWM_TIMING_INFO)) }; + HRESULT hr = _DwmGetCompositionTimingInfo(hwnd, ref dti); + if (hr == HRESULT.E_PENDING) + { + // The system isn't yet ready to respond. Return null rather than throw. + return null; + } + hr.ThrowIfFailed(); + + return dti; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", EntryPoint = "DwmIsCompositionEnabled", PreserveSig = false)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _DwmIsCompositionEnabled(); + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static bool DwmIsCompositionEnabled() { @@ -2691,7 +2818,7 @@ public static void DwmSetWindowAttributeFlip3DPolicy(IntPtr hwnd, DWMFLIP3D flip { Assert.IsTrue(Utility.IsOSVistaOrNewer); var dwPolicy = (int)flip3dPolicy; - _DwmSetWindowAttribute(hwnd, DWMWA.FLIP3D_POLICY, ref dwPolicy, sizeof(int)); + _DwmSetWindowAttribute(hwnd, DWMWA.FLIP3D_POLICY, ref dwPolicy, sizeof(int)); } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] @@ -2775,7 +2902,22 @@ public static RECT GetClientRect(IntPtr hwnd) return rc; } - [DllImport("uxtheme.dll", EntryPoint="GetCurrentThemeName", CharSet = CharSet.Unicode)] + [DllImport("user32.dll", EntryPoint="GetCursorPos", SetLastError=true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _GetCursorPos(out POINT lpPoint); + + public static POINT GetCursorPos() + { + POINT pt; + if (!_GetCursorPos(out pt)) + { + HRESULT.ThrowLastError(); + } + + return pt; + } + + [DllImport("uxtheme.dll", EntryPoint = "GetCurrentThemeName", CharSet = CharSet.Unicode)] private static extern HRESULT _GetCurrentThemeName( StringBuilder pszThemeFileName, int dwMaxNameChars, @@ -2814,11 +2956,9 @@ public static void GetDC() { } [DllImport("gdi32.dll")] public static extern int GetDeviceCaps(SafeDC hdc, DeviceCap nIndex); - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("kernel32.dll", EntryPoint = "GetModuleFileName", CharSet = CharSet.Unicode, SetLastError = true)] + [DllImport("kernel32.dll", EntryPoint="GetModuleFileName", CharSet=CharSet.Unicode, SetLastError=true)] private static extern int _GetModuleFileName(IntPtr hModule, StringBuilder lpFilename, int nSize); - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static string GetModuleFileName(IntPtr hModule) { var buffer = new StringBuilder((int)Win32Value.MAX_PATH); @@ -2913,6 +3053,19 @@ public static IntPtr GetWindowLongPtr(IntPtr hwnd, GWL nIndex) return ret; } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint="SetProp", CharSet=CharSet.Unicode, SetLastError=true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SetProp(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] string lpString, IntPtr hData); + + public static void SetProp(IntPtr hwnd, string lpString, IntPtr hData) + { + if (!_SetProp(hwnd, lpString, hData)) + { + HRESULT.ThrowLastError(); + } + } + /// /// Sets attributes to control how visual styles are applied to a specified window. /// @@ -3163,25 +3316,18 @@ public static void SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool bRedraw) private static extern bool _SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags); [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags) + public static void SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags) { if (!_SetWindowPos(hWnd, hWndInsertAfter, x, y, cx, cy, uFlags)) { - // If this fails it's never worth taking down the process. Let the caller deal with the error if they want. - return false; + throw new Win32Exception(); } - - return true; } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("shell32.dll", SetLastError = false)] public static extern Win32Error SHFileOperation(ref SHFILEOPSTRUCT lpFileOp); - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool ShowWindow(IntPtr hwnd, SW nCmdShow); - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("user32.dll", EntryPoint = "SystemParametersInfoW", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] @@ -3238,6 +3384,7 @@ public static HIGHCONTRAST SystemParameterInfo_GetHIGHCONTRAST() // This function is strange in that it returns a BOOL if TPM_RETURNCMD isn't specified, but otherwise the command Id. // Currently it's only used with TPM_RETURNCMD, so making the signature match that. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("user32.dll")] public static extern uint TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm); @@ -3279,6 +3426,10 @@ public static IntPtr SelectObject(SafeDC hdc, SafeHBITMAP hgdiobj) [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr SendMessage(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam); + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ShowWindow(IntPtr hwnd, SW nCmdShow); + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("user32.dll", EntryPoint = "UnregisterClass", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] @@ -3310,11 +3461,11 @@ public static void UnregisterClass(string lpClassName, IntPtr hInstance) [DllImport("user32.dll", SetLastError = true, EntryPoint = "UpdateLayeredWindow")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool _UpdateLayeredWindow( - IntPtr hwnd, - SafeDC hdcDst, - [In] ref POINT pptDst, - [In] ref SIZE psize, - SafeDC hdcSrc, + IntPtr hwnd, + SafeDC hdcDst, + [In] ref POINT pptDst, + [In] ref SIZE psize, + SafeDC hdcSrc, [In] ref POINT pptSrc, int crKey, ref BLENDFUNCTION pblend, @@ -3365,52 +3516,33 @@ public static void UpdateLayeredWindow( } } - #region Win7 declarations - - [DllImport("shell32.dll", EntryPoint = "SHAddToRecentDocs")] - private static extern void _SHAddToRecentDocs_String(SHARD uFlags, [MarshalAs(UnmanagedType.LPWStr)] string pv); + [DllImport("user32.dll", SetLastError=true, EntryPoint="RegisterClipboardFormatW", CharSet=CharSet.Unicode)] + private static extern uint _RegisterClipboardFormat(string lpszFormatName); - // This overload is required. There's a cast in the Shell code that causes the wrong vtbl to be used - // if we let the marshaller convert the parameter to an IUnknown. - [DllImport("shell32.dll", EntryPoint = "SHAddToRecentDocs")] - private static extern void _SHAddToRecentDocs_ShellLink(SHARD uFlags, IShellLinkW pv); - - public static void SHAddToRecentDocs(string path) + public static uint RegisterClipboardFormat(string formatName) { - _SHAddToRecentDocs_String(SHARD.PATHW, path); - } + uint ret = _RegisterClipboardFormat(formatName); + if (ret == 0) + { + HRESULT.ThrowLastError(); + } - // Win7 only. - public static void SHAddToRecentDocs(IShellLinkW shellLink) - { - _SHAddToRecentDocs_ShellLink(SHARD.LINK, shellLink); + return ret; } + [DllImport("ole32.dll")] + public static extern void ReleaseStgMedium(ref STGMEDIUM pmedium); - //#define DWM_SIT_DISPLAYFRAME 0x00000001 // Display a window frame around the provided bitmap + [DllImport("ole32.dll")] + public static extern HRESULT CreateStreamOnHGlobal(IntPtr hGlobal, bool fDeleteOnRelease, out IStream ppstm); - [DllImport("dwmapi.dll", EntryPoint="DwmGetCompositionTimingInfo")] - private static extern HRESULT _DwmGetCompositionTimingInfo(IntPtr hwnd, ref DWM_TIMING_INFO pTimingInfo); + [DllImport("urlmon.dll")] + public static extern HRESULT CopyStgMedium(ref STGMEDIUM pcstgmedSrc, ref STGMEDIUM pstgmedDest); - public static DWM_TIMING_INFO? DwmGetCompositionTimingInfo(IntPtr hwnd) - { - if (!Utility.IsOSVistaOrNewer) - { - // API was new to Vista. - return null; - } - var dti = new DWM_TIMING_INFO { cbSize = Marshal.SizeOf(typeof(DWM_TIMING_INFO)) }; - HRESULT hr = _DwmGetCompositionTimingInfo(hwnd, ref dti); - if (hr == HRESULT.E_PENDING) - { - // The system isn't yet ready to respond. Return null rather than throw. - return null; - } - hr.ThrowIfFailed(); + #region Win7 declarations - return dti; - } + //#define DWM_SIT_DISPLAYFRAME 0x00000001 // Display a window frame around the provided bitmap [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("dwmapi.dll", PreserveSig = false)] @@ -3428,6 +3560,45 @@ public static void SHAddToRecentDocs(IShellLinkW shellLink) [DllImport("shell32.dll", PreserveSig = false)] public static extern void SHGetItemFromDataObject(IDataObject pdtobj, DOGIF dwFlags, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object ppv); + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", PreserveSig = false, EntryPoint = "SHAddToRecentDocs")] + private static extern void _SHAddToRecentDocsObj(SHARD uFlags, object pv); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", EntryPoint = "SHAddToRecentDocs")] + private static extern void _SHAddToRecentDocs_String(SHARD uFlags, [MarshalAs(UnmanagedType.LPWStr)] string pv); + + // This overload is required. There's a cast in the Shell code that causes the wrong vtbl to be used + // if we let the marshaller convert the parameter to an IUnknown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", EntryPoint = "SHAddToRecentDocs")] + private static extern void _SHAddToRecentDocs_ShellLink(SHARD uFlags, IShellLinkW pv); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SHAddToRecentDocs(string path) + { + _SHAddToRecentDocs_String(SHARD.PATHW, path); + } + + // Win7 only. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SHAddToRecentDocs(IShellLinkW shellLink) + { + _SHAddToRecentDocs_ShellLink(SHARD.LINK, shellLink); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SHAddToRecentDocs(SHARDAPPIDINFO info) + { + _SHAddToRecentDocsObj(SHARD.APPIDINFO, info); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SHAddToRecentDocs(SHARDAPPIDINFOIDLIST infodIdList) + { + _SHAddToRecentDocsObj(SHARD.APPIDINFOIDLIST, infodIdList); + } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] [DllImport("shell32.dll", PreserveSig = false)] public static extern HRESULT SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IBindCtx pbc, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object ppv); diff --git a/Microsoft.Windows.Shell/Standard/NotifyingList.cs b/Microsoft.Windows.Shell/Standard/NotifyingList.cs new file mode 100644 index 0000000..697e018 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/NotifyingList.cs @@ -0,0 +1,187 @@ + +namespace Standard +{ + using System.Collections; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Collections.Specialized; + using System.ComponentModel; + + internal class NotifyingList : IList, INotifyCollectionChanged where T : INotifyPropertyChanged + { + private readonly ObservableCollection _list; + + public event PropertyChangedEventHandler ItemPropertyChanged; + + private void _SafeAddPropertyListener(T item) + { + if (item != null) + { + item.PropertyChanged += _OnItemPropertyChanged; + } + } + + private void _SafeRemovePropertyListener(T item) + { + if (item != null) + { + item.PropertyChanged -= _OnItemPropertyChanged; + } + } + + public NotifyingList() + { + _list = new ObservableCollection(); + } + + public NotifyingList(IEnumerable collection) + { + _list = new ObservableCollection(collection); + foreach (T item in collection) + { + _SafeAddPropertyListener(item); + } + } + + private void _OnItemPropertyChanged(object sender, PropertyChangedEventArgs e) + { + var handler = ItemPropertyChanged; + if (handler != null) + { + handler(sender, e); + } + } + + #region IList Members + + public int IndexOf(T item) + { + return _list.IndexOf(item); + } + + public void Insert(int index, T item) + { + _list.Insert(index, item); + _SafeAddPropertyListener(item); + } + + public void RemoveAt(int index) + { + T item = _list[index]; + _list.RemoveAt(index); + _SafeRemovePropertyListener(item); + } + + public T this[int index] + { + get { return _list[index]; } + set { _list[index] = value; } + } + + #endregion + + #region ICollection Members + + public void Add(T item) + { + _list.Add(item); + _SafeAddPropertyListener(item); + } + + public void Clear() + { + T[] items = new T[_list.Count]; + _list.CopyTo(items, 0); + _list.Clear(); + foreach (T item in items) + { + _SafeRemovePropertyListener(item); + } + } + + public bool Contains(T item) + { + return _list.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + _list.CopyTo(array, arrayIndex); + } + + public int Count { get { return _list.Count; } } + + public bool IsReadOnly { get { return false; } } + + public bool Remove(T item) + { + // Don't call through _list.Remove(). + // If equality has been overloaded then we may try removing the handler + // from a different object and we'll leak it. + // Ensure reference equality. + int index = _list.IndexOf(item); + if (index == -1) + { + return false; + } + + RemoveAt(index); + return true; + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return _list.GetEnumerator(); + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return _list.GetEnumerator(); + } + + #endregion + + #region INotifyCollectionChanged Members + + private event NotifyCollectionChangedEventHandler _sourceCollectionChanged; + + public event NotifyCollectionChangedEventHandler CollectionChanged + { + add + { + if (_sourceCollectionChanged == null) + { + _list.CollectionChanged += _OnSourceCollectionChanged; + } + _sourceCollectionChanged += value; + } + remove + { + _sourceCollectionChanged -= value; + if (_sourceCollectionChanged == null) + { + _list.CollectionChanged -= _OnSourceCollectionChanged; + } + } + } + + private void _OnSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + var handler = _sourceCollectionChanged; + if (handler != null) + { + handler(this, e); + } + } + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/Standard/ShellProvider.cs b/Microsoft.Windows.Shell/Standard/ShellProvider.cs index 9738615..520e0b6 100644 --- a/Microsoft.Windows.Shell/Standard/ShellProvider.cs +++ b/Microsoft.Windows.Shell/Standard/ShellProvider.cs @@ -1,10 +1,7 @@ -/**************************************************************************\ - Copyright Microsoft Corporation. All Rights Reserved. -\**************************************************************************/ - -namespace Standard +namespace Standard { using System; + using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; using System.Text; @@ -13,6 +10,73 @@ namespace Standard #region Enums and Static Property Classes + /// ASSOCIATIONLEVEL, AL_* + internal enum AL + { + MACHINE, + EFFECTIVE, + USER, + } + + /// ASSOCIATIONTYPE, AT_* + internal enum AT + { + FILEEXTENSION, + URLPROTOCOL, + STARTMENUCLIENT, + MIMETYPE, + } + + /// FileDialog AddPlace options. FDAP_* + internal enum FDAP : uint + { + BOTTOM = 0x00000000, + TOP = 0x00000001, + } + + /// IFileDialog options. FOS_* + [Flags] + internal enum FOS : uint + { + OVERWRITEPROMPT = 0x00000002, + STRICTFILETYPES = 0x00000004, + NOCHANGEDIR = 0x00000008, + PICKFOLDERS = 0x00000020, + FORCEFILESYSTEM = 0x00000040, + ALLNONSTORAGEITEMS = 0x00000080, + NOVALIDATE = 0x00000100, + ALLOWMULTISELECT = 0x00000200, + PATHMUSTEXIST = 0x00000800, + FILEMUSTEXIST = 0x00001000, + CREATEPROMPT = 0x00002000, + SHAREAWARE = 0x00004000, + NOREADONLYRETURN = 0x00008000, + NOTESTFILECREATE = 0x00010000, + HIDEMRUPLACES = 0x00020000, + HIDEPINNEDPLACES = 0x00040000, + NODEREFERENCELINKS = 0x00100000, + DONTADDTORECENT = 0x02000000, + FORCESHOWHIDDEN = 0x10000000, + DEFAULTNOMINIMODE = 0x20000000, + FORCEPREVIEWPANEON = 0x40000000, + } + + /// FDE_OVERWRITE_RESPONSE. FDEOR_* + internal enum FDEOR + { + DEFAULT = 0x00000000, + ACCEPT = 0x00000001, + REFUSE = 0x00000002, + } + + /// FDE_SHAREVIOLATION_RESPONSE. FDESVR_* + internal enum FDESVR + { + DEFAULT = 0x00000000, + ACCEPT = 0x00000001, + REFUSE = 0x00000002, + } + /// ShellItem attribute flags. SIATTRIBFLAGS_* internal enum SIATTRIBFLAGS { @@ -316,6 +380,16 @@ internal static class STR_GPS #region Structs + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct COMDLG_FILTERSPEC + { + [MarshalAs(UnmanagedType.LPWStr)] + public string pszName; + [MarshalAs(UnmanagedType.LPWStr)] + public string pszSpec; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)] internal struct THUMBBUTTON { @@ -366,6 +440,42 @@ public PKEY(Guid fmtid, uint pid) #region Interfaces + // Application File Extension and URL Protocol Registration + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ApplicationAssociationRegistration), + ] + internal interface IApplicationAssociationRegistration + { + [return: MarshalAs(UnmanagedType.LPWStr)] + string QueryCurrentDefault( + [MarshalAs(UnmanagedType.LPWStr)] string pszQuery, + AT atQueryType, + AL alQueryLevel); + + [return: MarshalAs(UnmanagedType.Bool)] + bool QueryAppIsDefault( + [MarshalAs(UnmanagedType.LPWStr)] string pszQuery, + AT atQueryType, + AL alQueryLevel, + [MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName); + + [return: MarshalAs(UnmanagedType.Bool)] + bool QueryAppIsDefaultAll( + AL alQueryLevel, + [MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName); + + void SetAppAsDefault( + [MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName, + [MarshalAs(UnmanagedType.LPWStr)] string pszSet, + AT atSetType); + + void SetAppAsDefaultAll([MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName); + + void ClearUserAssociations(); + } + [ ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), @@ -963,5 +1073,237 @@ internal interface ITaskbarList4 : ITaskbarList3 void SetTabProperties(IntPtr hwndTab, STPF stpFlags); } + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.FileDialogEvents), +] + internal interface IFileDialogEvents + { + [PreserveSig] + HRESULT OnFileOk(IFileDialog pfd); + + [PreserveSig] + HRESULT OnFolderChanging(IFileDialog pfd, IShellItem psiFolder); + + [PreserveSig] + HRESULT OnFolderChange(IFileDialog pfd); + + [PreserveSig] + HRESULT OnSelectionChange(IFileDialog pfd); + + [PreserveSig] + HRESULT OnShareViolation(IFileDialog pfd, IShellItem psi, out FDESVR pResponse); + + [PreserveSig] + HRESULT OnTypeChange(IFileDialog pfd); + + [PreserveSig] + HRESULT OnOverwrite(IFileDialog pfd, IShellItem psi, out FDEOR pResponse); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ModalWindow), + ] + internal interface IModalWindow + { + [PreserveSig] + HRESULT Show(IntPtr parent); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.FileDialog), + ] + internal interface IFileDialog : IModalWindow + { + #region IModalWindow redeclarations + [PreserveSig] + new HRESULT Show(IntPtr parent); + #endregion + + void SetFileTypes(uint cFileTypes, [In] ref COMDLG_FILTERSPEC rgFilterSpec); + + void SetFileTypeIndex(uint iFileType); + + uint GetFileTypeIndex(); + + uint Advise(IFileDialogEvents pfde); + + void Unadvise(uint dwCookie); + + void SetOptions(FOS fos); + + FOS GetOptions(); + + void SetDefaultFolder(IShellItem psi); + + void SetFolder(IShellItem psi); + + IShellItem GetFolder(); + + IShellItem GetCurrentSelection(); + + void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName); + + [return: MarshalAs(UnmanagedType.LPWStr)] + string GetFileName(); + + void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle); + + void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText); + + void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel); + + IShellItem GetResult(); + + void AddPlace(IShellItem psi, FDAP alignment); + + void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); + + void Close([MarshalAs(UnmanagedType.Error)] int hr); + + void SetClientGuid([In] ref Guid guid); + + void ClearClientData(); + + void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.FileOpenDialog), + ] + internal interface IFileOpenDialog : IFileDialog + { + #region IFileDialog redeclarations + + #region IModalDialog redeclarations + [PreserveSig] + new HRESULT Show(IntPtr parent); + #endregion + + new void SetFileTypes(uint cFileTypes, [In] ref COMDLG_FILTERSPEC rgFilterSpec); + new void SetFileTypeIndex(uint iFileType); + new uint GetFileTypeIndex(); + new uint Advise(IFileDialogEvents pfde); + new void Unadvise(uint dwCookie); + new void SetOptions(FOS fos); + new FOS GetOptions(); + new void SetDefaultFolder(IShellItem psi); + new void SetFolder(IShellItem psi); + new IShellItem GetFolder(); + new IShellItem GetCurrentSelection(); + new void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName); + [return: MarshalAs(UnmanagedType.LPWStr)] + new string GetFileName(); + new void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle); + new void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText); + new void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel); + new IShellItem GetResult(); + new void AddPlace(IShellItem psi, FDAP fdcp); + new void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); + new void Close([MarshalAs(UnmanagedType.Error)] int hr); + new void SetClientGuid([In] ref Guid guid); + new void ClearClientData(); + new void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter); + + #endregion + + IShellItemArray GetResults(); + + IShellItemArray GetSelectedItems(); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.FileSaveDialog), + ] + internal interface IFileSaveDialog : IFileDialog + { + #region IFileDialog redeclarations + + #region IModalDialog redeclarations + [PreserveSig] + new HRESULT Show(IntPtr parent); + #endregion + + new void SetFileTypes(uint cFileTypes, [In] ref COMDLG_FILTERSPEC rgFilterSpec); + new void SetFileTypeIndex(uint iFileType); + new uint GetFileTypeIndex(); + new uint Advise(IFileDialogEvents pfde); + new void Unadvise(uint dwCookie); + new void SetOptions(FOS fos); + new FOS GetOptions(); + new void SetDefaultFolder(IShellItem psi); + new void SetFolder(IShellItem psi); + new IShellItem GetFolder(); + new IShellItem GetCurrentSelection(); + new void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName); + [return: MarshalAs(UnmanagedType.LPWStr)] + new string GetFileName(); + new void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle); + new void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText); + new void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel); + new IShellItem GetResult(); + new void AddPlace(IShellItem psi, FDAP fdcp); + new void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); + new void Close([MarshalAs(UnmanagedType.Error)] int hr); + new void SetClientGuid([In] ref Guid guid); + new void ClearClientData(); + new void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter); + + #endregion + + void SetSaveAsItem(IShellItem psi); + + void SetProperties([In, MarshalAs(UnmanagedType.Interface)] object pStore); + + void SetCollectedProperties([In, MarshalAs(UnmanagedType.Interface)] object pList, [In] int fAppendDefault); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetProperties(); + + void ApplyProperties(IShellItem psi, [MarshalAs(UnmanagedType.Interface)] object pStore, [In] ref IntPtr hwnd, [MarshalAs(UnmanagedType.Interface)] object pSink); + } + + internal static class ShellUtil + { + public static string GetPathFromShellItem(IShellItem item) + { + return item.GetDisplayName(SIGDN.DESKTOPABSOLUTEPARSING); + } + + public static IShellItem2 GetShellItemForPath(string path) + { + if (string.IsNullOrEmpty(path)) + { + // Internal function. Should have verified this before calling if we cared. + return null; + } + + Guid iidShellItem2 = new Guid(IID.ShellItem2); + object unk; + HRESULT hr = NativeMethods.SHCreateItemFromParsingName(path, null, ref iidShellItem2, out unk); + + // Silently absorb errors such as ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND. + // Let others pass through + if (hr == (HRESULT)Win32Error.ERROR_FILE_NOT_FOUND || hr == (HRESULT)Win32Error.ERROR_PATH_NOT_FOUND) + { + hr = HRESULT.S_OK; + unk = null; + } + + hr.ThrowIfFailed(); + + return (IShellItem2)unk; + } + } + #endregion } diff --git a/Microsoft.Windows.Shell/Standard/SmallString.cs b/Microsoft.Windows.Shell/Standard/SmallString.cs new file mode 100644 index 0000000..7c2853e --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/SmallString.cs @@ -0,0 +1,253 @@ + +namespace Standard +{ + using System; + + [System.Diagnostics.DebuggerDisplay("SmallString: { GetString() }")] + internal struct SmallString : IEquatable, IComparable + { + [Flags] + private enum _SmallFlags : byte + { + None = 0, + IsInt64 = 1, + HasHashCode = 2, + Reserved = 4, + } + + private static readonly System.Text.UTF8Encoding s_Encoder = new System.Text.UTF8Encoding(false /* do not emit BOM */, true /* throw on error */); + private readonly byte[] _encodedBytes; + private _SmallFlags _flags; + private int _cachedHashCode; + + public SmallString(string value, bool precacheHashCode = false) + { + _flags = _SmallFlags.None; + _cachedHashCode = 0; + + if (!string.IsNullOrEmpty(value)) + { + if (precacheHashCode) + { + _flags |= _SmallFlags.HasHashCode; + _cachedHashCode = value.GetHashCode(); + } + + long numValue; + if (long.TryParse(value, System.Globalization.NumberStyles.None, null, out numValue)) + { + _flags |= _SmallFlags.IsInt64; + _encodedBytes = BitConverter.GetBytes(numValue); + + // It's possible that this doesn't round trip with full fidelity. + // If this assert ever gets hit, consider adding an overload that opts + // out of this optimization. + // (Note that the parameters are not evaluated on retail builds) + Assert.AreEqual(this.GetString(), value); + + return; + } + + _encodedBytes = s_Encoder.GetBytes(value); + Assert.IsNotNull(_encodedBytes); + } + else + { + _encodedBytes = null; + } + } + + private bool _IsInt64 + { + get { return (_flags & _SmallFlags.IsInt64) == _SmallFlags.IsInt64; } + } + + private bool _HasCachedHashCode + { + get { return (_flags & _SmallFlags.HasHashCode) == _SmallFlags.HasHashCode; } + } + + #region Object Overrides + + public override string ToString() + { + Assert.Fail(); + throw new NotSupportedException("This exception exists to prevent accidental performance penalties. Call GetString() instead."); + } + + public override int GetHashCode() + { + if (_encodedBytes == null) + { + return 0; + } + + if (!_HasCachedHashCode) + { + // Intentionally hashes similarly to the expanded strings. + _cachedHashCode = GetString().GetHashCode(); + _flags |= _SmallFlags.HasHashCode; + } + + return _cachedHashCode; + } + + public override bool Equals(object obj) + { + try + { + return Equals((SmallString)obj); + } + catch (InvalidCastException) + { + return false; + } + } + + #endregion + + #region IEquatable Members + + public bool Equals(SmallString other) + { + if (_encodedBytes == null) + { + return other._encodedBytes == null; + } + + if (other._encodedBytes == null) + { + return false; + } + + if (_encodedBytes.Length != other._encodedBytes.Length) + { + return false; + } + + // If only one is a number, then they're not equal. + if (((_flags ^ other._flags) & _SmallFlags.IsInt64) == _SmallFlags.IsInt64) + { + return false; + } + + if (_HasCachedHashCode && other._HasCachedHashCode) + { + if (_cachedHashCode != other._cachedHashCode) + { + return false; + } + } + + if (_IsInt64) + { + return BitConverter.ToInt64(_encodedBytes, 0) == BitConverter.ToInt64(other._encodedBytes, 0); + } + + // Note that this is doing a literal binary comparison of the two strings. + // It's possible for two real strings to compare equally even though they + // can be encoded in different ways with UTF8. + return Utility.MemCmp(_encodedBytes, other._encodedBytes, _encodedBytes.Length); + } + + #endregion + + public string GetString() + { + if (_encodedBytes == null) + { + return ""; + } + + if (_IsInt64) + { + return BitConverter.ToInt64(_encodedBytes, 0).ToString(); + } + + return s_Encoder.GetString(_encodedBytes); + } + + public static bool operator==(SmallString left, SmallString right) + { + return left.Equals(right); + } + + public static bool operator!=(SmallString left, SmallString right) + { + return !left.Equals(right); + } + + #region IComparable Members + + public int CompareTo(SmallString other) + { + // If either of the strings contains multibyte characters + // then we can't do a strictly bitwise comparison. + // We can look for a signaled high-bit in the byte to detect this. + // Opportunistically, we're going to assume that the strings are + // ASCII compatible until we find out they aren't. + + if (_encodedBytes == null) + { + if (other._encodedBytes == null) + { + return 0; + } + Assert.AreNotEqual(0, other._encodedBytes.Length); + return -1; + } + else if (other._encodedBytes == null) + { + Assert.AreNotEqual(0, _encodedBytes.Length); + return 1; + } + + bool? isThisStringShorter = null; + int cb = _encodedBytes.Length; + int cbDiffernce = other._encodedBytes.Length - cb; + + if (cbDiffernce < 0) + { + isThisStringShorter = false; + cb = other._encodedBytes.Length; + } + else if (cbDiffernce > 0) + { + isThisStringShorter = true; + } + + for (int i = 0; i < cb; ++i) + { + bool isEitherHighBitSet = ((_encodedBytes[i] | other._encodedBytes[i]) & 0x80) != 0; + // If the byte array contains multibyte characters + // we need to do a real string comparison. + if (isEitherHighBitSet) + { + string left = this.GetString(); + string right = other.GetString(); + + return left.CompareTo(right); + } + + if (_encodedBytes[i] != other._encodedBytes[i]) + { + return _encodedBytes[i] - other._encodedBytes[i]; + } + } + + if (isThisStringShorter == null) + { + return 0; + } + + if (isThisStringShorter == false) + { + return -1; + } + + return 1; + } + + #endregion + } +} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/Standard/SmallUri.cs b/Microsoft.Windows.Shell/Standard/SmallUri.cs new file mode 100644 index 0000000..4a3c350 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/SmallUri.cs @@ -0,0 +1,151 @@ + +namespace Standard +{ + using System; + using System.Diagnostics; + using System.Text; + + [DebuggerDisplay("SmallUri: { GetUri() }")] + internal struct SmallUri : IEquatable + { + private static readonly UTF8Encoding s_Encoder = new UTF8Encoding(false /* do not emit BOM */, true /* throw on error */); + private readonly byte[] _utf8String; + private readonly bool _isHttp; + + public SmallUri(Uri value) + { + _isHttp = false; + _utf8String = null; + + if (value == null) + { + return; + } + + if (!value.IsAbsoluteUri) + { + throw new ArgumentException("The parameter is not a valid absolute uri", "value"); + } + + string strValue = value.OriginalString; + if (strValue.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) + { + _isHttp = true; + strValue = strValue.Substring(7); + } + + _utf8String = s_Encoder.GetBytes(strValue); + Assert.IsNotNull(_utf8String); + } + + public SmallUri(string value) + { + _isHttp = false; + _utf8String = null; + + if (string.IsNullOrEmpty(value)) + { + return; + } + + if (!Uri.IsWellFormedUriString(value, UriKind.Absolute)) + { + throw new ArgumentException("The parameter is not a valid uri", "value"); + } + + if (value.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) + { + _isHttp = true; + value = value.Substring(7); + } + + _utf8String = s_Encoder.GetBytes(value); + Assert.IsNotNull(_utf8String); + } + + #region Object Overrides + + public override string ToString() + { + Assert.Fail(); + throw new NotSupportedException("This exception exists to prevent accidental performance penalties. Call GetString() instead."); + } + + public override int GetHashCode() + { + // Intentionally hashes similarly to the expanded strings. + return GetString().GetHashCode(); + } + + public override bool Equals(object obj) + { + try + { + return Equals((SmallUri)obj); + } + catch (InvalidCastException) + { + return false; + } + } + + #endregion + + #region IEquatable Members + + public bool Equals(SmallUri other) + { + if (_utf8String == null) + { + return other._utf8String == null; + } + + if (other._utf8String == null) + { + return false; + } + + if (_isHttp != other._isHttp) + { + return false; + } + + if (_utf8String.Length != other._utf8String.Length) + { + return false; + } + + return Utility.MemCmp(_utf8String, other._utf8String, _utf8String.Length); + } + + #endregion + + public string GetString() + { + if (_utf8String == null) + { + return ""; + } + return GetUri().ToString(); + } + + public Uri GetUri() + { + if (_utf8String == null) + { + return null; + } + return new Uri((_isHttp ? "http://" : "") + s_Encoder.GetString(_utf8String), UriKind.Absolute); + } + + public static bool operator ==(SmallUri left, SmallUri right) + { + return left.Equals(right); + } + + public static bool operator !=(SmallUri left, SmallUri right) + { + return !left.Equals(right); + } + } +} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/Standard/Standard.csproj b/Microsoft.Windows.Shell/Standard/Standard.csproj new file mode 100644 index 0000000..fba179b --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/Standard.csproj @@ -0,0 +1,162 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {A1326555-AD64-4A93-A95C-B68ABD5672D4} + Library + Properties + Standard + Standard + v4.0 + 512 + + + + + + + + + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + true + GlobalSuppressions.cs + prompt + true + AllRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + + + + 3.0 + + + 3.0 + + + + 3.5 + + + + 3.5 + + + 3.5 + + + + + 3.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/Microsoft.Windows.Shell/Standard/StreamHelper.cs b/Microsoft.Windows.Shell/Standard/StreamHelper.cs index a5d0355..2885963 100644 --- a/Microsoft.Windows.Shell/Standard/StreamHelper.cs +++ b/Microsoft.Windows.Shell/Standard/StreamHelper.cs @@ -1,6 +1,9 @@ -/**************************************************************************\ - Copyright Microsoft Corporation. All Rights Reserved. -\**************************************************************************/ +// The ComStream class is used for the contact property types. +// The types can have unexpected behavior if they're changed by callers, +// so this provides an immutable stream implementation. +// The volatile functions are implemented (not tested) +// in case a separate ReadonlyStream needs to be implemented. +//#define FEATURE_MUTABLE_COM_STREAMS namespace Standard { @@ -13,6 +16,191 @@ namespace Standard // disambiguate with System.Runtime.InteropServices.STATSTG using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG; + // This is adapted from Microsoft KB article 321340 + /// + /// Wraps an IStream interface pointer from COM into a form consumable by .Net. + /// + /// + /// This implementation is immutable, though it's possible that the underlying + /// stream can be changed in another context. + /// + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + internal sealed class ComStream : Stream + { + private const int STATFLAG_NONAME = 1; + + private IStream _source; + + private void _Validate() + { + if (null == _source) + { + throw new ObjectDisposedException("this"); + } + } + + /// + /// Wraps a native IStream interface into a CLR Stream subclass. + /// + /// + /// The stream that this object wraps. + /// + /// + /// Note that the parameter is passed by ref. On successful creation it is + /// zeroed out to the caller. This object becomes responsible for the lifetime + /// management of the wrapped IStream. + /// + public ComStream(ref IStream stream) + { + Verify.IsNotNull(stream, "stream"); + _source = stream; + // Zero out caller's reference to this. The object now owns the memory. + stream = null; + } + + #region Overridden Stream Methods + + // Experimentally, the base class seems to deal with the IDisposable pattern. + // Overridden implementations aren't called, but Close is as part of the Dispose call. + public override void Close() + { + if (null != _source) + { +#if FEATURE_MUTABLE_COM_STREAMS + Flush(); +#endif + Utility.SafeRelease(ref _source); + } + } + + public override bool CanRead + { + get + { + // For the context of this class, this should be true... + return true; + } + } + + public override bool CanSeek + { + get + { + // This should be true... + return true; + } + } + + public override bool CanWrite + { + get + { +#if FEATURE_MUTABLE_COM_STREAMS + // Really don't know that this is true... + return true; +#endif + return false; + } + } + + public override void Flush() + { +#if FEATURE_MUTABLE_COM_STREAMS + _Validate(); + // Don't have enough context of the underlying object to reliably do anything here. + try + { + _source.Commit(STGC_DEFAULT); + } + catch { } +#endif + } + + public override long Length + { + get + { + _Validate(); + + STATSTG statstg; + _source.Stat(out statstg, STATFLAG_NONAME); + return statstg.cbSize; + } + } + + public override long Position + { + get { return Seek(0, SeekOrigin.Current); } + set { Seek(value, SeekOrigin.Begin); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + _Validate(); + + IntPtr pcbRead = IntPtr.Zero; + + try + { + pcbRead = Marshal.AllocHGlobal(sizeof(Int32)); + + // PERFORMANCE NOTE: This buffer doesn't need to be allocated if offset == 0 + var tempBuffer = new byte[count]; + _source.Read(tempBuffer, count, pcbRead); + Array.Copy(tempBuffer, 0, buffer, offset, Marshal.ReadInt32(pcbRead)); + + return Marshal.ReadInt32(pcbRead); + } + finally + { + Utility.SafeFreeHGlobal(ref pcbRead); + } + } + + public override long Seek(long offset, SeekOrigin origin) + { + _Validate(); + + IntPtr plibNewPosition = IntPtr.Zero; + + try + { + plibNewPosition = Marshal.AllocHGlobal(sizeof(Int64)); + _source.Seek(offset, (int)origin, plibNewPosition); + + return Marshal.ReadInt64(plibNewPosition); + } + finally + { + Utility.SafeFreeHGlobal(ref plibNewPosition); + } + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); +#if FEATURE_MUTABLE_COM_STREAMS + _Validate(); + _source.SetSize(value); +#endif + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); +#if FEATURE_MUTABLE_COM_STREAMS + _Validate(); + + // PERFORMANCE NOTE: This buffer doesn't need to be allocated if offset == 0 + byte[] tempBuffer = new byte[buffer.Length - offset]; + Array.Copy(buffer, offset, tempBuffer, 0, tempBuffer.Length); + _source.Write(tempBuffer, tempBuffer.Length, IntPtr.Zero); +#endif + } + + #endregion + } + // All these methods return void. Does the standard marshaller convert them to HRESULTs? /// /// Wraps a managed stream instance into an interface pointer consumable by COM. @@ -338,4 +526,188 @@ public void Dispose() #endregion } + +#if CONSIDER_ADDING + /// + /// Wraps an existing stream in a read-only interface. The stream can still be modified externally. + /// + public class ReadonlyStream : Stream + { + private Stream _stream; + + public ReadonlyStream(Stream source) + { + Verify.IsNotNull(source, "source"); + _stream = source; + } + + public override bool CanRead + { + get + { + return _stream.CanRead; + } + } + + public override bool CanSeek + { + get + { + return _stream.CanSeek; + } + } + + public override bool CanWrite + { + get + { + return false; + } + } + + public override void Flush() { } + + public override long Length + { + get + { + return _stream.Length; + } + } + + public override long Position + { + get + { + return _stream.Position; + } + set + { + _stream.Position = value; + } + } + + public override int Read(byte[] buffer, int offset, int count) + { + return _stream.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return _stream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + throw new NotSupportedException("The stream doesn't support modifications."); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException("The stream doesn't support modifications."); + } + + public override void Close() + { + base.Close(); + } + } + + /// + /// Wraps a string to provide read-only Stream semantics. + /// + public class StringStream : Stream + { + private string _source; + private int _position; + + public StringStream(string source) + { + _source = source; + _position = 0; + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return true; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length + { + get { return _source.Length * 2; } + } + + public override long Position + { + get + { + return _position; + } + set + { + Validate.BoundedInteger(0, (int)value, (int)Length + 1, "value"); + _position = (int)value; + } + } + + public override int Read(byte[] buffer, int offset, int count) + { + int cbRead = 0; + for (; cbRead < count; ++cbRead) + { + if (Length <= Position) + { + break; + } + buffer[offset + cbRead] = (byte)(0xFF & (_source[(int)Position / 2] >> ((0 == Position % 2) ? 0 : 8))); + ++Position; + } + return cbRead; + } + + public override long Seek(long offset, SeekOrigin origin) + { + switch (origin) + { + case SeekOrigin.Begin: + Position = offset; + break; + case SeekOrigin.Current: + Position += offset; + break; + case SeekOrigin.End: + Position = Length + offset; + break; + default: + throw new FormatException("Bad value for origin"); + } + return Position; + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + } +#endif } diff --git a/Microsoft.Windows.Shell/Standard/Utilities.cs b/Microsoft.Windows.Shell/Standard/Utilities.cs index af68855..6791f68 100644 --- a/Microsoft.Windows.Shell/Standard/Utilities.cs +++ b/Microsoft.Windows.Shell/Standard/Utilities.cs @@ -1,7 +1,3 @@ -/**************************************************************************\ - Copyright Microsoft Corporation. All Rights Reserved. -\**************************************************************************/ - // This file contains general utilities to aid in development. // Classes here generally shouldn't be exposed publicly since // they're not particular to any library functionality. @@ -15,18 +11,23 @@ namespace Standard using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; + using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.Text; - using System.Windows; - using System.Windows.Media; - using System.Windows.Media.Imaging; + + internal enum SafeCopyFileOptions + { + PreserveOriginal, + Overwrite, + FindBetterName, + } internal static partial class Utility { private static readonly Version _osVersion = Environment.OSVersion.Version; - private static readonly Version _presentationFrameworkVersion = Assembly.GetAssembly(typeof(Window)).GetName().Version; + private static readonly Random _randomNumberGenerator = new Random(); [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] private static bool _MemCmp(IntPtr left, IntPtr right, long cb) @@ -58,27 +59,74 @@ private static bool _MemCmp(IntPtr left, IntPtr right, long cb) return true; } - /// The native RGB macro. - /// - /// [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static int RGB(Color c) + public static Exception FailableFunction(Func function, out T result) { - return c.R | (c.G << 8) | (c.B << 16); + return FailableFunction(5, function, out result); } - /// Convert a native integer that represent a color with an alpha channel into a Color struct. - /// The integer that represents the color. Its bits are of the format 0xAARRGGBB. - /// A Color representation of the parameter. - public static Color ColorFromArgbDword(uint color) + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static T FailableFunction(Func function) { - return Color.FromArgb( - (byte)((color & 0xFF000000) >> 24), - (byte)((color & 0x00FF0000) >> 16), - (byte)((color & 0x0000FF00) >> 8), - (byte)((color & 0x000000FF) >> 0)); + T result; + Exception e = FailableFunction(function, out result); + if (e != null) + { + throw e; + } + return result; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static T FailableFunction(int maxRetries, Func function) + { + T result; + Exception e = FailableFunction(maxRetries, function, out result); + if (e != null) + { + throw e; + } + return result; + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Exception FailableFunction(int maxRetries, Func function, out T result) + { + Assert.IsNotNull(function); + Assert.BoundedInteger(1, maxRetries, 100); + int i = 0; + while (true) + { + try + { + result = function(); + return null; + } + catch (Exception e) + { + if (i == maxRetries) + { + result = default(T); + return e; + } + } + ++i; + } } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string GetHashString(string value) + { + using (MD5 md5 = MD5.Create()) + { + byte[] signatureHash = md5.ComputeHash(Encoding.UTF8.GetBytes(value)); + string signature = signatureHash.Aggregate( + new StringBuilder(), + (sb, b) => sb.Append(b.ToString("x2", CultureInfo.InvariantCulture))).ToString(); + return signature; + } + } [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static int GET_X_LPARAM(IntPtr lParam) @@ -235,6 +283,16 @@ public static bool IsFlagSet(ulong value, ulong mask) return 0 != (value & mask); } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsInterfaceImplemented(Type objectType, Type interfaceType) + { + Assert.IsNotNull(objectType); + Assert.IsNotNull(interfaceType); + Assert.IsTrue(interfaceType.IsInterface); + + return objectType.GetInterfaces().Any(type => type == interfaceType); + } + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static bool IsOSVistaOrNewer { @@ -248,188 +306,41 @@ public static bool IsOSWindows7OrNewer } /// - /// Is this using WPF4? + /// Wrapper around File.Copy to provide feedback as to whether the file wasn't copied because it didn't exist. /// - /// - /// There are a few specific bugs in Window in 3.5SP1 and below that require workarounds - /// when handling WM_NCCALCSIZE on the HWND. - /// - public static bool IsPresentationFrameworkVersionLessThan4 - { - get { return _presentationFrameworkVersion < new Version(4, 0); } - } - - // Caller is responsible for destroying the HICON - // Caller is responsible to ensure that GDI+ has been initialized. - [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")] - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static IntPtr GenerateHICON(ImageSource image, Size dimensions) + /// + /// + /// + /// + public static string SafeCopyFile(string sourceFileName, string destFileName, SafeCopyFileOptions options) { - if (image == null) - { - return IntPtr.Zero; - } - - // If we're getting this from a ".ico" resource, then it comes through as a BitmapFrame. - // We can use leverage this as a shortcut to get the right 16x16 representation - // because DrawImage doesn't do that for us. - var bf = image as BitmapFrame; - if (bf != null) - { - bf = GetBestMatch(bf.Decoder.Frames, (int)dimensions.Width, (int)dimensions.Height); - } - else + switch (options) { - // Constrain the dimensions based on the aspect ratio. - var drawingDimensions = new Rect(0, 0, dimensions.Width, dimensions.Height); - - // There's no reason to assume that the requested image dimensions are square. - double renderRatio = dimensions.Width / dimensions.Height; - double aspectRatio = image.Width / image.Height; - - // If it's smaller than the requested size, then place it in the middle and pad the image. - if (image.Width <= dimensions.Width && image.Height <= dimensions.Height) - { - drawingDimensions = new Rect((dimensions.Width - image.Width) / 2, (dimensions.Height - image.Height) / 2, image.Width, image.Height); - } - else if (renderRatio > aspectRatio) - { - double scaledRenderWidth = (image.Width / image.Height) * dimensions.Width; - drawingDimensions = new Rect((dimensions.Width - scaledRenderWidth) / 2, 0, scaledRenderWidth, dimensions.Height); - } - else if (renderRatio < aspectRatio) - { - double scaledRenderHeight = (image.Height / image.Width) * dimensions.Height; - drawingDimensions = new Rect(0, (dimensions.Height - scaledRenderHeight) / 2, dimensions.Width, scaledRenderHeight); - } - - var dv = new DrawingVisual(); - DrawingContext dc = dv.RenderOpen(); - dc.DrawImage(image, drawingDimensions); - dc.Close(); - - var bmp = new RenderTargetBitmap((int)dimensions.Width, (int)dimensions.Height, 96, 96, PixelFormats.Pbgra32); - bmp.Render(dv); - bf = BitmapFrame.Create(bmp); - } - - // Using GDI+ to convert to an HICON. - // I'd rather not duplicate their code. - using (MemoryStream memstm = new MemoryStream()) - { - BitmapEncoder enc = new PngBitmapEncoder(); - enc.Frames.Add(bf); - enc.Save(memstm); - - using (var istm = new ManagedIStream(memstm)) - { - // We are not bubbling out GDI+ errors when creating the native image fails. - IntPtr bitmap = IntPtr.Zero; - try + case SafeCopyFileOptions.PreserveOriginal: + if (!File.Exists(destFileName)) { - Status gpStatus = NativeMethods.GdipCreateBitmapFromStream(istm, out bitmap); - if (Status.Ok != gpStatus) - { - return IntPtr.Zero; - } - - IntPtr hicon; - gpStatus = NativeMethods.GdipCreateHICONFromBitmap(bitmap, out hicon); - if (Status.Ok != gpStatus) - { - return IntPtr.Zero; - } - - // Caller is responsible for freeing this. - return hicon; + File.Copy(sourceFileName, destFileName); + return destFileName; } - finally + return null; + case SafeCopyFileOptions.Overwrite: + File.Copy(sourceFileName, destFileName, true); + return destFileName; + case SafeCopyFileOptions.FindBetterName: + string directoryPart = Path.GetDirectoryName(destFileName); + string fileNamePart = Path.GetFileNameWithoutExtension(destFileName); + string extensionPart = Path.GetExtension(destFileName); + foreach (string path in GenerateFileNames(directoryPart, fileNamePart, extensionPart)) { - Utility.SafeDisposeImage(ref bitmap); - } - } - } - } - - public static BitmapFrame GetBestMatch(IList frames, int width, int height) - { - return _GetBestMatch(frames, _GetBitDepth(), width, height); - } - - private static int _MatchImage(BitmapFrame frame, int bitDepth, int width, int height, int bpp) - { - int score = 2 * _WeightedAbs(bpp, bitDepth, false) + - _WeightedAbs(frame.PixelWidth, width, true) + - _WeightedAbs(frame.PixelHeight, height, true); - - return score; - } - - private static int _WeightedAbs(int valueHave, int valueWant, bool fPunish) - { - int diff = (valueHave - valueWant); - - if (diff < 0) - { - diff = (fPunish ? -2 : -1) * diff; - } - - return diff; - } - - /// From a list of BitmapFrames find the one that best matches the requested dimensions. - /// The methods used here are copied from Win32 sources. We want to be consistent with - /// system behaviors. - private static BitmapFrame _GetBestMatch(IList frames, int bitDepth, int width, int height) - { - int bestScore = int.MaxValue; - int bestBpp = 0; - int bestIndex = 0; - - bool isBitmapIconDecoder = frames[0].Decoder is IconBitmapDecoder; - - for (int i = 0; i < frames.Count && bestScore != 0; ++i) - { - int currentIconBitDepth = isBitmapIconDecoder ? frames[i].Thumbnail.Format.BitsPerPixel : frames[i].Format.BitsPerPixel; - - if (currentIconBitDepth == 0) - { - currentIconBitDepth = 8; - } - - int score = _MatchImage(frames[i], bitDepth, width, height, currentIconBitDepth); - if (score < bestScore) - { - bestIndex = i; - bestBpp = currentIconBitDepth; - bestScore = score; - } - else if (score == bestScore) - { - // Tie breaker: choose the higher color depth. If that fails, choose first one. - if (bestBpp < currentIconBitDepth) - { - bestIndex = i; - bestBpp = currentIconBitDepth; + if (!File.Exists(path)) + { + File.Copy(sourceFileName, path); + return path; + } } - } + return null; } - - return frames[bestIndex]; - } - - // This can be cached. It's not going to change under reasonable circumstances. - private static int s_bitDepth; // = 0; - private static int _GetBitDepth() - { - if (s_bitDepth == 0) - { - using (SafeDC dc = SafeDC.GetDesktop()) - { - s_bitDepth = NativeMethods.GetDeviceCaps(dc, DeviceCap.BITSPIXEL) * NativeMethods.GetDeviceCaps(dc, DeviceCap.PLANES); - } - } - return s_bitDepth; + throw new ArgumentException("Invalid enumeration value", "options"); } /// @@ -445,31 +356,30 @@ public static void SafeDeleteFile(string path) { if (!string.IsNullOrEmpty(path)) { - File.Delete(path); } } - /// GDI's DeleteObject [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SafeDeleteObject(ref IntPtr gdiObject) + public static void SafeDestroyIcon(ref IntPtr hicon) { - IntPtr p = gdiObject; - gdiObject = IntPtr.Zero; + IntPtr p = hicon; + hicon = IntPtr.Zero; if (IntPtr.Zero != p) { - NativeMethods.DeleteObject(p); + NativeMethods.DestroyIcon(p); } } + /// GDI's DeleteObject [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SafeDestroyIcon(ref IntPtr hicon) + public static void SafeDeleteObject(ref IntPtr gdiObject) { - IntPtr p = hicon; - hicon = IntPtr.Zero; + IntPtr p = gdiObject; + gdiObject = IntPtr.Zero; if (IntPtr.Zero != p) { - NativeMethods.DestroyIcon(p); + NativeMethods.DeleteObject(p); } } @@ -660,9 +570,16 @@ public static string HashStreamMD5(Stream stm) [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public static void EnsureDirectory(string path) { - if (!Directory.Exists(Path.GetDirectoryName(path))) + if (!path.EndsWith(@"\")) + { + path += @"\"; + } + + path = Path.GetDirectoryName(path); + + if (!Directory.Exists(path)) { - Directory.CreateDirectory(Path.GetDirectoryName(path)); + Directory.CreateDirectory(path); } } @@ -944,94 +861,61 @@ private static int _HexToInt(char h) return -1; } - public static void AddDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener) - { - if (component == null) - { - return; - } - Assert.IsNotNull(property); - Assert.IsNotNull(listener); - - DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType()); - dpd.AddValueChanged(component, listener); - } - - public static void RemoveDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener) - { - if (component == null) - { - return; - } - Assert.IsNotNull(property); - Assert.IsNotNull(listener); - - DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType()); - dpd.RemoveValueChanged(component, listener); - } - - #region Extension Methods - - public static bool IsThicknessNonNegative(Thickness thickness) + public static string MakeValidFileName(string invalidPath) { - if (!IsDoubleFiniteAndNonNegative(thickness.Top)) - { - return false; - } - - if (!IsDoubleFiniteAndNonNegative(thickness.Left)) - { - return false; - } - - if (!IsDoubleFiniteAndNonNegative(thickness.Bottom)) - { - return false; - } - - if (!IsDoubleFiniteAndNonNegative(thickness.Right)) - { - return false; - } - - return true; + return invalidPath + .Replace('\\', '_') + .Replace('/', '_') + .Replace(':', '_') + .Replace('*', '_') + .Replace('?', '_') + .Replace('\"', '_') + .Replace('<', '_') + .Replace('>', '_') + .Replace('|', '_'); } - public static bool IsCornerRadiusValid(CornerRadius cornerRadius) + public static IEnumerable GenerateFileNames(string directory, string primaryFileName, string extension) { - if (!IsDoubleFiniteAndNonNegative(cornerRadius.TopLeft)) - { - return false; - } + Verify.IsNeitherNullNorEmpty(directory, "directory"); + Verify.IsNeitherNullNorEmpty(primaryFileName, "primaryFileName"); - if (!IsDoubleFiniteAndNonNegative(cornerRadius.TopRight)) - { - return false; - } + primaryFileName = MakeValidFileName(primaryFileName); - if (!IsDoubleFiniteAndNonNegative(cornerRadius.BottomLeft)) + for (int i = 0; i <= 50; ++i) { - return false; - } - - if (!IsDoubleFiniteAndNonNegative(cornerRadius.BottomRight)) - { - return false; + if (0 == i) + { + yield return Path.Combine(directory, primaryFileName) + extension; + } + else if (40 >= i) + { + yield return Path.Combine(directory, primaryFileName) + " (" + i.ToString((IFormatProvider)null) + ")" + extension; + } + else + { + // At this point we're hitting pathological cases. This should stir things up enough that it works. + // If this fails because of naming conflicts after an extra 10 tries, then I don't care. + yield return Path.Combine(directory, primaryFileName) + " (" + _randomNumberGenerator.Next(41, 9999) + ")" + extension; + } } - - return true; } - public static bool IsDoubleFiniteAndNonNegative(double d) + public static bool TryFileMove(string sourceFileName, string destFileName) { - if (double.IsNaN(d) || double.IsInfinity(d) || d < 0) + if (!File.Exists(destFileName)) { - return false; + try + { + File.Move(sourceFileName, destFileName); + } + catch (IOException) + { + return false; + } + return true; } - - return true; + return false; } - - #endregion } } diff --git a/Microsoft.Windows.Shell/Standard/Verify.cs b/Microsoft.Windows.Shell/Standard/Verify.cs index b806b1f..a6367ff 100644 --- a/Microsoft.Windows.Shell/Standard/Verify.cs +++ b/Microsoft.Windows.Shell/Standard/Verify.cs @@ -1,7 +1,3 @@ -/**************************************************************************\ - Copyright Microsoft Corporation. All Rights Reserved. -\**************************************************************************/ - // This file contains general utilities to aid in development. // Classes here generally shouldn't be exposed publicly since // they're not particular to any library functionality. @@ -40,6 +36,7 @@ public static void IsApartmentState(ApartmentState requiredState, string message { if (Thread.CurrentThread.GetApartmentState() != requiredState) { + Assert.Fail(); throw new InvalidOperationException(message); } } @@ -61,10 +58,12 @@ public static void IsNeitherNullNorEmpty(string value, string name) const string errorMessage = "The parameter can not be either null or empty."; if (null == value) { + Assert.Fail(); throw new ArgumentNullException(name, errorMessage); } if ("" == value) { + Assert.Fail(); throw new ArgumentException(errorMessage, name); } } @@ -86,10 +85,12 @@ public static void IsNeitherNullNorWhitespace(string value, string name) const string errorMessage = "The parameter can not be either null or empty or consist only of white space characters."; if (null == value) { + Assert.Fail(); throw new ArgumentNullException(name, errorMessage); } if ("" == value.Trim()) { + Assert.Fail(); throw new ArgumentException(errorMessage, name); } } @@ -104,6 +105,7 @@ public static void IsNotDefault(T obj, string name) where T : struct { if (default(T).Equals(obj)) { + Assert.Fail(); throw new ArgumentException("The parameter must not be the default value.", name); } } @@ -118,6 +120,7 @@ public static void IsNotNull(T obj, string name) where T : class { if (null == obj) { + Assert.Fail(); throw new ArgumentNullException(name); } } @@ -132,6 +135,7 @@ public static void IsNull(T obj, string name) where T : class { if (null != obj) { + Assert.Fail(); throw new ArgumentException("The parameter must be null.", name); } } @@ -142,6 +146,7 @@ public static void PropertyIsNotNull(T obj, string name) where T : class { if (null == obj) { + Assert.Fail(); throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The property {0} cannot be null at this time.", name)); } } @@ -152,6 +157,7 @@ public static void PropertyIsNull(T obj, string name) where T : class { if (null != obj) { + Assert.Fail(); throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The property {0} must be null at this time.", name)); } } @@ -167,6 +173,18 @@ public static void IsTrue(bool statement, string name) { if (!statement) { + Assert.Fail(); + throw new ArgumentException("", name); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsFalse(bool statement, string name) + { + if (statement) + { + Assert.Fail(); throw new ArgumentException("", name); } } @@ -183,6 +201,7 @@ public static void IsTrue(bool statement, string name, string message) { if (!statement) { + Assert.Fail(); throw new ArgumentException(message, name); } } @@ -196,11 +215,13 @@ public static void AreEqual(T expected, T actual, string parameterName, strin // Two nulls are considered equal, regardless of type semantics. if (null != actual && !actual.Equals(expected)) { + Assert.Fail(); throw new ArgumentException(message, parameterName); } } else if (!expected.Equals(actual)) { + Assert.Fail(); throw new ArgumentException(message, parameterName); } } @@ -214,11 +235,13 @@ public static void AreNotEqual(T notExpected, T actual, string parameterName, // Two nulls are considered equal, regardless of type semantics. if (null == actual || actual.Equals(notExpected)) { + Assert.Fail(); throw new ArgumentException(message, parameterName); } } else if (notExpected.Equals(actual)) { + Assert.Fail(); throw new ArgumentException(message, parameterName); } } @@ -230,6 +253,7 @@ public static void UriIsAbsolute(Uri uri, string parameterName) Verify.IsNotNull(uri, parameterName); if (!uri.IsAbsoluteUri) { + Assert.Fail(); throw new ArgumentException("The URI must be absolute.", parameterName); } } @@ -246,6 +270,7 @@ public static void BoundedInteger(int lowerBoundInclusive, int value, int upperB { if (value < lowerBoundInclusive || value >= upperBoundExclusive) { + Assert.Fail(); throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The integer value must be bounded with [{0}, {1})", lowerBoundInclusive, upperBoundExclusive), parameterName); } } @@ -256,6 +281,7 @@ public static void BoundedDoubleInc(double lowerBoundInclusive, double value, do { if (value < lowerBoundInclusive || value > upperBoundInclusive) { + Assert.Fail(); throw new ArgumentException(message, parameter); } } @@ -270,6 +296,7 @@ public static void TypeSupportsInterface(Type type, Type interfaceType, string p if (type.GetInterface(interfaceType.Name) == null) { + Assert.Fail(); throw new ArgumentException("The type of this parameter does not support a required interface", parameterName); } } @@ -281,6 +308,7 @@ public static void FileExists(string filePath, string parameterName) Verify.IsNeitherNullNorEmpty(filePath, parameterName); if (!File.Exists(filePath)) { + Assert.Fail(); throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "No file exists at \"{0}\"", filePath), parameterName); } } @@ -305,6 +333,7 @@ internal static void ImplementsInterface(object parameter, Type interfaceType, s if (!isImplemented) { + Assert.Fail(); throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The parameter must implement interface {0}.", interfaceType.ToString()), parameterName); } } diff --git a/Microsoft.Windows.Shell/Standard/WicProvider.cs b/Microsoft.Windows.Shell/Standard/WicProvider.cs new file mode 100644 index 0000000..94badb9 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/WicProvider.cs @@ -0,0 +1,648 @@ +// wincodec.idl +namespace Standard +{ + using System; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.ComTypes; + using System.Text; + + using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; + using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG; + + #region WIC Values + + internal static class WicValues + { + public const uint WINCODEC_SDK_VERSION = 0x0236; + public static readonly Guid GUID_VendorMicrosoft = new Guid(0xf0e749ca, 0xedef, 0x4589, 0xa7, 0x3a, 0xee, 0xe, 0x62, 0x6a, 0x2a, 0x2b); + } + + /// + /// GUID Identifiers for the image container formats + /// + internal static class WicGUID + { + /// GUID_ContainerFormatBmp + public const string ContainerFormatBmp = "0af1d87e-fcfe-4188-bdeb-a7906471cbe3"; + /// GUID_ContainerFormatPng + public const string ContainerFormatPng = "1b7cfaf4-713f-473c-bbcd-6137425faeaf"; + /// GUID_ContainerFormatIco + public const string ContainerFormatIco = "a3a860c4-338f-4c17-919a-fba4b5628f21"; + /// GUID_ContainerFormatJpeg + public const string ContainerFormatJpeg = "19e4a5aa-5662-4fc5-a0c0-1758028e1057"; + /// GUID_ContainerFormatTiff + public const string ContainerFormatTiff = "163bcc30-e2e9-4f0b-961d-a3e9fdb788a3"; + /// GUID_ContainerFormatGif + public const string ContainerFormatGif = "1f8a5601-7d4d-4cbd-9c82-1bc8d4eeb9a5"; + /// GUID_ContainerFormatWmp + public const string ContainerFormatWmp = "57a37caa-367a-4540-916b-f183c5093a4b"; + } + + /// + /// WIC Category Identifiers + /// + internal static class WicCATID + { + /// CATID_WICBitmapDecoders + public const string WICBitmapDecoders = "7ed96837-96f0-4812-b211-f13c24117ed3"; + /// CATID_WICBitmapEncoders + public const string WICBitmapEncoders = "ac757296-3522-4e11-9862-c17be5a1767e"; + /// CATID_WICPixelFormats + public const string WICPixelFormats = "2b46e70f-cda7-473e-89f6-dc9630a2390b"; + /// CATID_WICFormatConverters + public const string WICFormatConverters = "7835eae8-bf14-49d1-93ce-533a407b2248"; + /// CATID_WICMetadataReader + public const string WICMetadataReader = "05af94d8-7174-4cd2-be4a-4124b80ee4b8"; + /// CATID_WICMetadataWriter + public const string WICMetadataWriter = "abe3b9a4-257d-4b97-bd1a-294af496222e"; + } + + internal static class WicCLSID + { + #region (WIC) GUID identifiers for the codecs + + /// CLSID_WICBmpDecoder + public const string WICBmpDecoder = "6b462062-7cbf-400d-9fdb-813dd10f2778"; + /// CLSID_WICPngDecoder + public const string WICPngDecoder = "389ea17b-5078-4cde-b6ef-25c15175c751"; + /// CLSID_WICIcoDecoder + public const string WICIcoDecoder = "c61bfcdf-2e0f-4aad-a8d7-e06bafebcdfe"; + /// CLSID_WICJpegDecoder + public const string WICJpegDecoder = "9456a480-e88b-43ea-9e73-0b2d9b71b1ca"; + /// CLSID_WICGifDecoder + public const string WICGifDecoder = "381dda3c-9ce9-4834-a23e-1f98f8fc52be"; + /// CLSID_WICTiffDecoder + public const string WICTiffDecoder = "b54e85d9-fe23-499f-8b88-6acea713752b"; + /// CLSID_WICWmpDecoder + public const string WICWmpDecoder = "a26cec36-234c-4950-ae16-e34aace71d0d"; + + /// CLSID_WICBmpEncoder + public const string WICBmpEncoder = "69be8bb4-d66d-47c8-865a-ed1589433782"; + /// CLSID_WICPngEncoder + public const string WICPngEncoder = "27949969-876a-41d7-9447-568f6a35a4dc"; + /// CLSID_WICJpegEncoder + public const string WICJpegEncoder = "1a34f5c1-4a5a-46dc-b644-1f4567e7a676"; + /// CLSID_WICGifEncoder + public const string WICGifEncoder = "114f5598-0b22-40a0-86a1-c83ea495adbd"; + /// CLSID_WICTiffEncoder + public const string WICTiffEncoder = "0131be10-2001-4c5f-a9b0-cc88fab64ce8"; + /// CLSID_WICWmpEncoder + public const string WICWmpEncoder = "ac4ce3cb-e1c1-44cd-8215-5a1665509ec2"; + + #endregion + + #region Category Identifiers + + /// CLSID_WICImagingCategories + public const string WICImagingCategories = "fae3d380-fea4-4623-8c75-c6b61110b681"; + + #endregion + + #region Format converters + + /// CLSID_WICDefaultFormatConverter + public const string WICDefaultFormatConverter = "1a3f11dc-b514-4b17-8c5f-2154513852f1"; + /// CLSID_WICFormatConverterNChannel + public const string WICFormatConverterNChannel = "c17cabb2-d4a3-47d7-a557-339b2efbd4f1"; + /// CLSID_WICFormatConverterWMPhoto + public const string WICFormatConverterWMPhoto = "9cb5172b-d600-46ba-ab77-77bb7e3a00d9"; + + #endregion + } + + /// Pixel format GUIDs. + internal static class WICPixelFormat + { + /* Undefined formats */ + public static readonly Guid WICPixelFormatDontCare = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x00); + public static readonly Guid WICPixelFormatUndefined = WICPixelFormatDontCare; + + /* Indexed formats */ + public static readonly Guid WICPixelFormat1bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x01); + public static readonly Guid WICPixelFormat2bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x02); + public static readonly Guid WICPixelFormat4bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x03); + public static readonly Guid WICPixelFormat8bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x04); + + public static readonly Guid WICPixelFormatBlackWhite = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x05); + public static readonly Guid WICPixelFormat2bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x06); + public static readonly Guid WICPixelFormat4bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x07); + public static readonly Guid WICPixelFormat8bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x08); + + /* sRGB formats (gamma is approx. 2.2) */ + /* For a full definition, see the sRGB spec */ + + /* 16bpp formats */ + public static readonly Guid WICPixelFormat16bppBGR555 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x09); + public static readonly Guid WICPixelFormat16bppBGR565 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0a); + public static readonly Guid WICPixelFormat16bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0b); + + /* 24bpp formats */ + public static readonly Guid WICPixelFormat24bppBGR = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c); + public static readonly Guid WICPixelFormat24bppRGB = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d); + + /* 32bpp format */ + public static readonly Guid WICPixelFormat32bppBGR = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0e); + public static readonly Guid WICPixelFormat32bppBGRA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f); + public static readonly Guid WICPixelFormat32bppPBGRA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x10); + public static readonly Guid WICPixelFormat32bppGrayFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x11); + + /* 48bpp format */ + public static readonly Guid WICPixelFormat48bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x12); + + /* scRGB formats. Gamma is 1.0 */ + /* For a full definition, see the scRGB spec */ + + /* 16bpp format */ + public static readonly Guid WICPixelFormat16bppGrayFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x13); + + /* 32bpp format */ + public static readonly Guid WICPixelFormat32bppBGR101010 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x14); + + /* 48bpp format */ + public static readonly Guid WICPixelFormat48bppRGB = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x15); + + /* 64bpp format */ + public static readonly Guid WICPixelFormat64bppRGBA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x16); + public static readonly Guid WICPixelFormat64bppPRGBA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x17); + + /* 96bpp format */ + public static readonly Guid WICPixelFormat96bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x18); + + /* Floating point scRGB formats */ + public static readonly Guid WICPixelFormat128bppRGBAFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x19); + public static readonly Guid WICPixelFormat128bppPRGBAFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1a); + public static readonly Guid WICPixelFormat128bppRGBFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1b); + + /* CMYK formats. */ + public static readonly Guid WICPixelFormat32bppCMYK = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1c); + + /* Photon formats */ + public static readonly Guid WICPixelFormat64bppRGBAFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1d); + public static readonly Guid WICPixelFormat64bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x40); + public static readonly Guid WICPixelFormat128bppRGBAFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1e); + public static readonly Guid WICPixelFormat128bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x41); + + public static readonly Guid WICPixelFormat64bppRGBAHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3a); + public static readonly Guid WICPixelFormat64bppRGBHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x42); + public static readonly Guid WICPixelFormat48bppRGBHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3b); + + public static readonly Guid WICPixelFormat32bppRGBE = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3d); + + public static readonly Guid WICPixelFormat16bppGrayHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3e); + public static readonly Guid WICPixelFormat32bppGrayFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3f); + + /* More CMYK formats and n-Channel formats */ + public static readonly Guid WICPixelFormat64bppCMYK = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1f); + + public static readonly Guid WICPixelFormat24bpp3Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x20); + public static readonly Guid WICPixelFormat32bpp4Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x21); + public static readonly Guid WICPixelFormat40bpp5Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x22); + public static readonly Guid WICPixelFormat48bpp6Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x23); + public static readonly Guid WICPixelFormat56bpp7Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x24); + public static readonly Guid WICPixelFormat64bpp8Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x25); + + public static readonly Guid WICPixelFormat48bpp3Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x26); + public static readonly Guid WICPixelFormat64bpp4Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x27); + public static readonly Guid WICPixelFormat80bpp5Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x28); + public static readonly Guid WICPixelFormat96bpp6Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x29); + public static readonly Guid WICPixelFormat112bpp7Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2a); + public static readonly Guid WICPixelFormat128bpp8Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2b); + + public static readonly Guid WICPixelFormat40bppCMYKAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2c); + public static readonly Guid WICPixelFormat80bppCMYKAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2d); + + public static readonly Guid WICPixelFormat32bpp3ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2e); + public static readonly Guid WICPixelFormat40bpp4ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2f); + public static readonly Guid WICPixelFormat48bpp5ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x30); + public static readonly Guid WICPixelFormat56bpp6ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x31); + public static readonly Guid WICPixelFormat64bpp7ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x32); + public static readonly Guid WICPixelFormat72bpp8ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x33); + + public static readonly Guid WICPixelFormat64bpp3ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x34); + public static readonly Guid WICPixelFormat80bpp4ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x35); + public static readonly Guid WICPixelFormat96bpp5ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x36); + public static readonly Guid WICPixelFormat112bpp6ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x37); + public static readonly Guid WICPixelFormat128bpp7ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x38); + public static readonly Guid WICPixelFormat144bpp8ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x39); + } + + [Flags] + internal enum WICComponentType : int + { + WICDecoder = 0x00000001, + WICEncoder = 0x00000002, + WICPixelFormatConverter = 0x00000004, + WICMetadataReader = 0x00000008, + WICMetadataWriter = 0x00000010, + WICPixelFormat = 0x00000020, + WICAllComponents = 0x0000003F, + } + + internal enum WICBitmapDitherType : int + { + None = 0x00000000, + Solid = 0x00000000, + Ordered4x4 = 0x00000001, + Ordered8x8 = 0x00000002, + Ordered16x16 = 0x00000003, + Spiral4x4 = 0x00000004, + Spiral8x8 = 0x00000005, + DualSpiral4x4 = 0x00000006, + DualSpiral8x8 = 0x00000007, + ErrorDiffusion = 0x00000008, + } + + /// WICDecodeMetadata*, WICDecodeOptions + internal enum WICDecodeMetadata : int + { + CacheOnDemand = 0x00000000, + CacheOnLoad = 0x00000001, + } + + [Flags] + internal enum WICComponentSigning : uint + { + WICComponentSigned = 0x00000001, + WICComponentUnsigned = 0x00000002, + WICComponentSafe = 0x00000004, + WICComponentDisabled = 0x80000000, + } + + /// + /// WICBitmapPaletteType* + /// + internal enum WICBitmapPaletteType + { + /// Arbitrary custom palette provided by caller. + Custom = 0x00000000, + /// Optimal palette generated using a median-cut algorithm. + MedianCut = 0x00000001, + /// Black and white palette. + FixedBW = 0x00000002, + + // Symmetric halftone palettes. + // Each of these halftone palettes will be a superset of the system palette. + // E.g. Halftone8 will have it's 8-color on-off primaries and the 16 system + // colors added. With duplicates removed, that leaves 16 colors. + + FixedHalftone8 = 0x00000003, // 8-color, on-off primaries + FixedHalftone27 = 0x00000004, // 3 intensity levels of each color + FixedHalftone64 = 0x00000005, // 4 intensity levels of each color + FixedHalftone125 = 0x00000006, // 5 intensity levels of each color + FixedHalftone216 = 0x00000007, // 6 intensity levels of each color + + /// convenient web palette, same as WICBitmapPaletteTypeFixedHalftone216 + FixedWebPalette = FixedHalftone216, + + // Assymetric halftone palettes. + // These are somewhat less useful than the symmetric ones, but are + // included for completeness. These do not include all of the system + // colors. + + FixedHalftone252 = 0x00000008, // 6-red, 7-green, 6-blue intensities + FixedHalftone256 = 0x00000009, // 8-red, 8-green, 4-blue intensities + + FixedGray4 = 0x0000000A,// 4 shades of gray + FixedGray16 = 0x0000000B,// 16 shades of gray + FixedGray256 = 0x0000000C,// 256 shades of gray + } + + /// + /// WICBitmapTransform*, WICBitmapTransformOptions + /// + internal enum WICBitmapTransform : int + { + Rotate0 = 0x00000000, + Rotate90 = 0x00000001, + Rotate180 = 0x00000002, + Rotate270 = 0x00000003, + FlipHorizontal = 0x00000008, + FlipVertical = 0x00000010, + } + + /// + /// WICBitmap* + /// + internal enum WICBitmapCreateCacheOption : int + { + NoCache = 0x00000000, + CacheOnDemand = 0x00000001, + CacheOnLoad = 0x00000002, + } + + /// + /// WICBitmap* + /// + internal enum WICBitmapAlphaChannelOption : int + { + UseAlpha = 0x00000000, + UsePremultipliedAlpha = 0x00000001, + IgnoreAlpha = 0x00000002, + } + + #endregion + + #region WIC Structures + + [StructLayout(LayoutKind.Sequential)] + internal struct WICRect + { + public int X; + public int Y; + public int Width; + public int Height; + } + + #endregion + + #region WIC Interfaces + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICBitmapDecoder), + ] + internal interface IWICBitmapDecoder + { + uint QueryCapability([In] IStream pIStream); + + void Initialize([In] IStream pIStream, WICDecodeMetadata cacheOptions); + + Guid GetContainerFormat(); + + // returns IWICBitmapDecoderInfo + IntPtr GetDecoderInfo(); + + void CopyPalette([In] /*IWICPalette*/ IntPtr pIPalette); + + // returns IWICMetadataQueryReader + IntPtr GetMetadataQueryReader(); + + // returns IWICBitmapSource + IntPtr GetPreview(); + + void GetColorContexts(int cCount, [In, Out] /*IWICColorContext*/ ref IntPtr ppIColorContexts, out int pcActualCount); + + // returns IWICBitmapSource + IntPtr GetThumbnail(); + + int GetFrameCount(); + + IWICBitmapFrameDecode GetFrame(int index); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICBitmapSource) + ] + internal interface IWICBitmapSource + { + void GetSize(out int puiWidth, out int puiHeight); + + Guid GetPixelFormat(); + + void GetResolution(out double pDpiX, out double pDpiY); + + void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); + + void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICFormatConverter) + ] + interface IWICFormatConverter : IWICBitmapSource + { + #region IWICBitmapSource redeclaration + new void GetSize(out int puiWidth, out int puiHeight); + new Guid GetPixelFormat(); + new void GetResolution(out double pDpiX, out double pDpiY); + new void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); + new void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); + #endregion + + void Initialize( + IWICBitmapSource pISource, + [In] ref Guid dstFormat, + WICBitmapDitherType dither, + IntPtr pIPalette, + double alphaThresholdPercent, + WICBitmapPaletteType paletteTranslate); + + [return: MarshalAs(UnmanagedType.Bool)] + bool CanConvert( + [In] ref Guid srcPixelFormat, + [In] ref Guid dstPixelFormat); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICBitmap) + ] + internal interface IWICBitmap : IWICBitmapSource + { + #region IWICBitmapSource redeclaration + new void GetSize(out int puiWidth, out int puiHeight); + new Guid GetPixelFormat(); + new void GetResolution(out double pDpiX, out double pDpiY); + new void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); + new void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); + #endregion + + // IWICBitmapLock + IntPtr Lock([In] ref WICRect prcLock, int flags); + + void SetPalette(IntPtr pIPalette); + + void SetResolution(double dpiX, double dpiY); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICBitmapFrameDecode) + ] + internal interface IWICBitmapFrameDecode : IWICBitmapSource + { + #region IWICBitmapSource redeclaration + new void GetSize(out int puiWidth, out int puiHeight); + new Guid GetPixelFormat(); + new void GetResolution(out double pDpiX, out double pDpiY); + new void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); + new void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); + #endregion + + // IWICMetadataQueryReader + IntPtr GetMetadataQueryReader(); + + void GetColorContexts(int cCount, [In, Out] ref IntPtr /*IWICColorContext*/ ppIColorContexts, out int pcActualCount); + + IWICBitmapSource GetThumbnail(); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICBitmapFlipRotator) + ] + internal interface IWICBitmapFlipRotator : IWICBitmapSource + { + #region IWICBitmapSource redeclaration + new void GetSize(out int puiWidth, out int puiHeight); + new Guid GetPixelFormat(); + new void GetResolution(out double pDpiX, out double pDpiY); + new void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); + new void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); + #endregion + + void Initialize(IWICBitmapSource pISource, WICBitmapTransform options); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICImagingFactory) + ] + internal interface IWICImagingFactory + { + IWICBitmapDecoder CreateDecoderFromFilename( + [MarshalAs(UnmanagedType.LPWStr)] string wzFileName, + [In] ref Guid pguidVendor, + uint dwDesiredAccess, + WICDecodeMetadata metadataOptions); + + IWICBitmapDecoder CreateDecoderFromStream( + [In] IStream pIStream, + [In] ref Guid pguidVendor, + WICDecodeMetadata metadataOptions); + + IWICBitmapDecoder CreateDecoderFromFileHandle( + IntPtr hFile, + [In] ref Guid pguidVendor, + WICDecodeMetadata metadataOptions); + + // returns IWICComponentInfo + IntPtr CreateComponentInfo([In] ref Guid clsidComponent); + + IWICBitmapDecoder CreateDecoder( + [In] ref Guid guidContainerFormat, + [In] ref Guid pguidVendor); + + // IWICBitmapEncoder + IntPtr CreateEncoder( + [In] ref Guid guidContainerFormat, + [In] ref Guid pguidVendor); + + // IWICPalette + IntPtr CreatePalette(); + + IWICFormatConverter CreateFormatConverter(); + + // IWICBitmapScaler + IntPtr CreateBitmapScaler(); + + // IWICBitmapClipper + IntPtr CreateBitmapClipper(); + + IWICBitmapFlipRotator CreateBitmapFlipRotator(); + + IWICStream CreateStream(); + + // IWICColorContext + IntPtr CreateColorContext(); + + // IWICColorTransform + IntPtr CreateColorTransformer(); + + /* Bitmap creation */ + + IWICBitmap CreateBitmap( + int uiWidth, + int uiHeight, + [In] ref Guid pixelFormat, + WICBitmapCreateCacheOption option); + + IWICBitmap CreateBitmapFromSource( + IWICBitmapSource pIBitmapSource, + WICBitmapCreateCacheOption option); + + IWICBitmap CreateBitmapFromSourceRect( + IWICBitmapSource pIBitmapSource, + int x, + int y, + int width, + int height); + + IWICBitmap CreateBitmapFromMemory( + int uiWidth, + int uiHeight, + [In] ref Guid pixelFormat, + int cbStride, + int cbBufferSize, + IntPtr pbBuffer); + + IWICBitmap CreateBitmapFromHBITMAP( + IntPtr hBitmap, + IntPtr hPalette, + WICBitmapAlphaChannelOption options); + + IWICBitmap CreateBitmapFromHICON(IntPtr hIcon); + + // IEnumUnknown + IntPtr CreateComponentEnumerator( + int componentTypes, // WICComponentType + int options); // WICComponentEnumerateOptions + + // IWICFastMetadataEncoder + IntPtr CreateFastMetadataEncoderFromDecoder(IWICBitmapDecoder pIDecoder); + + // IWICFastMetadataEncoder + IntPtr CreateFastMetadataEncoderFromFrameDecode(IntPtr pIFrameDecoder); + + // IWICMetadataQueryWriter + IntPtr CreateQueryWriter( + [In] ref Guid guidMetadataFormat, + [In] ref Guid pguidVendor); + + // IWICMetadataQueryWriter + IntPtr CreateQueryWriterFromReader( + IntPtr pIQueryReader, + [In] ref Guid pguidVendor); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICStream) + ] + internal interface IWICStream : IStream + { + #region IStream redeclaration + + new void Clone(out IStream ppstm); + new void Commit(int grfCommitFlags); + new void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten); + new void LockRegion(long libOffset, long cb, int dwLockType); + new void Read(byte[] pv, int cb, IntPtr pcbRead); + new void Revert(); + new void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition); + new void SetSize(long libNewSize); + new void Stat(out STATSTG pstatstg, int grfStatFlag); + new void UnlockRegion(long libOffset, long cb, int dwLockType); + new void Write(byte[] pv, int cb, IntPtr pcbWritten); + + #endregion + + void InitializeFromIStream(IStream pIStream); + void InitializeFromFilename([In, MarshalAs(UnmanagedType.LPWStr)] string wzFileName, int dwDesiredAccess); + void InitializeFromMemory(IntPtr pbBuffer, uint cbBufferSize); + void InitializeFromIStreamRegion(IStream pIStream, ulong ulOffset, ulong ulMaxSize); + } + + #endregion +} diff --git a/Microsoft.Windows.Shell/Standard/WindowExtensions.cs b/Microsoft.Windows.Shell/Standard/WindowExtensions.cs new file mode 100644 index 0000000..d0fb5b2 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/WindowExtensions.cs @@ -0,0 +1,137 @@ + +namespace Standard +{ + using System; + using System.ComponentModel; + using System.Windows; + using System.Windows.Interop; + using System.Windows.Media; + + /// + /// Attached properties for WPF Windows. + /// + internal sealed class WindowExtensions + { + private IntPtr _hwnd = IntPtr.Zero; + private Window _window = null; + + private event Action WindowSourceInitialized; + + private WindowExtensions(Window window) + { + Assert.IsNotNull(window); + _window = window; + _hwnd = new WindowInteropHelper(window).Handle; + + if (_hwnd == IntPtr.Zero) + { + _window.SourceInitialized += _OnWindowSourceInitialized; + } + } + + private void _OnWindowSourceInitialized(object sender, EventArgs e) + { + Assert.AreEqual(sender, _window); + + _window.SourceInitialized -= _OnWindowSourceInitialized; + + _hwnd = new WindowInteropHelper(_window).Handle; + Assert.IsNotDefault(_hwnd); + + Action handler = WindowSourceInitialized; + if (handler != null) + { + handler(); + } + } + + private static WindowExtensions _EnsureAttachedExtensions(Window window) + { + Assert.IsNotNull(window); + + var ext = (WindowExtensions)window.GetValue(WindowExtensionsProperty); + if (ext == null) + { + ext = new WindowExtensions(window); + window.SetValue(WindowExtensionsProperty, ext); + } + + return ext; + } + + private static readonly DependencyProperty WindowExtensionsProperty = DependencyProperty.RegisterAttached( + "WindowExtensions", + typeof(WindowExtensions), + typeof(WindowExtensions), + new PropertyMetadata(null)); + + // Not bothering with CLR attached property getter/setter since this is a private dependency property. + + + public static readonly DependencyProperty HwndBackgroundBrushProperty = DependencyProperty.RegisterAttached( + "HwndBackgroundBrush", + typeof(SolidColorBrush), + typeof(WindowExtensions), + new PropertyMetadata( + Brushes.Pink, + (d,e) => _OnHwndBackgroundBrushChanged(d))); + + public static SolidColorBrush GetHwndBackgroundBrush(FrameworkElement window) + { + Verify.IsNotNull(window, "window"); + return (SolidColorBrush)window.GetValue(HwndBackgroundBrushProperty); + } + + public static void SetHwndBackgroundBrush(FrameworkElement window, SolidColorBrush value) + { + if (!(window is Window)) + { + return; + } + Verify.IsNotNull(window, "window"); + window.SetValue(HwndBackgroundBrushProperty, value); + } + + private static void _OnHwndBackgroundBrushChanged(DependencyObject d) + { + if (DesignerProperties.GetIsInDesignMode(d)) + { + return; + } + + var window = d as Window; + Verify.IsNotNull(window, "window"); + + WindowExtensions ext = _EnsureAttachedExtensions(window); + + if (ext._hwnd == IntPtr.Zero) + { + ext.WindowSourceInitialized += () => _OnHwndBackgroundBrushChanged(window); + return; + } + + SolidColorBrush backgroundBrush = (SolidColorBrush)window.GetValue(HwndBackgroundBrushProperty); + //if (backgroundBrush == null) + //{ + // Nothing to change. + // return; + //} + + Color backgroundColor = backgroundBrush.Color; + + // Not really handling errors here, but they shouldn't matter... Might leak an HBRUSH. + + IntPtr hBrush = NativeMethods.CreateSolidBrush(Utility.RGB(backgroundColor)); + + // Note that setting this doesn't necessarily repaint the window right away. + // Since the WPF content should cover the HWND background this doesn't matter. + // The new background will get repainted when the window is resized. + IntPtr hBrushOld = NativeMethods.SetClassLongPtr(ext._hwnd, GCLP.HBRBACKGROUND, hBrush); + + if (IntPtr.Zero != hBrushOld) + { + NativeMethods.DeleteObject(hBrushOld); + } + } + } +} diff --git a/Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimation.cs b/Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimation.cs new file mode 100644 index 0000000..50368d1 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimation.cs @@ -0,0 +1,541 @@ +namespace Standard +{ + using System; + using System.Diagnostics; + using System.Windows; + using System.Windows.Media.Animation; + + internal enum AnimationType + { + Automatic, + FromTo, + FromBy, + From, + To, + By, + } + + /// + /// Animates the value of a CornerRadius property using linear interpolation + /// between two values. The values are determined by the combination of + /// From, To, or By values that are set on the animation. + /// + internal partial class CornerRadiusAnimation : CornerRadiusAnimationBase + { + #region Data + + /// + /// This is used if the user has specified From, To, and/or By values. + /// + private CornerRadius[] _keyValues; + + private AnimationType _animationType; + private bool _isAnimationFunctionValid; + + #endregion + + #region Constructors + + /// + /// Static ctor for CornerRadiusAnimation establishes + /// dependency properties, using as much shared data as possible. + /// + static CornerRadiusAnimation() + { + Type typeofProp = typeof(CornerRadius?); + Type typeofThis = typeof(CornerRadiusAnimation); + PropertyChangedCallback propCallback = new PropertyChangedCallback(AnimationFunction_Changed); + ValidateValueCallback validateCallback = new ValidateValueCallback(ValidateFromToOrByValue); + + FromProperty = DependencyProperty.Register( + "From", + typeofProp, + typeofThis, + new PropertyMetadata((CornerRadius?)null, propCallback), + validateCallback); + + ToProperty = DependencyProperty.Register( + "To", + typeofProp, + typeofThis, + new PropertyMetadata((CornerRadius?)null, propCallback), + validateCallback); + + ByProperty = DependencyProperty.Register( + "By", + typeofProp, + typeofThis, + new PropertyMetadata((CornerRadius?)null, propCallback), + validateCallback); + + } + + + /// + /// Creates a new CornerRadiusAnimation with all properties set to + /// their default values. + /// + public CornerRadiusAnimation() + : base() + { + } + + /// + /// Creates a new CornerRadiusAnimation that will animate a + /// CornerRadius property from its base value to the value specified + /// by the "toValue" parameter of this constructor. + /// + public CornerRadiusAnimation(CornerRadius toValue, Duration duration) + : this() + { + To = toValue; + Duration = duration; + } + + /// + /// Creates a new CornerRadiusAnimation that will animate a + /// CornerRadius property from its base value to the value specified + /// by the "toValue" parameter of this constructor. + /// + public CornerRadiusAnimation(CornerRadius toValue, Duration duration, FillBehavior fillBehavior) + : this() + { + To = toValue; + Duration = duration; + FillBehavior = fillBehavior; + } + + /// + /// Creates a new CornerRadiusAnimation that will animate a + /// CornerRadius property from the "fromValue" parameter of this constructor + /// to the "toValue" parameter. + /// + public CornerRadiusAnimation(CornerRadius fromValue, CornerRadius toValue, Duration duration) + : this() + { + From = fromValue; + To = toValue; + Duration = duration; + } + + /// + /// Creates a new CornerRadiusAnimation that will animate a + /// CornerRadius property from the "fromValue" parameter of this constructor + /// to the "toValue" parameter. + /// + public CornerRadiusAnimation(CornerRadius fromValue, CornerRadius toValue, Duration duration, FillBehavior fillBehavior) + : this() + { + From = fromValue; + To = toValue; + Duration = duration; + FillBehavior = fillBehavior; + } + + #endregion + + #region Freezable + + /// + /// Creates a copy of this CornerRadiusAnimation + /// + /// The copy + public new CornerRadiusAnimation Clone() + { + return (CornerRadiusAnimation)base.Clone(); + } + + // + // Note that we don't override the Clone virtuals (CloneCore, CloneCurrentValueCore, + // GetAsFrozenCore, and GetCurrentValueAsFrozenCore) even though this class has state + // not stored in a DP. + // + // We don't need to clone _animationType and _keyValues because they are the the cached + // results of animation function validation, which can be recomputed. The other remaining + // field, isAnimationFunctionValid, defaults to false, which causes this recomputation to happen. + // + + /// + /// Implementation of Freezable.CreateInstanceCore. + /// + /// The new Freezable. + protected override Freezable CreateInstanceCore() + { + return new CornerRadiusAnimation(); + } + + #endregion + + #region Methods + + /// + /// Calculates the value this animation believes should be the current value for the property. + /// + /// + /// This value is the suggested origin value provided to the animation + /// to be used if the animation does not have its own concept of a + /// start value. If this animation is the first in a composition chain + /// this value will be the snapshot value if one is available or the + /// base property value if it is not; otherise this value will be the + /// value returned by the previous animation in the chain with an + /// animationClock that is not Stopped. + /// + /// + /// This value is the suggested destination value provided to the animation + /// to be used if the animation does not have its own concept of an + /// end value. This value will be the base value if the animation is + /// in the first composition layer of animations on a property; + /// otherwise this value will be the output value from the previous + /// composition layer of animations for the property. + /// + /// + /// This is the animationClock which can generate the CurrentTime or + /// CurrentProgress value to be used by the animation to generate its + /// output value. + /// + /// + /// The value this animation believes should be the current value for the property. + /// + protected override CornerRadius GetCurrentValueCore(CornerRadius defaultOriginValue, CornerRadius defaultDestinationValue, AnimationClock animationClock) + { + Debug.Assert(animationClock.CurrentState != ClockState.Stopped); + + if (!_isAnimationFunctionValid) + { + ValidateAnimationFunction(); + } + + double progress = animationClock.CurrentProgress.Value; + + CornerRadius from = new CornerRadius(); + CornerRadius to = new CornerRadius(); + CornerRadius accumulated = new CornerRadius(); + CornerRadius foundation = new CornerRadius(); + + // need to validate the default origin and destination values if + // the animation uses them as the from, to, or foundation values + bool validateOrigin = false; + bool validateDestination = false; + + switch(_animationType) + { + case AnimationType.Automatic: + + from = defaultOriginValue; + to = defaultDestinationValue; + + validateOrigin = true; + validateDestination = true; + + break; + + case AnimationType.From: + + from = _keyValues[0]; + to = defaultDestinationValue; + + validateDestination = true; + + break; + + case AnimationType.To: + + from = defaultOriginValue; + to = _keyValues[0]; + + validateOrigin = true; + + break; + + case AnimationType.By: + + // According to the SMIL specification, a By animation is + // always additive. But we don't force this so that a + // user can re-use a By animation and have it replace the + // animations that precede it in the list without having + // to manually set the From value to the base value. + + to = _keyValues[0]; + foundation = defaultOriginValue; + + validateOrigin = true; + + break; + + case AnimationType.FromTo: + + from = _keyValues[0]; + to = _keyValues[1]; + + if (IsAdditive) + { + foundation = defaultOriginValue; + validateOrigin = true; + } + + break; + + case AnimationType.FromBy: + + from = _keyValues[0]; + to = _AddCornerRadius(_keyValues[0], _keyValues[1]); + + if (IsAdditive) + { + foundation = defaultOriginValue; + validateOrigin = true; + } + + break; + + default: + + Debug.Fail("Unknown animation type."); + + break; + } + + if (validateOrigin + && !_IsValidAnimationValueCornerRadius(defaultOriginValue)) + { + throw new InvalidOperationException(); + } + + if (validateDestination + && !_IsValidAnimationValueCornerRadius(defaultDestinationValue)) + { + throw new InvalidOperationException(); + } + + + if (IsCumulative) + { + double currentRepeat = (double)(animationClock.CurrentIteration - 1); + + if (currentRepeat > 0.0) + { + CornerRadius accumulator = _SubtractCornerRadius(to, from); + + accumulated = _ScaleCornerRadius(accumulator, currentRepeat); + } + } + + // return foundation + accumulated + from + ((to - from) * progress) + + return _AddCornerRadius( + foundation, + _AddCornerRadius( + accumulated, + _InterpolateCornerRadius(from, to, progress))); + } + + private CornerRadius _InterpolateCornerRadius(CornerRadius from, CornerRadius to, double progress) + { + return this._ScaleCornerRadius(this._SubtractCornerRadius(to, from), progress); + } + + private CornerRadius _ScaleCornerRadius(CornerRadius first, double currentRepeat) + { + return new CornerRadius( + first.TopLeft * currentRepeat, + first.TopRight * currentRepeat, + first.BottomRight * currentRepeat, + first.BottomLeft * currentRepeat); + } + + private CornerRadius _SubtractCornerRadius(CornerRadius first, CornerRadius second) + { + return new CornerRadius( + first.TopLeft - second.TopLeft, + first.TopRight - second.TopRight, + first.BottomRight - second.BottomRight, + first.BottomLeft - second.BottomLeft); + } + + private static bool _IsValidAnimationValueCornerRadius(CornerRadius defaultOriginValue) + { + return true; + } + + private CornerRadius _AddCornerRadius(CornerRadius first, CornerRadius second) + { + return new CornerRadius( + first.TopLeft + second.TopLeft, + first.TopRight + second.TopRight, + first.BottomRight + second.BottomRight, + first.BottomLeft + second.BottomLeft); + } + + private void ValidateAnimationFunction() + { + _animationType = AnimationType.Automatic; + _keyValues = null; + + if (From.HasValue) + { + if (To.HasValue) + { + _animationType = AnimationType.FromTo; + _keyValues = new CornerRadius[2]; + _keyValues[0] = From.Value; + _keyValues[1] = To.Value; + } + else if (By.HasValue) + { + _animationType = AnimationType.FromBy; + _keyValues = new CornerRadius[2]; + _keyValues[0] = From.Value; + _keyValues[1] = By.Value; + } + else + { + _animationType = AnimationType.From; + _keyValues = new CornerRadius[1]; + _keyValues[0] = From.Value; + } + } + else if (To.HasValue) + { + _animationType = AnimationType.To; + _keyValues = new CornerRadius[1]; + _keyValues[0] = To.Value; + } + else if (By.HasValue) + { + _animationType = AnimationType.By; + _keyValues = new CornerRadius[1]; + _keyValues[0] = By.Value; + } + + _isAnimationFunctionValid = true; + } + + #endregion + + #region Properties + + private static void AnimationFunction_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + CornerRadiusAnimation a = (CornerRadiusAnimation)d; + + a._isAnimationFunctionValid = false; + //a.PropertyChanged(e.Property); + } + + private void PropertyChanged(DependencyProperty dependencyProperty) + { + //throw new NotImplementedException(); + } + + private static bool ValidateFromToOrByValue(object value) + { + CornerRadius? typedValue = (CornerRadius?)value; + + if (typedValue.HasValue) + { + return _IsValidAnimationValueCornerRadius(typedValue.Value); + } + else + { + return true; + } + } + + /// + /// FromProperty + /// + public static readonly DependencyProperty FromProperty; + + /// + /// From + /// + public CornerRadius? From + { + get + { + return (CornerRadius?)GetValue(FromProperty); + } + set + { + SetValue(FromProperty, value); + } + } + + /// + /// ToProperty + /// + public static readonly DependencyProperty ToProperty; + + /// + /// To + /// + public CornerRadius? To + { + get + { + return (CornerRadius?)GetValue(ToProperty); + } + set + { + SetValue(ToProperty, value); + } + } + + /// + /// ByProperty + /// + public static readonly DependencyProperty ByProperty; + + /// + /// By + /// + public CornerRadius? By + { + get + { + return (CornerRadius?)GetValue(ByProperty); + } + set + { + SetValue(ByProperty, value); + } + } + + + /// + /// If this property is set to true the animation will add its value to + /// the base value instead of replacing it entirely. + /// + public bool IsAdditive + { + get + { + return (bool)GetValue(IsAdditiveProperty); + } + set + { + SetValue(IsAdditiveProperty, value); + } + } + + /// + /// It this property is set to true, the animation will accumulate its + /// value over repeats. For instance if you have a From value of 0.0 and + /// a To value of 1.0, the animation return values from 1.0 to 2.0 over + /// the second reteat cycle, and 2.0 to 3.0 over the third, etc. + /// + public bool IsCumulative + { + get + { + return (bool)GetValue(IsCumulativeProperty); + } + set + { + SetValue(IsCumulativeProperty, value); + } + } + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimationBase.cs b/Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimationBase.cs new file mode 100644 index 0000000..cd04245 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimationBase.cs @@ -0,0 +1,191 @@ +namespace Standard +{ + using System; + using System.Windows; + using System.Windows.Media.Animation; + + internal abstract class CornerRadiusAnimationBase : AnimationTimeline + { + #region Constructors + + /// + /// Creates a new CornerRadiusAnimationBase. + /// + protected CornerRadiusAnimationBase() + : base() + { + } + + #endregion + + #region Freezable + + /// + /// Creates a copy of this CornerRadiusAnimationBase + /// + /// The copy + public new CornerRadiusAnimationBase Clone() + { + return (CornerRadiusAnimationBase)base.Clone(); + } + + #endregion + + #region IAnimation + + /// + /// Calculates the value this animation believes should be the current value for the property. + /// + /// + /// This value is the suggested origin value provided to the animation + /// to be used if the animation does not have its own concept of a + /// start value. If this animation is the first in a composition chain + /// this value will be the snapshot value if one is available or the + /// base property value if it is not; otherise this value will be the + /// value returned by the previous animation in the chain with an + /// animationClock that is not Stopped. + /// + /// + /// This value is the suggested destination value provided to the animation + /// to be used if the animation does not have its own concept of an + /// end value. This value will be the base value if the animation is + /// in the first composition layer of animations on a property; + /// otherwise this value will be the output value from the previous + /// composition layer of animations for the property. + /// + /// + /// This is the animationClock which can generate the CurrentTime or + /// CurrentProgress value to be used by the animation to generate its + /// output value. + /// + /// + /// The value this animation believes should be the current value for the property. + /// + public override sealed object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock) + { + // Verify that object arguments are non-null since we are a value type + if (defaultOriginValue == null) + { + throw new ArgumentNullException("defaultOriginValue"); + } + if (defaultDestinationValue == null) + { + throw new ArgumentNullException("defaultDestinationValue"); + } + return GetCurrentValue((CornerRadius)defaultOriginValue, (CornerRadius)defaultDestinationValue, animationClock); + } + + /// + /// Returns the type of the target property + /// + public override sealed Type TargetPropertyType + { + get + { + ReadPreamble(); + + return typeof(CornerRadius); + } + } + + #endregion + + #region Methods + + + /// + /// Calculates the value this animation believes should be the current value for the property. + /// + /// + /// This value is the suggested origin value provided to the animation + /// to be used if the animation does not have its own concept of a + /// start value. If this animation is the first in a composition chain + /// this value will be the snapshot value if one is available or the + /// base property value if it is not; otherise this value will be the + /// value returned by the previous animation in the chain with an + /// animationClock that is not Stopped. + /// + /// + /// This value is the suggested destination value provided to the animation + /// to be used if the animation does not have its own concept of an + /// end value. This value will be the base value if the animation is + /// in the first composition layer of animations on a property; + /// otherwise this value will be the output value from the previous + /// composition layer of animations for the property. + /// + /// + /// This is the animationClock which can generate the CurrentTime or + /// CurrentProgress value to be used by the animation to generate its + /// output value. + /// + /// + /// The value this animation believes should be the current value for the property. + /// + public CornerRadius GetCurrentValue(CornerRadius defaultOriginValue, CornerRadius defaultDestinationValue, AnimationClock animationClock) + { + ReadPreamble(); + + if (animationClock == null) + { + throw new ArgumentNullException("animationClock"); + } + + // We check for null above but presharp doesn't notice so we suppress the + // warning here. + + //#pragma warning suppress 6506 + if (animationClock.CurrentState == ClockState.Stopped) + { + return defaultDestinationValue; + } + + /* + if (!AnimatedTypeHelpers.IsValidAnimationValueCornerRadius(defaultDestinationValue)) + { + throw new ArgumentException( + SR.Get( + SRID.Animation_InvalidBaseValue, + defaultDestinationValue, + defaultDestinationValue.GetType(), + GetType()), + "defaultDestinationValue"); + } + */ + + return GetCurrentValueCore(defaultOriginValue, defaultDestinationValue, animationClock); + } + + + /// + /// Calculates the value this animation believes should be the current value for the property. + /// + /// + /// This value is the suggested origin value provided to the animation + /// to be used if the animation does not have its own concept of a + /// start value. If this animation is the first in a composition chain + /// this value will be the snapshot value if one is available or the + /// base property value if it is not; otherise this value will be the + /// value returned by the previous animation in the chain with an + /// animationClock that is not Stopped. + /// + /// + /// This value is the suggested destination value provided to the animation + /// to be used if the animation does not have its own concept of an + /// end value. This value will be the base value if the animation is + /// in the first composition layer of animations on a property; + /// otherwise this value will be the output value from the previous + /// composition layer of animations for the property. + /// + /// + /// This is the animationClock which can generate the CurrentTime or + /// CurrentProgress value to be used by the animation to generate its + /// output value. + /// + /// + /// The value this animation believes should be the current value for the property. + /// + protected abstract CornerRadius GetCurrentValueCore(CornerRadius defaultOriginValue, CornerRadius defaultDestinationValue, AnimationClock animationClock); + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/Standard/DpiHelper.cs b/Microsoft.Windows.Shell/Standard/Wpf/DpiHelper.cs similarity index 86% rename from Microsoft.Windows.Shell/Standard/DpiHelper.cs rename to Microsoft.Windows.Shell/Standard/Wpf/DpiHelper.cs index 693bd6f..42b4544 100644 --- a/Microsoft.Windows.Shell/Standard/DpiHelper.cs +++ b/Microsoft.Windows.Shell/Standard/Wpf/DpiHelper.cs @@ -1,8 +1,4 @@ -/**************************************************************************\ - Copyright Microsoft Corporation. All Rights Reserved. -\**************************************************************************/ - -namespace Standard +namespace Standard { using System; using System.Diagnostics.CodeAnalysis; @@ -82,5 +78,13 @@ public static Size DeviceSizeToLogical(Size deviceSize) return new Size(pt.X, pt.Y); } + + public static Thickness LogicalThicknessToDevice(Thickness logicalThickness) + { + Point topLeft = LogicalPixelsToDevice(new Point(logicalThickness.Left, logicalThickness.Top)); + Point bottomRight = LogicalPixelsToDevice(new Point(logicalThickness.Right, logicalThickness.Bottom)); + + return new Thickness(topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y); + } } } diff --git a/Microsoft.Windows.Shell/Standard/Wpf/GlassHelper.cs b/Microsoft.Windows.Shell/Standard/Wpf/GlassHelper.cs new file mode 100644 index 0000000..efc48e7 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/Wpf/GlassHelper.cs @@ -0,0 +1,283 @@ +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Windows; + using System.Windows.Interop; + using System.Windows.Media; + + internal class GlassHelper + { + // Test Notes: + // Things to manually verify when making changes to this class. + // * Do modified windows look correct in non-composited themes? + // * Does changing the theme back and forth leave the window in a visually ugly state? + // * Does it matter which theme was used first? + // * Does glass extension work properly in high-dpi? + // * Which of SetWindowThemeAttribute and ExtendGlassFrame are set first shouldn't matter. + // The hooks injected by one should not block the hooks of the other. + // * Do captions and icons always show up when composition is disabled? + // + // There are not automated unit tests for this class ( Boo!!! :( ) + // Be careful not to break things... + + private static readonly Dictionary _extendedWindows = new Dictionary(); + + // TODO: + // Verify that this really is sufficient. There are DWMWINDOWATTRIBUTEs as well, so this may + // be able to be turned off on a per-HWND basis, but I never see comments about that online... + public static bool IsCompositionEnabled + { + get + { + if (!Utility.IsOSVistaOrNewer) + { + return false; + } + + return NativeMethods.DwmIsCompositionEnabled(); + } + } + + public static bool ExtendGlassFrameComplete(Window window) + { + return ExtendGlassFrame(window, new Thickness(-1)); + } + + /// + /// Extends the glass frame of a window. Only works on operating systems that support composition. + /// + /// The window to modify. + /// The margins of the new frame. + /// Whether the frame was successfully extended. + /// + /// This function adds hooks to the Window to respond to changes to whether composition is enabled. + /// + public static bool ExtendGlassFrame(Window window, Thickness margin) + { + Verify.IsNotNull(window, "window"); + + window.VerifyAccess(); + + IntPtr hwnd = new WindowInteropHelper(window).Handle; + + if (_extendedWindows.ContainsKey(hwnd)) + { + // The hook into the HWND's WndProc has the original margin cached. + // Don't want to support dynamically adjusting that unless there's a need. + throw new InvalidOperationException("Multiple calls to this function for the same Window are not supported."); + } + + return _ExtendGlassFrameInternal(window, margin); + } + + private static bool _ExtendGlassFrameInternal(Window window, Thickness margin) + { + Assert.IsNotNull(window); + Assert.IsTrue(window.CheckAccess()); + + // Expect that this might be called on OSes other than Vista. + if (!Utility.IsOSVistaOrNewer) + { + // Not an error. Just not on Vista so we're not going to get glass. + return false; + } + + IntPtr hwnd = new WindowInteropHelper(window).Handle; + if (IntPtr.Zero == hwnd) + { + throw new InvalidOperationException("Window must be shown before extending glass."); + } + + HwndSource hwndSource = HwndSource.FromHwnd(hwnd); + + bool isGlassEnabled = NativeMethods.DwmIsCompositionEnabled(); + + if (!isGlassEnabled) + { + window.Background = SystemColors.WindowBrush; + hwndSource.CompositionTarget.BackgroundColor = SystemColors.WindowColor; + } + else + { + // Apply the transparent background to both the Window and the HWND + window.Background = Brushes.Transparent; + hwndSource.CompositionTarget.BackgroundColor = Colors.Transparent; + + // Thickness is going to be DIPs, need to convert to system coordinates. + Point deviceTopLeft = DpiHelper.LogicalPixelsToDevice(new Point(margin.Left, margin.Top)); + Point deviceBottomRight = DpiHelper.LogicalPixelsToDevice(new Point(margin.Right, margin.Bottom)); + + var dwmMargin = new MARGINS + { + // err on the side of pushing in glass an extra pixel. + cxLeftWidth = (int)Math.Ceiling(deviceTopLeft.X), + cxRightWidth = (int)Math.Ceiling(deviceBottomRight.X), + cyTopHeight = (int)Math.Ceiling(deviceTopLeft.Y), + cyBottomHeight = (int)Math.Ceiling(deviceBottomRight.Y), + }; + + NativeMethods.DwmExtendFrameIntoClientArea(hwnd, ref dwmMargin); + } + + // Even if glass isn't currently enabled, add the hook so we can appropriately respond + // if that changes. + + bool addHook = !_extendedWindows.ContainsKey(hwnd); + + if (addHook) + { + HwndSourceHook hook = delegate(IntPtr innerHwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + if (WM.DWMCOMPOSITIONCHANGED == (WM)msg) + { + _ExtendGlassFrameInternal(window, margin); + handled = false; + } + return IntPtr.Zero; + }; + + _extendedWindows.Add(hwnd, hook); + hwndSource.AddHook(hook); + window.Closing += _OnExtendedWindowClosing; + } + + return isGlassEnabled; + } + + /// + /// Handler for the Closing event on a Window with an extended glass frame. + /// + /// The source of the event. + /// The instance containing the event data. + /// + /// When a Window with an extended glass frame closes, removes any local references to it. + /// + // BUGBUG: Doesn't handle if the Closing gets canceled. + static void _OnExtendedWindowClosing(object sender, CancelEventArgs e) + { + var window = sender as Window; + Assert.IsNotNull(window); + + IntPtr hwnd = new WindowInteropHelper(window).Handle; + + // We use the Closing rather than the Closed event to ensure that we can get this value. + Assert.AreNotEqual(IntPtr.Zero, hwnd); + + HwndSource hwndSource = HwndSource.FromHwnd(hwnd); + + Assert.IsTrue(_extendedWindows.ContainsKey(hwnd)); + + hwndSource.RemoveHook(_extendedWindows[hwnd]); + _extendedWindows.Remove(hwnd); + + window.Closing -= _OnExtendedWindowClosing; + } + + private static readonly Dictionary _attributedWindows = new Dictionary(); + + public static bool SetWindowThemeAttribute(Window window, bool showCaption, bool showIcon) + { + Verify.IsNotNull(window, "window"); + + window.VerifyAccess(); + + IntPtr hwnd = new WindowInteropHelper(window).Handle; + + if (_attributedWindows.ContainsKey(hwnd)) + { + // The hook into the HWND's WndProc has the original settings cached. + // Don't want to support dynamically adjusting that unless there's a need. + throw new InvalidOperationException("Multiple calls to this function for the same Window are not supported."); + } + + return _SetWindowThemeAttribute(window, showCaption, showIcon); + } + + private static bool _SetWindowThemeAttribute(Window window, bool showCaption, bool showIcon) + { + bool isGlassEnabled; + + Assert.IsNotNull(window); + Assert.IsTrue(window.CheckAccess()); + + // This only is expected to work if Aero glass is enabled. + try + { + isGlassEnabled = NativeMethods.DwmIsCompositionEnabled(); + } + catch (DllNotFoundException) + { + // Not an error. Just not on Vista so we're not going to get glass. + return false; + } + + IntPtr hwnd = new WindowInteropHelper(window).Handle; + if (IntPtr.Zero == hwnd) + { + throw new InvalidOperationException("Window must be shown before we can modify attributes."); + } + + var options = new WTA_OPTIONS + { + dwMask = (WTNCA.NODRAWCAPTION | WTNCA.NODRAWICON) + }; + if (isGlassEnabled) + { + if (!showCaption) + { + options.dwFlags |= WTNCA.NODRAWCAPTION; + } + if (!showIcon) + { + options.dwFlags |= WTNCA.NODRAWICON; + } + } + + NativeMethods.SetWindowThemeAttribute(hwnd, WINDOWTHEMEATTRIBUTETYPE.WTA_NONCLIENT, ref options, WTA_OPTIONS.Size); + + bool addHook = !_attributedWindows.ContainsKey(hwnd); + + if (addHook) + { + HwndSourceHook hook = delegate(IntPtr unusedHwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + if (WM.DWMCOMPOSITIONCHANGED == (WM)msg) + { + _SetWindowThemeAttribute(window, showCaption, showIcon); + handled = false; + } + return IntPtr.Zero; + }; + + _attributedWindows.Add(hwnd, hook); + HwndSource.FromHwnd(hwnd).AddHook(hook); + window.Closing += _OnAttributedWindowClosing; + } + + return isGlassEnabled; + } + + static void _OnAttributedWindowClosing(object sender, CancelEventArgs e) + { + var window = sender as Window; + Assert.IsNotNull(window); + + IntPtr hwnd = new WindowInteropHelper(window).Handle; + + // We use the Closing rather than the Closed event to ensure that we can get this value. + Assert.AreNotEqual(IntPtr.Zero, hwnd); + + HwndSource hwndSource = HwndSource.FromHwnd(hwnd); + + Assert.IsTrue(_attributedWindows.ContainsKey(hwnd)); + + hwndSource.RemoveHook(_attributedWindows[hwnd]); + _attributedWindows.Remove(hwnd); + + window.Closing -= _OnExtendedWindowClosing; + } + + } +} diff --git a/Microsoft.Windows.Shell/Standard/Wpf/MshtmlProvider.cs b/Microsoft.Windows.Shell/Standard/Wpf/MshtmlProvider.cs new file mode 100644 index 0000000..9ba9273 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/Wpf/MshtmlProvider.cs @@ -0,0 +1,407 @@ + +// Interface declarations for MSHTML objects. +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using System.Reflection; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.ComTypes; + using System.Windows.Controls; + + [ + ComImport, + Guid(IID.WebBrowserEvents2), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + TypeLibType(TypeLibTypeFlags.FHidden) + ] + internal interface DWebBrowserEvents2 + { + [DispId(102)] + void StatusTextChange([In] string text); + [DispId(104)] + void DownloadComplete(); + [DispId(105)] + void CommandStateChange([In] long command, [In] bool enable); + [DispId(106)] + void DownloadBegin(); + [DispId(108)] + void ProgressChange([In] int progress, [In] int progressMax); + [DispId(112)] + void PropertyChange([In] string szProperty); + [DispId(113)] + void TitleChange([In] string text); + [DispId(225)] + void PrintTemplateInstantiation([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp); + [DispId(226)] + void PrintTemplateTeardown([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp); + [DispId(227)] + void UpdatePageStatus([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, [In] ref object nPage, [In] ref object fDone); + [DispId(250)] + void BeforeNavigate2( + [In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, + [In] ref object URL, + [In] ref object flags, + [In] ref object targetFrameName, + [In] ref object postData, + [In] ref object headers, + [In, Out] ref bool cancel); + [DispId(251)] + void NewWindow2([In, Out, MarshalAs(UnmanagedType.IDispatch)] ref object pDisp, [In, Out] ref bool cancel); + [DispId(252)] + void NavigateComplete2([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, [In] ref object URL); + [DispId(253)] + void OnQuit(); + [DispId(254)] + void OnVisible([In] bool visible); + [DispId(255)] + void OnToolBar([In] bool toolBar); + [DispId(256)] + void OnMenuBar([In] bool menuBar); + [DispId(257)] + void OnStatusBar([In] bool statusBar); + [DispId(258)] + void OnFullScreen([In] bool fullScreen); + [DispId(259)] + void DocumentComplete([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, [In] ref object URL); + [DispId(260)] + void OnTheaterMode([In] bool theaterMode); + [DispId(262)] + void WindowSetResizable([In] bool resizable); + [DispId(263)] + void WindowClosing([In] bool isChildWindow, [In, Out] ref bool cancel); + [DispId(264)] + void WindowSetLeft([In] int left); + [DispId(265)] + void WindowSetTop([In] int top); + [DispId(266)] + void WindowSetWidth([In] int width); + [DispId(267)] + void WindowSetHeight([In] int height); + [DispId(268)] + void ClientToHostWindow([In, Out] ref long cx, [In, Out] ref long cy); + [DispId(269)] + void SetSecureLockIcon([In] int secureLockIcon); + [DispId(270)] + void FileDownload([In, Out] ref bool activeDocument, [In, Out] ref bool cancel); + [DispId(271)] + void NavigateError( + [In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, + [In] ref object URL, + [In] ref object frame, + [In] ref object statusCode, + [In, Out] ref bool cancel); + [DispId(272)] + void PrivacyImpactedStateChange([In] bool bImpacted); + [DispId(282)] // IE 7+ + void SetPhishingFilterStatus(uint phishingFilterStatus); + [DispId(283)] // IE 7+ + void WindowStateChanged(uint dwFlags, uint dwValidFlagsMask); + } + + [ + ComImport, + Guid(IID.HtmlDocument2), + InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual) + ] + internal interface IHtmlDocument2 + { + [return: MarshalAs(UnmanagedType.Interface)] + object GetScript(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetAll(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetBody(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetActiveElement(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetImages(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetApplets(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetLinks(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetForms(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetAnchors(); + void SetTitle([In, MarshalAs(UnmanagedType.BStr)] string p); + [return: MarshalAs(UnmanagedType.BStr)] + string GetTitle(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetScripts(); + void SetDesignMode([In, MarshalAs(UnmanagedType.BStr)] string p); + [return: MarshalAs(UnmanagedType.BStr)] + string GetDesignMode(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetSelection(); + [return: MarshalAs(UnmanagedType.BStr)] + string GetReadyState(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetFrames(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetEmbeds(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetPlugins(); + void SetAlinkColor([In, MarshalAs(UnmanagedType.Struct)] object p); + [return: MarshalAs(UnmanagedType.Struct)] + object GetAlinkColor(); + void SetBackColor([In, MarshalAs(UnmanagedType.Struct)] object p); + [return: MarshalAs(UnmanagedType.Struct)] + object GetBackColor(); + void SetForeColor([In, MarshalAs(UnmanagedType.Struct)] object p); + [return: MarshalAs(UnmanagedType.Struct)] + object GetForeColor(); + void SetLinkColor([In, MarshalAs(UnmanagedType.Struct)] object p); + [return: MarshalAs(UnmanagedType.Struct)] + object GetLinkColor(); + void SetVlinkColor([In, MarshalAs(UnmanagedType.Struct)] object p); + [return: MarshalAs(UnmanagedType.Struct)] + object GetVlinkColor(); + [return: MarshalAs(UnmanagedType.BStr)] + string GetReferrer(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetLocation(); + } + + [ + ComImport, + DefaultMember("Name"), + Guid(IID.WebBrowser2), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + ] + interface IWebBrowser2 + { + [DispId(100)] + void GoBack(); + [DispId(0x65)] + void GoForward(); + [DispId(0x66)] + void GoHome(); + [DispId(0x67)] + void GoSearch(); + [DispId(0x68)] + void Navigate([MarshalAs(UnmanagedType.BStr)] string URL, [In] ref object Flags, [In] ref object TargetFrameName, [In] ref object PostData, [In] ref object Headers); + [DispId(-550)] + void Refresh(); + [DispId(0x69)] + void Refresh2([In] ref object Level); + [DispId(0x6a)] + void Stop(); + [DispId(300)] + void Quit(); + [DispId(0x12d)] + void ClientToWindow([In, Out] ref int pcx, [In, Out] ref int pcy); + [DispId(0x12e)] + void PutProperty([MarshalAs(UnmanagedType.BStr)] string Property, object vtValue); + [DispId(0x12f)] + object GetProperty([MarshalAs(UnmanagedType.BStr)] string Property); + [DispId(500)] + void Navigate2([In] ref object URL, [In] ref object Flags, [In] ref object TargetFrameName, [In] ref object PostData, [In] ref object Headers); + [DispId(0x1f5)] + OLECMDF QueryStatusWB(OLECMDID cmdID); + [DispId(0x1f6)] + void ExecWB(OLECMDID cmdID, OLECMDEXECOPT cmdexecopt, [In] ref object pvaIn, [In, Out] ref object pvaOut); + [DispId(0x1f7)] + void ShowBrowserBar([In] ref object pvaClsid, [In] ref object pvarShow, [In] ref object pvarSize); + bool AddressBar { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x22b)] get; [DispId(0x22b)] set; } + object Application { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(200)] get; } + bool Busy { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0xd4)] get; } + object Container { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xca)] get; } + object Document { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xcb)] get; } + string FullName { [return: MarshalAs(UnmanagedType.BStr)] [DispId(400)] get; } + bool FullScreen { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x197)] get; [DispId(0x197)] set; } + int Height { [DispId(0xd1)] get; [DispId(0xd1)] set; } + int HWND { [DispId(-515)] get; } + int Left { [DispId(0xce)] get; [DispId(0xce)] set; } + string LocationName { [return: MarshalAs(UnmanagedType.BStr)] [DispId(210)] get; } + string LocationURL { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0xd3)] get; } + bool MenuBar { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x196)] get; [DispId(0x196)] set; } + string Name { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0)] get; } + bool Offline { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(550)] get; [DispId(550)] set; } + object Parent { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xc9)] get; } + string Path { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x191)] get; } + READYSTATE ReadyState { [DispId(-525)] get; } + bool RegisterAsBrowser { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x228)] get; [DispId(0x228)] set; } + bool RegisterAsDropTarget { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x229)] get; [DispId(0x229)] set; } + bool Resizable { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x22c)] get; [DispId(0x22c)] set; } + bool Silent { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x227)] get; [DispId(0x227)] set; } + bool StatusBar { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x193)] get; [DispId(0x193)] set; } + string StatusText { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x194)] get; [DispId(0x194)] set; } + bool TheaterMode { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x22a)] get; [DispId(0x22a)] set; } + int ToolBar { [DispId(0x195)] get; [DispId(0x195)] set; } + int Top { [DispId(0xcf)] get; [DispId(0xcf)] set; } + bool TopLevelContainer { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0xcc)] get; } + string Type { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0xcd)] get; } + bool Visible { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x192)] get; [DispId(0x192)] set; } + int Width { [DispId(0xd0)] get; [DispId(0xd0)] set; } + } + + internal class WebBrowserEvents : IDisposable + { + private readonly _EventSink _sink; + private SafeConnectionPointCookie _cookie; + + public WebBrowserEvents(WebBrowser browser) + { + if (browser.Document == null) + { + throw new InvalidOperationException("Can't add an event sink until the browser's document is non-null"); + } + + var serviceProvider = (IServiceProvider)browser.Document; + var serviceGuid = new Guid(SID.SWebBrowserApp); + var iid = new Guid(IID.ConnectionPointContainer); + var cpc = (IConnectionPointContainer)serviceProvider.QueryService(ref serviceGuid, ref iid); + + _sink = new _EventSink(this); + _cookie = new SafeConnectionPointCookie(cpc, _sink, new Guid(IID.WebBrowserEvents2)); + } + + // Because the DWebBrowserEvents2 interface is internal, provide our own IDispatch front-end for interop. + private class _EventSink : DWebBrowserEvents2, IReflect + { + private readonly WebBrowserEvents _target; + private static readonly Dictionary _dispIdMethodMap = typeof(DWebBrowserEvents2).GetMethods() + .ToDictionary(mi => ((DispIdAttribute[])mi.GetCustomAttributes(typeof(DispIdAttribute), false))[0].Value); + + internal _EventSink(WebBrowserEvents target) + { + Assert.IsNotNull(target); + _target = target; + } + + #region DWebBrowserEvents2 Members + + public void StatusTextChange(string text) {} + public void DownloadComplete() {} + public void CommandStateChange(long command, bool enable) {} + public void DownloadBegin() {} + public void ProgressChange(int progress, int progressMax) {} + public void PropertyChange(string szProperty) {} + public void TitleChange(string text) {} + public void PrintTemplateInstantiation(object pDisp) {} + public void PrintTemplateTeardown(object pDisp) {} + public void UpdatePageStatus(object pDisp, ref object nPage, ref object fDone) {} + public void BeforeNavigate2(object pDisp, ref object URL, ref object flags, ref object targetFrameName, ref object postData, ref object headers, ref bool cancel) {} + public void NewWindow2(ref object pDisp, ref bool cancel) {} + public void NavigateComplete2(object pDisp, ref object URL) {} + public void OnQuit() {} + public void OnVisible(bool visible) {} + public void OnToolBar(bool toolBar) {} + public void OnMenuBar(bool menuBar) {} + public void OnStatusBar(bool statusBar) {} + public void OnFullScreen(bool fullScreen) {} + public void DocumentComplete(object pDisp, ref object URL) {} + public void OnTheaterMode(bool theaterMode) {} + public void WindowSetResizable(bool resizable) {} + public void WindowClosing(bool isChildWindow, ref bool cancel) + { + _target._NotifyWindowClosing(); + } + public void WindowSetLeft(int left) {} + public void WindowSetTop(int top) {} + public void WindowSetWidth(int width) {} + public void WindowSetHeight(int height) {} + public void ClientToHostWindow(ref long cx, ref long cy) {} + public void SetSecureLockIcon(int secureLockIcon) {} + public void FileDownload(ref bool activeDocument, ref bool cancel) {} + public void NavigateError(object pDisp, ref object URL, ref object frame, ref object statusCode, ref bool cancel) {} + public void PrivacyImpactedStateChange(bool bImpacted) {} + public void SetPhishingFilterStatus(uint phishingFilterStatus) {} + public void WindowStateChanged(uint dwFlags, uint dwValidFlagsMask) {} + + #endregion + + #region IReflect Members + + FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr) { throw new NotImplementedException(); } + FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) { return null; } + MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr) { throw new NotImplementedException(); } + MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr) { throw new NotImplementedException(); } + MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr) { throw new NotImplementedException(); } + MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) { throw new NotImplementedException(); } + MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr) { return null; } + PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr) { return null; } + PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) { throw new NotImplementedException(); } + PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr) { throw new NotImplementedException(); } + + object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) + { + if (name.StartsWith("[DISPID=", StringComparison.OrdinalIgnoreCase)) + { + int dispid = int.Parse(name.Substring(8, name.Length - 9), CultureInfo.InvariantCulture); + MethodInfo method; + if (_dispIdMethodMap.TryGetValue(dispid, out method)) + { + return method.Invoke(this, invokeAttr, binder, args, culture); + } + } + throw new MissingMethodException(GetType().Name, name); + } + + Type IReflect.UnderlyingSystemType { get { return typeof(DWebBrowserEvents2); } } + + #endregion + } + + public event EventHandler WindowClosing; + + private void _NotifyWindowClosing() + { + var handler = WindowClosing; + if (handler != null) + { + handler(this, EventArgs.Empty); + } + } + + #region IDisposable Pattern + + ~WebBrowserEvents() + { + Assert.Fail(); + _Dispose(false); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "_cookie")] + public void Dispose() + { + _Dispose(true); + GC.SuppressFinalize(this); + } + + private void _Dispose(bool disposing) + { + Utility.SafeDispose(ref _cookie); + } + + #endregion + } + + internal static partial class Utility + { + public static string GetWebPageTitle(WebBrowser browser) + { + if (browser.Document == null) + { + return ""; + } + + return ((IHtmlDocument2)browser.Document).GetTitle(); + } + + public static void SuppressJavaScriptErrors(WebBrowser browser) + { + if (browser.Document != null) + { + var serviceProvider = (IServiceProvider)browser.Document; + var serviceGuid = new Guid(SID.SWebBrowserApp); + var iid = new Guid(IID.WebBrowser2); + var webBrowser2 = (IWebBrowser2)serviceProvider.QueryService(ref serviceGuid, ref iid); + webBrowser2.Silent = true; + } + } + } +} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/Standard/Wpf/SplashScreen.cs b/Microsoft.Windows.Shell/Standard/Wpf/SplashScreen.cs new file mode 100644 index 0000000..4abab04 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/Wpf/SplashScreen.cs @@ -0,0 +1,344 @@ + +namespace Standard +{ + using System; + using System.Globalization; + using System.IO; + using System.Reflection; + using System.Resources; + using System.Runtime.InteropServices; + using System.Windows; + using System.Windows.Threading; + + // Current issues with this implementation: + // * FadeOutDuration will pop the splashscreen in front of the main window. This can be partially managed + // by using IsTopMost, but that has other effects. I should be able to hook the WndProc to keep this + // window from going inactive. + // * FadeInDuration doesn't work because this is being created on the main UI thread. For multiple reasons we + // should probably create this window on a background thread. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable")] + public class SplashScreen + { + private static readonly BLENDFUNCTION _BaseBlendFunction = new BLENDFUNCTION + { + BlendOp = AC.SRC_OVER, + BlendFlags = 0, + SourceConstantAlpha = 255, + AlphaFormat = AC.SRC_ALPHA, + }; + + private MessageWindow _hwndWrapper; + private SafeHBITMAP _hBitmap; + private DispatcherTimer _dt; + private DateTime _fadeOutEnd; + private DateTime _fadeInEnd; + private ResourceManager _resourceManager; + private string _resourceName; + private Dispatcher _dispatcher; + private Assembly _resourceAssembly; + private bool _isClosed = false; + + private void _VerifyMutability() + { + if (_hwndWrapper != null) + { + throw new InvalidOperationException("Splash screen has already been shown."); + } + } + + public SplashScreen() { } + + public Assembly ResourceAssembly + { + get { return _resourceAssembly; } + set + { + _VerifyMutability(); + + Verify.IsNotNull(value, "value"); + + _resourceAssembly = value; + AssemblyName name = new AssemblyName(_resourceAssembly.FullName); + _resourceManager = new ResourceManager(name.Name + ".g", _resourceAssembly); + } + } + + public string ResourceName + { + get { return _resourceName ?? ""; } + set + { + Verify.IsNeitherNullNorEmpty(value, "value"); + _resourceName = value.ToLowerInvariant(); + } + } + + public string ImageFileName { get; set; } + public bool IsTopMost { get; set; } + public bool CloseOnMainWindowCreation { get; set; } + public TimeSpan FadeOutDuration { get; set; } + public TimeSpan FadeInDuration { get; set; } + + public void Show() + { + _VerifyMutability(); + + Stream imageStream = null; + try + { + // Try to use the filepath first. If it's not provided or not available, use the embedded resource. + if (!string.IsNullOrEmpty(ImageFileName) && File.Exists(ImageFileName)) + { + try + { + imageStream = new FileStream(ImageFileName, FileMode.Open); + } + catch (IOException) { } + } + + if (imageStream == null) + { + imageStream = _resourceManager.GetStream(ResourceName, CultureInfo.CurrentUICulture); + if (imageStream == null) + { + throw new IOException("The resource could not be found."); + } + } + + Size bitmapSize; + _hBitmap = _CreateHBITMAPFromImageStream(imageStream, out bitmapSize); + + Point location = new Point( + (NativeMethods.GetSystemMetrics(SM.CXSCREEN) - bitmapSize.Width) / 2, + (NativeMethods.GetSystemMetrics(SM.CYSCREEN) - bitmapSize.Height) / 2); + + // Pass a null WndProc. Let the MessageWindow use DefWindowProc. + _hwndWrapper = new MessageWindow( + CS.HREDRAW | CS.VREDRAW, + WS.POPUP | WS.VISIBLE, + WS_EX.WINDOWEDGE | WS_EX.TOOLWINDOW | WS_EX.LAYERED | (IsTopMost ? WS_EX.TOPMOST : 0), + new Rect(location, bitmapSize), + "Splash Screen", + null); + + byte opacity = (byte)(FadeInDuration > TimeSpan.Zero ? 0 : 255); + + using (SafeDC hScreenDC = SafeDC.GetDesktop()) + { + using (SafeDC memDC = SafeDC.CreateCompatibleDC(hScreenDC)) + { + IntPtr hOldBitmap = NativeMethods.SelectObject(memDC, _hBitmap); + + RECT hwndRect = NativeMethods.GetWindowRect(_hwndWrapper.Handle); + + POINT hwndPos = hwndRect.Position; + SIZE hwndSize = hwndRect.Size; + POINT origin = new POINT(); + BLENDFUNCTION bf = _BaseBlendFunction; + bf.SourceConstantAlpha = opacity; + + NativeMethods.UpdateLayeredWindow(_hwndWrapper.Handle, hScreenDC, ref hwndPos, ref hwndSize, memDC, ref origin, 0, ref bf, ULW.ALPHA); + NativeMethods.SelectObject(memDC, hOldBitmap); + } + } + + + if (CloseOnMainWindowCreation) + { + Dispatcher.CurrentDispatcher.BeginInvoke( + DispatcherPriority.Loaded, + (DispatcherOperationCallback)delegate(object splashObj) + { + var splashScreen = (SplashScreen)splashObj; + if (!splashScreen._isClosed) + { + splashScreen.Close(); + } + return null; + }, + this); + } + + _dispatcher = Dispatcher.CurrentDispatcher; + if (FadeInDuration > TimeSpan.Zero) + { + _fadeInEnd = DateTime.UtcNow + FadeInDuration; + _dt = new DispatcherTimer(FadeInDuration, DispatcherPriority.Normal, _FadeInTick, _dispatcher); + _dt.Start(); + } + } + finally + { + Utility.SafeDispose(ref imageStream); + } + } + + public void Close() + { + if (!_dispatcher.CheckAccess()) + { + _dispatcher.Invoke(DispatcherPriority.Normal, (Action)Close); + return; + } + + if (_isClosed) + { + throw new InvalidOperationException("Splash screen was already closed"); + } + + _isClosed = true; + + if (FadeOutDuration <= TimeSpan.Zero) + { + _DestroyResources(); + return; + } + + try + { + NativeMethods.SetActiveWindow(_hwndWrapper.Handle); + } + catch + { + // SetActiveWindow fails if the application is not in the foreground. + // If this is the case, don't bother animating the fade out. + _DestroyResources(); + return; + } + + _fadeOutEnd = DateTime.UtcNow + FadeOutDuration; + if (_dt != null) + { + _dt.Stop(); + } + _dt = new DispatcherTimer(TimeSpan.FromMilliseconds(30), DispatcherPriority.Normal, _FadeOutTick, _dispatcher); + _dt.Start(); + + return; + } + + private void _FadeOutTick(object unused, EventArgs args) + { + DateTime dtNow = DateTime.UtcNow; + if (dtNow >= _fadeOutEnd) + { + _DestroyResources(); + } + else + { + double progress = (_fadeOutEnd - dtNow).TotalMilliseconds / FadeOutDuration.TotalMilliseconds; + BLENDFUNCTION bf = _BaseBlendFunction; + bf.SourceConstantAlpha = (byte)(255 * progress); + NativeMethods.UpdateLayeredWindow(_hwndWrapper.Handle, 0, ref bf, ULW.ALPHA); + } + } + + private void _FadeInTick(object unused, EventArgs args) + { + DateTime dtNow = DateTime.UtcNow; + if (dtNow >= _fadeInEnd) + { + _DestroyResources(); + } + else + { + double progress = 1 - (_fadeInEnd - dtNow).TotalMilliseconds / FadeInDuration.TotalMilliseconds; + progress = Math.Max(0, Math.Min(progress, 1)); + BLENDFUNCTION bf = _BaseBlendFunction; + bf.SourceConstantAlpha = (byte)(int)(255 * progress); + NativeMethods.UpdateLayeredWindow(_hwndWrapper.Handle, 0, ref bf, ULW.ALPHA); + } + } + + private void _DestroyResources() + { + if (_dt != null) + { + _dt.Stop(); + _dt = null; + } + Utility.SafeDispose(ref _hwndWrapper); + Utility.SafeDispose(ref _hBitmap); + if (_resourceManager != null) + { + _resourceManager.ReleaseAllResources(); + } + } + + private static SafeHBITMAP _CreateHBITMAPFromImageStream(Stream imgStream, out Size bitmapSize) + { + IWICImagingFactory pImagingFactory = null; + IWICBitmapDecoder pDecoder = null; + IWICStream pStream = null; + IWICBitmapFrameDecode pDecodedFrame = null; + IWICFormatConverter pBitmapSourceFormatConverter = null; + IWICBitmapFlipRotator pBitmapFlipRotator = null; + + SafeHBITMAP hbmp = null; + try + { + using (var istm = new ManagedIStream(imgStream)) + { + pImagingFactory = CLSID.CoCreateInstance(CLSID.WICImagingFactory); + pStream = pImagingFactory.CreateStream(); + pStream.InitializeFromIStream(istm); + + // Create an object that will decode the encoded image + Guid vendor = Guid.Empty; + pDecoder = pImagingFactory.CreateDecoderFromStream(pStream, ref vendor, WICDecodeMetadata.CacheOnDemand); + + pDecodedFrame = pDecoder.GetFrame(0); + pBitmapSourceFormatConverter = pImagingFactory.CreateFormatConverter(); + + // Convert the image from whatever format it is in to 32bpp premultiplied alpha BGRA + Guid pixelFormat = WICPixelFormat.WICPixelFormat32bppPBGRA; + pBitmapSourceFormatConverter.Initialize(pDecodedFrame, ref pixelFormat, WICBitmapDitherType.None, IntPtr.Zero, 0, WICBitmapPaletteType.Custom); + + pBitmapFlipRotator = pImagingFactory.CreateBitmapFlipRotator(); + pBitmapFlipRotator.Initialize(pBitmapSourceFormatConverter, WICBitmapTransform.FlipVertical); + + int width, height; + pBitmapFlipRotator.GetSize(out width, out height); + + bitmapSize = new Size { Width = width, Height = height }; + + var bmi = new BITMAPINFO + { + bmiHeader = new BITMAPINFOHEADER + { + biSize = Marshal.SizeOf(typeof(BITMAPINFOHEADER)), + biWidth = width, + biHeight = height, + biPlanes = 1, + biBitCount = 32, + biCompression = BI.RGB, + biSizeImage = (width * height * 4), + }, + }; + + // Create a 32bpp DIB. This DIB must have an alpha channel for UpdateLayeredWindow to succeed. + IntPtr pBitmapBits; + hbmp = NativeMethods.CreateDIBSection(null, ref bmi, out pBitmapBits, IntPtr.Zero, 0); + + // Copy the decoded image to the new buffer which backs the HBITMAP + var rect = new WICRect { X = 0, Y = 0, Width = width, Height = height }; + pBitmapFlipRotator.CopyPixels(ref rect, width * 4, bmi.bmiHeader.biSizeImage, pBitmapBits); + + var ret = hbmp; + hbmp = null; + return ret; + } + } + finally + { + Utility.SafeRelease(ref pImagingFactory); + Utility.SafeRelease(ref pDecoder); + Utility.SafeRelease(ref pStream); + Utility.SafeRelease(ref pDecodedFrame); + Utility.SafeRelease(ref pBitmapFlipRotator); + Utility.SafeRelease(ref pBitmapSourceFormatConverter); + Utility.SafeDispose(ref hbmp); + } + } + } +} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/Standard/Wpf/Utilities.Wpf.cs b/Microsoft.Windows.Shell/Standard/Wpf/Utilities.Wpf.cs new file mode 100644 index 0000000..b520a35 --- /dev/null +++ b/Microsoft.Windows.Shell/Standard/Wpf/Utilities.Wpf.cs @@ -0,0 +1,411 @@ +// This file contains general utilities to aid in development. +// Classes here generally shouldn't be exposed publicly since +// they're not particular to any library functionality. +// Because the classes here are internal, it's likely this file +// might be included in multiple assemblies. +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Reflection; + using System.Runtime.InteropServices; + using System.Security.Cryptography; + using System.Text; + using System.Windows; + using System.Windows.Media; + using System.Windows.Media.Imaging; + + internal static partial class Utility + { + private static readonly Version _presentationFrameworkVersion = Assembly.GetAssembly(typeof(Window)).GetName().Version; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static byte[] GetBytesFromBitmapSource(BitmapSource bmp) + { + int width = bmp.PixelWidth; + int height = bmp.PixelHeight; + int stride = width * ((bmp.Format.BitsPerPixel + 7) / 8); + + var pixels = new byte[height * stride]; + + bmp.CopyPixels(pixels, stride, 0); + + return pixels; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static BitmapSource GenerateBitmapSource(ImageSource img) + { + return GenerateBitmapSource(img, img.Width, img.Height); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static BitmapSource GenerateBitmapSource(ImageSource img, double renderWidth, double renderHeight) + { + var dv = new DrawingVisual(); + using (DrawingContext dc = dv.RenderOpen()) + { + dc.DrawImage(img, new Rect(0, 0, renderWidth, renderHeight)); + } + var bmp = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32); + bmp.Render(dv); + return bmp; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static BitmapSource GenerateBitmapSource(UIElement element, double renderWidth, double renderHeight, bool performLayout) + { + if (performLayout) + { + element.Measure(new Size(renderWidth, renderHeight)); + element.Arrange(new Rect(new Size(renderWidth, renderHeight))); + } + + var bmp = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32); + var dv = new DrawingVisual(); + using (DrawingContext dc = dv.RenderOpen()) + { + dc.DrawRectangle(new VisualBrush(element), null, new Rect(0, 0, renderWidth, renderHeight)); + } + bmp.Render(dv); + return bmp; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SaveToPng(BitmapSource source, string fileName) + { + var encoder = new PngBitmapEncoder(); + encoder.Frames.Add(BitmapFrame.Create(source)); + + using (FileStream stream = File.Create(fileName)) + { + encoder.Save(stream); + } + } + + // This can be cached. It's not going to change under reasonable circumstances. + private static int s_bitDepth; // = 0; + private static int _GetBitDepth() + { + if (s_bitDepth == 0) + { + using (SafeDC dc = SafeDC.GetDesktop()) + { + s_bitDepth = NativeMethods.GetDeviceCaps(dc, DeviceCap.BITSPIXEL) * NativeMethods.GetDeviceCaps(dc, DeviceCap.PLANES); + } + } + return s_bitDepth; + } + + public static BitmapFrame GetBestMatch(IList frames, int width, int height) + { + return _GetBestMatch(frames, _GetBitDepth(), width, height); + } + + private static int _MatchImage(BitmapFrame frame, int bitDepth, int width, int height, int bpp) + { + int score = 2 * _WeightedAbs(bpp, bitDepth, false) + + _WeightedAbs(frame.PixelWidth, width, true) + + _WeightedAbs(frame.PixelHeight, height, true); + + return score; + } + + private static int _WeightedAbs(int valueHave, int valueWant, bool fPunish) + { + int diff = (valueHave - valueWant); + + if (diff < 0) + { + diff = (fPunish ? -2 : -1) * diff; + } + + return diff; + } + + /// From a list of BitmapFrames find the one that best matches the requested dimensions. + /// The methods used here are copied from Win32 sources. We want to be consistent with + /// system behaviors. + private static BitmapFrame _GetBestMatch(IList frames, int bitDepth, int width, int height) + { + int bestScore = int.MaxValue; + int bestBpp = 0; + int bestIndex = 0; + + bool isBitmapIconDecoder = frames[0].Decoder is IconBitmapDecoder; + + for (int i = 0; i < frames.Count && bestScore != 0; ++i) + { + int currentIconBitDepth = isBitmapIconDecoder ? frames[i].Thumbnail.Format.BitsPerPixel : frames[i].Format.BitsPerPixel; + + if (currentIconBitDepth == 0) + { + currentIconBitDepth = 8; + } + + int score = _MatchImage(frames[i], bitDepth, width, height, currentIconBitDepth); + if (score < bestScore) + { + bestIndex = i; + bestBpp = currentIconBitDepth; + bestScore = score; + } + else if (score == bestScore) + { + // Tie breaker: choose the higher color depth. If that fails, choose first one. + if (bestBpp < currentIconBitDepth) + { + bestIndex = i; + bestBpp = currentIconBitDepth; + } + } + } + + return frames[bestIndex]; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int RGB(Color c) + { + return c.R | (c.G << 8) | (c.B << 16); + } + + public static int AlphaRGB(Color c) + { + return c.R | (c.G << 8) | (c.B << 16) | (c.A << 24); + } + + /// Convert a native integer that represent a color with an alpha channel into a Color struct. + /// The integer that represents the color. Its bits are of the format 0xAARRGGBB. + /// A Color representation of the parameter. + public static Color ColorFromArgbDword(uint color) + { + return Color.FromArgb( + (byte)((color & 0xFF000000) >> 24), + (byte)((color & 0x00FF0000) >> 16), + (byte)((color & 0x0000FF00) >> 8), + (byte)((color & 0x000000FF) >> 0)); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool AreImageSourcesEqual(ImageSource left, ImageSource right) + { + if (null == left) + { + return right == null; + } + if (null == right) + { + return false; + } + + BitmapSource leftBmp = GenerateBitmapSource(left); + BitmapSource rightBmp = GenerateBitmapSource(right); + + byte[] leftPixels = GetBytesFromBitmapSource(leftBmp); + byte[] rightPixels = GetBytesFromBitmapSource(rightBmp); + + if (leftPixels.Length != rightPixels.Length) + { + return false; + } + + return MemCmp(leftPixels, rightPixels, leftPixels.Length); + } + + /// + /// Is this using WPF4? + /// + /// + /// There are a few specific bugs in Window in 3.5SP1 and below that require workarounds + /// when handling WM_NCCALCSIZE on the HWND. + /// + public static bool IsPresentationFrameworkVersionLessThan4 + { + get { return _presentationFrameworkVersion < new Version(4, 0); } + } + + // Caller is responsible for destroying the HICON + // Caller is responsible to ensure that GDI+ has been initialized. + [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr GenerateHICON(ImageSource image, Size dimensions) + { + if (image == null) + { + return IntPtr.Zero; + } + + // If we're getting this from a ".ico" resource, then it comes through as a BitmapFrame. + // We can use leverage this as a shortcut to get the right 16x16 representation + // because DrawImage doesn't do that for us. + var bf = image as BitmapFrame; + if (bf != null) + { + bf = GetBestMatch(bf.Decoder.Frames, (int)dimensions.Width, (int)dimensions.Height); + } + else + { + // Constrain the dimensions based on the aspect ratio. + var drawingDimensions = new Rect(0, 0, dimensions.Width, dimensions.Height); + + // There's no reason to assume that the requested image dimensions are square. + double renderRatio = dimensions.Width / dimensions.Height; + double aspectRatio = image.Width / image.Height; + + // If it's smaller than the requested size, then place it in the middle and pad the image. + if (image.Width <= dimensions.Width && image.Height <= dimensions.Height) + { + drawingDimensions = new Rect((dimensions.Width - image.Width) / 2, (dimensions.Height - image.Height) / 2, image.Width, image.Height); + } + else if (renderRatio > aspectRatio) + { + double scaledRenderWidth = (image.Width / image.Height) * dimensions.Width; + drawingDimensions = new Rect((dimensions.Width - scaledRenderWidth) / 2, 0, scaledRenderWidth, dimensions.Height); + } + else if (renderRatio < aspectRatio) + { + double scaledRenderHeight = (image.Height / image.Width) * dimensions.Height; + drawingDimensions = new Rect(0, (dimensions.Height - scaledRenderHeight) / 2, dimensions.Width, scaledRenderHeight); + } + + var dv = new DrawingVisual(); + DrawingContext dc = dv.RenderOpen(); + dc.DrawImage(image, drawingDimensions); + dc.Close(); + + var bmp = new RenderTargetBitmap((int)dimensions.Width, (int)dimensions.Height, 96, 96, PixelFormats.Pbgra32); + bmp.Render(dv); + bf = BitmapFrame.Create(bmp); + } + + // Using GDI+ to convert to an HICON. + // I'd rather not duplicate their code. + using (MemoryStream memstm = new MemoryStream()) + { + BitmapEncoder enc = new PngBitmapEncoder(); + enc.Frames.Add(bf); + enc.Save(memstm); + + using (var istm = new ManagedIStream(memstm)) + { + // We are not bubbling out GDI+ errors when creating the native image fails. + IntPtr bitmap = IntPtr.Zero; + try + { + Status gpStatus = NativeMethods.GdipCreateBitmapFromStream(istm, out bitmap); + if (Status.Ok != gpStatus) + { + return IntPtr.Zero; + } + + IntPtr hicon; + gpStatus = NativeMethods.GdipCreateHICONFromBitmap(bitmap, out hicon); + if (Status.Ok != gpStatus) + { + return IntPtr.Zero; + } + + // Caller is responsible for freeing this. + return hicon; + } + finally + { + Utility.SafeDisposeImage(ref bitmap); + } + } + } + } + + public static void AddDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener) + { + if (component == null) + { + return; + } + Assert.IsNotNull(property); + Assert.IsNotNull(listener); + + DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType()); + dpd.AddValueChanged(component, listener); + } + + public static void RemoveDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener) + { + if (component == null) + { + return; + } + Assert.IsNotNull(property); + Assert.IsNotNull(listener); + + DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType()); + dpd.RemoveValueChanged(component, listener); + } + + public static bool IsThicknessNonNegative(Thickness thickness) + { + if (!IsDoubleFiniteAndNonNegative(thickness.Top)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(thickness.Left)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(thickness.Bottom)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(thickness.Right)) + { + return false; + } + + return true; + } + + public static bool IsCornerRadiusValid(CornerRadius cornerRadius) + { + if (!IsDoubleFiniteAndNonNegative(cornerRadius.TopLeft)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(cornerRadius.TopRight)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(cornerRadius.BottomLeft)) + { + return false; + } + + if (!IsDoubleFiniteAndNonNegative(cornerRadius.BottomRight)) + { + return false; + } + + return true; + } + + private static bool IsDoubleFiniteAndNonNegative(double d) + { + if (double.IsNaN(d) || double.IsInfinity(d) || d < 0) + { + return false; + } + + return true; + } + } +} diff --git a/Microsoft.Windows.Shell/WindowChrome.cs b/Microsoft.Windows.Shell/WindowChrome.cs index 69634ee..f35a515 100644 --- a/Microsoft.Windows.Shell/WindowChrome.cs +++ b/Microsoft.Windows.Shell/WindowChrome.cs @@ -11,6 +11,35 @@ namespace Microsoft.Windows.Shell using System.Windows.Data; using Standard; + public enum ResizeGripDirection + { + None, + TopLeft, + Top, + TopRight, + Right, + BottomRight, + Bottom, + BottomLeft, + Left, + } + + [Flags] + public enum SacrificialEdge + { + None = 0, + Left = 1, + Top = 2, + Right = 4, + Bottom = 8, + + Office = Left | Right | Bottom, + + // Don't use "All" - Handling WM_NCCALCSIZE with a client rect shrunk in all directions implicitly creates a + // normal sized caption area that doesn't actually properly participate with the rest of the implementation... + // All = Left | Top | Right | Bottom, + } + public class WindowChrome : Freezable { private struct _SystemParameterBoundProperty @@ -49,7 +78,7 @@ private static void _OnChromeChanged(DependencyObject d, DependencyPropertyChang // Update the ChromeWorker with this new object. // If there isn't currently a worker associated with the Window then assign a new one. - // There can be a many:1 relationship of to Window to WindowChrome objects, but a 1:1 for a Window and a WindowChromeWorker. + // There can be a many:1 relationship of Window to WindowChrome objects, but a 1:1 for a Window and a WindowChromeWorker. WindowChromeWorker chromeWorker = WindowChromeWorker.GetWindowChromeWorker(window); if (chromeWorker == null) { @@ -108,6 +137,38 @@ public static void SetIsHitTestVisibleInChrome(IInputElement inputElement, bool dobj.SetValue(IsHitTestVisibleInChromeProperty, hitTestVisible); } + public static readonly DependencyProperty ResizeGripDirectionProperty = DependencyProperty.RegisterAttached( + "ResizeGripDirection", + typeof(ResizeGripDirection), + typeof(WindowChrome), + new FrameworkPropertyMetadata(ResizeGripDirection.None, FrameworkPropertyMetadataOptions.Inherits)); + + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static ResizeGripDirection GetResizeGripDirection(IInputElement inputElement) + { + Verify.IsNotNull(inputElement, "inputElement"); + var dobj = inputElement as DependencyObject; + if (dobj == null) + { + throw new ArgumentException("The element must be a DependencyObject", "inputElement"); + } + return (ResizeGripDirection)dobj.GetValue(ResizeGripDirectionProperty); + } + + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + [SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] + public static void SetResizeGripDirection(IInputElement inputElement, ResizeGripDirection direction) + { + Verify.IsNotNull(inputElement, "inputElement"); + var dobj = inputElement as DependencyObject; + if (dobj == null) + { + throw new ArgumentException("The element must be a DependencyObject", "inputElement"); + } + dobj.SetValue(ResizeGripDirectionProperty, direction); + } + #endregion #region Dependency Properties @@ -161,12 +222,25 @@ private static object _CoerceGlassFrameThickness(Thickness thickness) return thickness; } + public Thickness GlassFrameThickness { get { return (Thickness)GetValue(GlassFrameThicknessProperty); } set { SetValue(GlassFrameThicknessProperty, value); } } + public static readonly DependencyProperty UseAeroCaptionButtonsProperty = DependencyProperty.Register( + "UseAeroCaptionButtons", + typeof(bool), + typeof(WindowChrome), + new FrameworkPropertyMetadata(true)); + + public bool UseAeroCaptionButtons + { + get { return (bool)GetValue(UseAeroCaptionButtonsProperty); } + set { SetValue(UseAeroCaptionButtonsProperty, value); } + } + public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register( "CornerRadius", typeof(CornerRadius), @@ -182,6 +256,55 @@ public CornerRadius CornerRadius set { SetValue(CornerRadiusProperty, value); } } + public static readonly DependencyProperty SacrificialEdgeProperty = DependencyProperty.Register( + "SacrificialEdge", + typeof(SacrificialEdge), + typeof(WindowChrome), + new PropertyMetadata( + SacrificialEdge.None, + (d, e) => ((WindowChrome)d)._OnPropertyChangedThatRequiresRepaint()), + _IsValidSacrificialEdge); + + private static readonly SacrificialEdge SacrificialEdge_All = SacrificialEdge.Bottom | SacrificialEdge.Top | SacrificialEdge.Left | SacrificialEdge.Right; + + private static bool _IsValidSacrificialEdge(object value) + { + SacrificialEdge se = SacrificialEdge.None; + try + { + se = (SacrificialEdge)value; + } + catch (InvalidCastException) + { + return false; + } + + if (se == SacrificialEdge.None) + { + return true; + } + + // Does this only contain valid bits? + if ((se | SacrificialEdge_All) != SacrificialEdge_All) + { + return false; + } + + // It can't sacrifice all 4 edges. Weird things happen. + if (se == SacrificialEdge_All) + { + return false; + } + + return true; + } + + public SacrificialEdge SacrificialEdge + { + get { return (SacrificialEdge)GetValue(SacrificialEdgeProperty); } + set { SetValue(SacrificialEdgeProperty, value); } + } + #endregion protected override Freezable CreateInstanceCore() diff --git a/Microsoft.Windows.Shell/WindowChromeWorker.cs b/Microsoft.Windows.Shell/WindowChromeWorker.cs index 883b7e7..b8fe06f 100644 --- a/Microsoft.Windows.Shell/WindowChromeWorker.cs +++ b/Microsoft.Windows.Shell/WindowChromeWorker.cs @@ -41,9 +41,6 @@ internal class WindowChromeWorker : DependencyObject private bool _hasUserMovedWindow = false; private Point _windowPosAtStartOfUserMove = default(Point); - // Field to track attempts to force off Device Bitmaps on Win7. - private int _blackGlassFixupAttemptCount; - /// Object that describes the current modifications being made to the chrome. private WindowChrome _chromeInfo; @@ -144,13 +141,18 @@ private void _SetWindow(Window window) // If the window hasn't yet been shown, then we need to make sure to remove hooks after it's closed. _hwnd = new WindowInteropHelper(_window).Handle; - if (Utility.IsPresentationFrameworkVersionLessThan4) - { - // On older versions of the framework the client size of the window is incorrectly calculated. - // We need to modify the template to fix this on behalf of the user. - Utility.AddDependencyPropertyChangeListener(_window, Window.TemplateProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); - Utility.AddDependencyPropertyChangeListener(_window, Window.FlowDirectionProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); - } + // if (Utility.IsPresentationFrameworkVersionLessThan4) + // { + + // On older versions of the framework the client size of the window is incorrectly calculated. + // We need to modify the template to fix this on behalf of the user. + + // This should only be required on older versions of the framework, but because of a DWM bug in Windows 7 we're exposing + // the SacrificialEdge property which requires this kind of fixup to be a bit more ubiquitous. + Utility.AddDependencyPropertyChangeListener(_window, Window.TemplateProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); + Utility.AddDependencyPropertyChangeListener(_window, Window.FlowDirectionProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); + + // } _window.Closed += _UnsetWindow; @@ -187,11 +189,9 @@ private void _SetWindow(Window window) private void _UnsetWindow(object sender, EventArgs e) { - if (Utility.IsPresentationFrameworkVersionLessThan4) - { - Utility.RemoveDependencyPropertyChangeListener(_window, Window.TemplateProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); - Utility.RemoveDependencyPropertyChangeListener(_window, Window.FlowDirectionProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); - } + // if (Utility.IsPresentationFrameworkVersionLessThan4) + Utility.RemoveDependencyPropertyChangeListener(_window, Window.TemplateProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); + Utility.RemoveDependencyPropertyChangeListener(_window, Window.FlowDirectionProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); if (_chromeInfo != null) { @@ -217,16 +217,14 @@ public static void SetWindowChromeWorker(Window window, WindowChromeWorker chrom private void _OnWindowPropertyChangedThatRequiresTemplateFixup(object sender, EventArgs e) { - Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); - if (_chromeInfo != null && _hwnd != IntPtr.Zero) { // Assume that when the template changes it's going to be applied. // We don't have a good way to externally hook into the template // actually being applied, so we asynchronously post the fixup operation // at Loaded priority, so it's expected that the visual tree will be - // updated before _FixupFrameworkIssues is called. - _window.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (_Action)_FixupFrameworkIssues); + // updated before _FixupTemplateIssues is called. + _window.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (_Action)_FixupTemplateIssues); } } @@ -250,7 +248,7 @@ private void _ApplyNewCustomChrome() _isHooked = true; } - _FixupFrameworkIssues(); + _FixupTemplateIssues(); // Force this the first time. _UpdateSystemMenu(_window.WindowState); @@ -259,18 +257,11 @@ private void _ApplyNewCustomChrome() NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, _SwpFlags); } - private void _FixupFrameworkIssues() + private void _FixupTemplateIssues() { Assert.IsNotNull(_chromeInfo); Assert.IsNotNull(_window); - // This margin is only necessary if the client rect is going to be calculated incorrectly by WPF. - // This bug was fixed in V4 of the framework. - if (!Utility.IsPresentationFrameworkVersionLessThan4) - { - return; - } - if (_window.Template == null) { // Nothing to fixup yet. This will get called again when a template does get set. @@ -282,106 +273,86 @@ private void _FixupFrameworkIssues() { // The template isn't null, but we don't have a visual tree. // Hope that ApplyTemplate is in the queue and repost this, because there's not much we can do right now. - _window.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (_Action)_FixupFrameworkIssues); + _window.Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (_Action)_FixupTemplateIssues); return; } - var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0); - - RECT rcWindow = NativeMethods.GetWindowRect(_hwnd); - RECT rcAdjustedClient = _GetAdjustedWindowRect(rcWindow); - - Rect rcLogicalWindow = DpiHelper.DeviceRectToLogical(new Rect(rcWindow.Left, rcWindow.Top, rcWindow.Width, rcWindow.Height)); - Rect rcLogicalClient = DpiHelper.DeviceRectToLogical(new Rect(rcAdjustedClient.Left, rcAdjustedClient.Top, rcAdjustedClient.Width, rcAdjustedClient.Height)); - - Thickness nonClientThickness = new Thickness( - rcLogicalWindow.Left - rcLogicalClient.Left, - rcLogicalWindow.Top - rcLogicalClient.Top, - rcLogicalClient.Right - rcLogicalWindow.Right, - rcLogicalClient.Bottom - rcLogicalWindow.Bottom); - - rootElement.Margin = new Thickness( - 0, - 0, - -(nonClientThickness.Left + nonClientThickness.Right), - -(nonClientThickness.Top + nonClientThickness.Bottom)); - - // The negative thickness on the margin doesn't properly get applied in RTL layouts. - // The width is right, but there is a black bar on the right. - // To fix this we just add an additional RenderTransform to the root element. - // This works fine, but if the window is dynamically changing its FlowDirection then this can have really bizarre side effects. - // This will mostly work if the FlowDirection is dynamically changed, but there aren't many real scenarios that would call for - // that so I'm not addressing the rest of the quirkiness. - if (_window.FlowDirection == FlowDirection.RightToLeft) - { - rootElement.RenderTransform = new MatrixTransform(1, 0, 0, 1, -(nonClientThickness.Left + nonClientThickness.Right), 0); - } - else - { - rootElement.RenderTransform = null; - } - - if (!_isFixedUp) - { - _hasUserMovedWindow = false; - _window.StateChanged += _FixupRestoreBounds; - - _isFixedUp = true; - } - } + Thickness templateFixupMargin = default(Thickness); + Transform templateFixupTransform = null; - // There was a regression in DWM in Windows 7 with regard to handling WM_NCCALCSIZE to effect custom chrome. - // When windows with glass are maximized on a multimonitor setup the glass frame tends to turn black. - // Also when windows are resized they tend to flicker black, sometimes staying that way until resized again. - // - // This appears to be a bug in DWM related to device bitmap optimizations. At least on RTM Win7 we can - // evoke a legacy code path that bypasses the bug by calling an esoteric DWM function. This doesn't affect - // the system, just the application. - // WPF also tends to call this function anyways during animations, so we're just forcing the issue - // consistently and a bit earlier. - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - private void _FixupWindows7Issues() - { - if (_blackGlassFixupAttemptCount > 5) + if (Utility.IsPresentationFrameworkVersionLessThan4) { - // Don't keep trying if there's an endemic problem with this. - return; + RECT rcWindow = NativeMethods.GetWindowRect(_hwnd); + RECT rcAdjustedClient = _GetAdjustedWindowRect(rcWindow); + + Rect rcLogicalWindow = DpiHelper.DeviceRectToLogical(new Rect(rcWindow.Left, rcWindow.Top, rcWindow.Width, rcWindow.Height)); + Rect rcLogicalClient = DpiHelper.DeviceRectToLogical(new Rect(rcAdjustedClient.Left, rcAdjustedClient.Top, rcAdjustedClient.Width, rcAdjustedClient.Height)); + + Thickness nonClientThickness = new Thickness( + rcLogicalWindow.Left - rcLogicalClient.Left, + rcLogicalWindow.Top - rcLogicalClient.Top, + rcLogicalClient.Right - rcLogicalWindow.Right, + rcLogicalClient.Bottom - rcLogicalWindow.Bottom); + + templateFixupMargin = new Thickness( + 0, + 0, + -(nonClientThickness.Left + nonClientThickness.Right), + -(nonClientThickness.Top + nonClientThickness.Bottom)); + + // The negative thickness on the margin doesn't properly get applied in RTL layouts. + // The width is right, but there is a black bar on the right. + // To fix this we just add an additional RenderTransform to the root element. + // This works fine, but if the window is dynamically changing its FlowDirection then this can have really bizarre side effects. + // This will mostly work if the FlowDirection is dynamically changed, but there aren't many real scenarios that would call for + // that so I'm not addressing the rest of the quirkiness. + if (_window.FlowDirection == FlowDirection.RightToLeft) + { + templateFixupTransform = new MatrixTransform(1, 0, 0, 1, -(nonClientThickness.Left + nonClientThickness.Right), 0); + } + else + { + templateFixupTransform = null; + } } - if (Utility.IsOSWindows7OrNewer && NativeMethods.DwmIsCompositionEnabled()) + if (_chromeInfo.SacrificialEdge != SacrificialEdge.None) { - ++_blackGlassFixupAttemptCount; - - bool success = false; - try + if (Utility.IsFlagSet((int)_chromeInfo.SacrificialEdge, (int)SacrificialEdge.Top)) { - DWM_TIMING_INFO? dti = NativeMethods.DwmGetCompositionTimingInfo(_hwnd); - success = dti != null; + templateFixupMargin.Top -= SystemParameters2.Current.WindowResizeBorderThickness.Top; } - catch (Exception) + if (Utility.IsFlagSet((int)_chromeInfo.SacrificialEdge, (int)SacrificialEdge.Left)) { - // We aren't sure of all the reasons this could fail. - // If we find new ones we should consider making the NativeMethod swallow them as well. - // Since we have a limited number of retries and this method isn't actually critical, just repost. - - // Disabling this for the published code to reduce debug noise. This will get compiled away for retail binaries anyways. - //Assert.Fail(e.Message); + templateFixupMargin.Left -= SystemParameters2.Current.WindowResizeBorderThickness.Left; } - - // NativeMethods.DwmGetCompositionTimingInfo swallows E_PENDING. - // If the call wasn't successful, try again later. - if (!success) + if (Utility.IsFlagSet((int)_chromeInfo.SacrificialEdge, (int)SacrificialEdge.Bottom)) { - Dispatcher.BeginInvoke(DispatcherPriority.Loaded, (_Action)_FixupWindows7Issues); + templateFixupMargin.Bottom -= SystemParameters2.Current.WindowResizeBorderThickness.Bottom; } - else + if (Utility.IsFlagSet((int)_chromeInfo.SacrificialEdge, (int)SacrificialEdge.Right)) { - // Reset this. We will want to force this again if DWM composition changes. - _blackGlassFixupAttemptCount = 0; + templateFixupMargin.Right -= SystemParameters2.Current.WindowResizeBorderThickness.Right; + } + } + + var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0); + rootElement.Margin = templateFixupMargin; + rootElement.RenderTransform = templateFixupTransform; + + if (Utility.IsPresentationFrameworkVersionLessThan4) + { + if (!_isFixedUp) + { + _hasUserMovedWindow = false; + _window.StateChanged += _FixupRestoreBounds; + + _isFixedUp = true; } } } + private void _FixupRestoreBounds(object sender, EventArgs e) { Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); @@ -492,59 +463,125 @@ private IntPtr _HandleNCActivate(WM uMsg, IntPtr wParam, IntPtr lParam, out bool return lRet; } + // There was a regression in DWM in Windows 7 with regard to handling WM_NCCALCSIZE to effect custom chrome. + // When windows with glass are maximized on a multimonitor setup the glass frame tends to turn black. + // Also when windows are resized they tend to flicker black, sometimes staying that way until resized again. + // + // This appears to be a bug in DWM related to device bitmap optimizations. At least on RTM Win7 we can avoid + // the problem by making the client area not extactly match the non-client area, so we added the SacrificialEdge property. private IntPtr _HandleNCCalcSize(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) { // lParam is an [in, out] that can be either a RECT* (wParam == FALSE) or an NCCALCSIZE_PARAMS*. // Since the first field of NCCALCSIZE_PARAMS is a RECT and is the only field we care about // we can unconditionally treat it as a RECT. - // Since we always want the client size to equal the window size, we can unconditionally handle it - // without having to modify the parameters. + if (_chromeInfo.SacrificialEdge != SacrificialEdge.None) + { + Thickness windowResizeBorderThicknessDevice = DpiHelper.LogicalThicknessToDevice(SystemParameters2.Current.WindowResizeBorderThickness); + var rcClientArea = (RECT)Marshal.PtrToStructure(lParam, typeof(RECT)); + if (Utility.IsFlagSet((int)_chromeInfo.SacrificialEdge, (int)SacrificialEdge.Top)) + { + rcClientArea.Top += (int)windowResizeBorderThicknessDevice.Top; + } + if (Utility.IsFlagSet((int)_chromeInfo.SacrificialEdge, (int)SacrificialEdge.Left)) + { + rcClientArea.Left += (int)windowResizeBorderThicknessDevice.Left; + } + if (Utility.IsFlagSet((int)_chromeInfo.SacrificialEdge, (int)SacrificialEdge.Bottom)) + { + rcClientArea.Bottom -= (int)windowResizeBorderThicknessDevice.Bottom; + } + if (Utility.IsFlagSet((int)_chromeInfo.SacrificialEdge, (int)SacrificialEdge.Right)) + { + rcClientArea.Right -= (int)windowResizeBorderThicknessDevice.Right; + } + + Marshal.StructureToPtr(rcClientArea, lParam, false); + } handled = true; return new IntPtr((int)WVR.REDRAW); } - private IntPtr _HandleNCHitTest(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + private HT _GetHTFromResizeGripDirection(ResizeGripDirection direction) { - IntPtr lRet = IntPtr.Zero; - handled = false; - - // Give DWM a chance at this first. - if (Utility.IsOSVistaOrNewer && _chromeInfo.GlassFrameThickness != default(Thickness) && _isGlassEnabled) + bool compliment = _window.FlowDirection == FlowDirection.RightToLeft; + switch (direction) { - // If we're on Vista, give the DWM a chance to handle the message first. - handled = NativeMethods.DwmDefWindowProc(_hwnd, uMsg, wParam, lParam, out lRet); + case ResizeGripDirection.Bottom: + return HT.BOTTOM; + case ResizeGripDirection.BottomLeft: + return compliment ? HT.BOTTOMRIGHT : HT.BOTTOMLEFT; + case ResizeGripDirection.BottomRight: + return compliment ? HT.BOTTOMLEFT : HT.BOTTOMRIGHT; + case ResizeGripDirection.Left: + return compliment ? HT.RIGHT : HT.LEFT; + case ResizeGripDirection.Right: + return compliment ? HT.LEFT : HT.RIGHT; + case ResizeGripDirection.Top: + return HT.TOP; + case ResizeGripDirection.TopLeft: + return compliment ? HT.TOPRIGHT : HT.TOPLEFT; + case ResizeGripDirection.TopRight: + return compliment ? HT.TOPLEFT : HT.TOPRIGHT; + default: + return HT.NOWHERE; } + } - // Handle letting the system know if we consider the mouse to be in our effective non-client area. - // If DWM already handled this by way of DwmDefWindowProc, then respect their call. - if (IntPtr.Zero == lRet) + private IntPtr _HandleNCHitTest(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) + { + // Let the system know if we consider the mouse to be in our effective non-client area. + var mousePosScreen = new Point(Utility.GET_X_LPARAM(lParam), Utility.GET_Y_LPARAM(lParam)); + Rect windowPosition = _GetWindowRect(); + + Point mousePosWindow = mousePosScreen; + mousePosWindow.Offset(-windowPosition.X, -windowPosition.Y); + mousePosWindow = DpiHelper.DevicePixelsToLogical(mousePosWindow); + + // If the app is asking for content to be treated as client then that takes precedence over _everything_, even DWM caption buttons. + // This allows apps to set the glass frame to be non-empty, still cover it with WPF content to hide all the glass, + // yet still get DWM to draw a drop shadow. + IInputElement inputElement = _window.InputHitTest(mousePosWindow); + if (inputElement != null) { - var mousePosScreen = new Point(Utility.GET_X_LPARAM(lParam), Utility.GET_Y_LPARAM(lParam)); - Rect windowPosition = _GetWindowRect(); + if (WindowChrome.GetIsHitTestVisibleInChrome(inputElement)) + { + handled = true; + return new IntPtr((int)HT.CLIENT); + } - HT ht = _HitTestNca( - DpiHelper.DeviceRectToLogical(windowPosition), - DpiHelper.DevicePixelsToLogical(mousePosScreen)); + ResizeGripDirection direction = WindowChrome.GetResizeGripDirection(inputElement); + if (direction != ResizeGripDirection.None) + { + handled = true; + return new IntPtr((int)_GetHTFromResizeGripDirection(direction)); + } + } - // Don't blindly respect HTCAPTION. - // We want UIElements in the caption area to be actionable so run through a hittest first. - if (ht != HT.CLIENT) + // It's not opted out, so offer up the hittest to DWM, then to our custom non-client area logic. + if (_chromeInfo.UseAeroCaptionButtons) + { + IntPtr lRet; + if (Utility.IsOSVistaOrNewer && _chromeInfo.GlassFrameThickness != default(Thickness) && _isGlassEnabled) { - Point mousePosWindow = mousePosScreen; - mousePosWindow.Offset(-windowPosition.X, -windowPosition.Y); - mousePosWindow = DpiHelper.DevicePixelsToLogical(mousePosWindow); - IInputElement inputElement = _window.InputHitTest(mousePosWindow); - if (inputElement != null && WindowChrome.GetIsHitTestVisibleInChrome(inputElement)) + // If we're on Vista, give the DWM a chance to handle the message first. + handled = NativeMethods.DwmDefWindowProc(_hwnd, uMsg, wParam, lParam, out lRet); + + if (IntPtr.Zero != lRet) { - ht = HT.CLIENT; + // If DWM claims to have handled this, then respect their call. + return lRet; } } - handled = true; - lRet = new IntPtr((int)ht); } - return lRet; + + HT ht = _HitTestNca( + DpiHelper.DeviceRectToLogical(windowPosition), + DpiHelper.DevicePixelsToLogical(mousePosScreen)); + + handled = true; + return new IntPtr((int)ht); } private IntPtr _HandleNCRButtonUp(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) @@ -616,7 +653,7 @@ private IntPtr _HandleSettingChange(WM uMsg, IntPtr wParam, IntPtr lParam, out b // These shouldn't be required on the v4 framework. Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); - _FixupFrameworkIssues(); + _FixupTemplateIssues(); handled = false; return IntPtr.Zero; @@ -813,8 +850,6 @@ private void _UpdateFrameState(bool force) { _ClearRoundingRegion(); _ExtendGlassFrame(); - - _FixupWindows7Issues(); } NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, _SwpFlags); @@ -985,10 +1020,9 @@ private static void _CreateAndCombineRoundRectRgn(IntPtr hrgnSource, Rect region throw new InvalidOperationException("Unable to combine two HRGNs."); } } - catch + finally { Utility.SafeDeleteObject(ref hrgn); - throw; } } @@ -1043,16 +1077,40 @@ private void _ExtendGlassFrame() _hwndSource.CompositionTarget.BackgroundColor = Colors.Transparent; // Thickness is going to be DIPs, need to convert to system coordinates. - Point deviceTopLeft = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.GlassFrameThickness.Left, _chromeInfo.GlassFrameThickness.Top)); - Point deviceBottomRight = DpiHelper.LogicalPixelsToDevice(new Point(_chromeInfo.GlassFrameThickness.Right, _chromeInfo.GlassFrameThickness.Bottom)); + Thickness deviceGlassThickness = DpiHelper.LogicalThicknessToDevice(_chromeInfo.GlassFrameThickness); + + if (_chromeInfo.SacrificialEdge != SacrificialEdge.None) + { + Thickness windowResizeBorderThicknessDevice = DpiHelper.LogicalThicknessToDevice(SystemParameters2.Current.WindowResizeBorderThickness); + if (Utility.IsFlagSet((int)_chromeInfo.SacrificialEdge, (int)SacrificialEdge.Top)) + { + deviceGlassThickness.Top -= windowResizeBorderThicknessDevice.Top; + deviceGlassThickness.Top = Math.Max(0, deviceGlassThickness.Top); + } + if (Utility.IsFlagSet((int)_chromeInfo.SacrificialEdge, (int)SacrificialEdge.Left)) + { + deviceGlassThickness.Left -= windowResizeBorderThicknessDevice.Left; + deviceGlassThickness.Left = Math.Max(0, deviceGlassThickness.Left); + } + if (Utility.IsFlagSet((int)_chromeInfo.SacrificialEdge, (int)SacrificialEdge.Bottom)) + { + deviceGlassThickness.Bottom -= windowResizeBorderThicknessDevice.Bottom; + deviceGlassThickness.Bottom = Math.Max(0, deviceGlassThickness.Bottom); + } + if (Utility.IsFlagSet((int)_chromeInfo.SacrificialEdge, (int)SacrificialEdge.Right)) + { + deviceGlassThickness.Right -= windowResizeBorderThicknessDevice.Right; + deviceGlassThickness.Right = Math.Max(0, deviceGlassThickness.Right); + } + } var dwmMargin = new MARGINS { // err on the side of pushing in glass an extra pixel. - cxLeftWidth = (int)Math.Ceiling(deviceTopLeft.X), - cxRightWidth = (int)Math.Ceiling(deviceBottomRight.X), - cyTopHeight = (int)Math.Ceiling(deviceTopLeft.Y), - cyBottomHeight = (int)Math.Ceiling(deviceBottomRight.Y), + cxLeftWidth = (int)Math.Ceiling(deviceGlassThickness.Left), + cxRightWidth = (int)Math.Ceiling(deviceGlassThickness.Right), + cyTopHeight = (int)Math.Ceiling(deviceGlassThickness.Top), + cyBottomHeight = (int)Math.Ceiling(deviceGlassThickness.Bottom), }; NativeMethods.DwmExtendFrameIntoClientArea(_hwnd, ref dwmMargin); @@ -1125,7 +1183,7 @@ private void _RestoreStandardChromeState(bool isClosing) if (!isClosing) { - _RestoreFrameworkIssueFixups(); + _RestoreTemplateFixups(); _RestoreGlassFrame(); _RestoreHrgn(); @@ -1145,21 +1203,23 @@ private void _UnhookCustomChrome() } } - private void _RestoreFrameworkIssueFixups() + private void _RestoreTemplateFixups() { // This margin is only necessary if the client rect is going to be calculated incorrectly by WPF. // This bug was fixed in V4 of the framework. - if (Utility.IsPresentationFrameworkVersionLessThan4) - { - Assert.IsTrue(_isFixedUp); + // But it still needs to happen if there was a SacrificialEdge. + //if (Utility.IsPresentationFrameworkVersionLessThan4) + + //Assert.IsTrue(_isFixedUp); + + Assert.Implies(Utility.IsPresentationFrameworkVersionLessThan4, () => _isFixedUp); - var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0); - // Undo anything that was done before. - rootElement.Margin = new Thickness(); + var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0); + // Undo anything that was done before. + rootElement.Margin = new Thickness(); - _window.StateChanged -= _FixupRestoreBounds; - _isFixedUp = false; - } + _window.StateChanged -= _FixupRestoreBounds; + _isFixedUp = false; } private void _RestoreGlassFrame() From 83dc3fdfef53616804f7ea4f26ba5b378e24eb4d Mon Sep 17 00:00:00 2001 From: Joe Castro Date: Wed, 8 May 2013 11:47:42 -0700 Subject: [PATCH 04/21] Switching Standard to be a submodule --- .gitignore | 4 + .gitmodules | 3 + .../Microsoft.Windows.Shell.csproj | 29 +- Microsoft.Windows.Shell/Standard/ComGuids.cs | 156 - Microsoft.Windows.Shell/Standard/Debug.cs | 398 -- .../Standard/DoubleUtil.cs | 140 - .../Standard/Enumerable2.cs | 288 -- .../Standard/ErrorCodes.cs | 631 --- .../Standard/FileWalker.cs | 114 - .../Standard/MergeableCollection.cs | 628 --- .../Standard/MessageWindow.cs | 165 - .../Standard/NativeMethods.cs | 3629 ----------------- .../Standard/NotifyingList.cs | 187 - .../Standard/ShellProvider.cs | 1309 ------ .../Standard/SmallString.cs | 253 -- Microsoft.Windows.Shell/Standard/SmallUri.cs | 151 - .../Standard/Standard.csproj | 162 - .../Standard/StreamHelper.cs | 713 ---- Microsoft.Windows.Shell/Standard/Utilities.cs | 921 ----- Microsoft.Windows.Shell/Standard/Verify.cs | 341 -- .../Standard/WicProvider.cs | 648 --- .../Standard/WindowExtensions.cs | 137 - .../Standard/Wpf/CornerRadiusAnimation.cs | 541 --- .../Standard/Wpf/CornerRadiusAnimationBase.cs | 191 - .../Standard/Wpf/DpiHelper.cs | 90 - .../Standard/Wpf/GlassHelper.cs | 283 -- .../Standard/Wpf/MshtmlProvider.cs | 407 -- .../Standard/Wpf/SplashScreen.cs | 344 -- .../Standard/Wpf/Utilities.Wpf.cs | 411 -- Microsoft.Windows.Shell/standard.net | 1 + 30 files changed, 22 insertions(+), 13253 deletions(-) create mode 100644 .gitmodules delete mode 100644 Microsoft.Windows.Shell/Standard/ComGuids.cs delete mode 100644 Microsoft.Windows.Shell/Standard/Debug.cs delete mode 100644 Microsoft.Windows.Shell/Standard/DoubleUtil.cs delete mode 100644 Microsoft.Windows.Shell/Standard/Enumerable2.cs delete mode 100644 Microsoft.Windows.Shell/Standard/ErrorCodes.cs delete mode 100644 Microsoft.Windows.Shell/Standard/FileWalker.cs delete mode 100644 Microsoft.Windows.Shell/Standard/MergeableCollection.cs delete mode 100644 Microsoft.Windows.Shell/Standard/MessageWindow.cs delete mode 100644 Microsoft.Windows.Shell/Standard/NativeMethods.cs delete mode 100644 Microsoft.Windows.Shell/Standard/NotifyingList.cs delete mode 100644 Microsoft.Windows.Shell/Standard/ShellProvider.cs delete mode 100644 Microsoft.Windows.Shell/Standard/SmallString.cs delete mode 100644 Microsoft.Windows.Shell/Standard/SmallUri.cs delete mode 100644 Microsoft.Windows.Shell/Standard/Standard.csproj delete mode 100644 Microsoft.Windows.Shell/Standard/StreamHelper.cs delete mode 100644 Microsoft.Windows.Shell/Standard/Utilities.cs delete mode 100644 Microsoft.Windows.Shell/Standard/Verify.cs delete mode 100644 Microsoft.Windows.Shell/Standard/WicProvider.cs delete mode 100644 Microsoft.Windows.Shell/Standard/WindowExtensions.cs delete mode 100644 Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimation.cs delete mode 100644 Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimationBase.cs delete mode 100644 Microsoft.Windows.Shell/Standard/Wpf/DpiHelper.cs delete mode 100644 Microsoft.Windows.Shell/Standard/Wpf/GlassHelper.cs delete mode 100644 Microsoft.Windows.Shell/Standard/Wpf/MshtmlProvider.cs delete mode 100644 Microsoft.Windows.Shell/Standard/Wpf/SplashScreen.cs delete mode 100644 Microsoft.Windows.Shell/Standard/Wpf/Utilities.Wpf.cs create mode 160000 Microsoft.Windows.Shell/standard.net diff --git a/.gitignore b/.gitignore index bdc3535..f165140 100644 --- a/.gitignore +++ b/.gitignore @@ -106,3 +106,7 @@ Generated_Code #added for RIA/Silverlight projects _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML + +.DS_Store + +*.swp diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..766d62f --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "Microsoft.Windows.Shell/standard.net"] + path = Microsoft.Windows.Shell/standard.net + url = git@github.com:joecastro/standard.net.git diff --git a/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj b/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj index 7869ff3..8079209 100644 --- a/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj +++ b/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj @@ -115,20 +115,19 @@ - - - - - - - - - - - - Code - - + + + + + + + + + + + + + @@ -165,4 +164,4 @@ --> - \ No newline at end of file + diff --git a/Microsoft.Windows.Shell/Standard/ComGuids.cs b/Microsoft.Windows.Shell/Standard/ComGuids.cs deleted file mode 100644 index 6c830cc..0000000 --- a/Microsoft.Windows.Shell/Standard/ComGuids.cs +++ /dev/null @@ -1,156 +0,0 @@ -namespace Standard -{ - internal static partial class IID - { - /// IID_IApplicationAssociationRegistration - public const string ApplicationAssociationRegistration = "4e530b0a-e611-4c77-a3ac-9031d022281b"; - /// IID_IConnectionPoint - public const string ConnectionPoint = "B196B286-BAB4-101A-B69C-00AA00341D07"; - /// IID_IConnectionPointContainer - public const string ConnectionPointContainer = "B196B284-BAB4-101A-B69C-00AA00341D07"; - public const string DragSourceHelper = "DE5BF786-477A-11D2-839D-00C04FD918D0"; - public const string DragSourceHelper2 = "83E07D0D-0C5F-4163-BF1A-60B274051E40"; - public const string DropTargetHelper = "4657278B-411B-11D2-839A-00C04FD918D0"; - /// IID_IEnumConnectionPoints - public const string EnumConnectionPoints = "B196B285-BAB4-101A-B69C-00AA00341D07"; - /// IID_IEnumConnections - public const string EnumConnections = "B196B287-BAB4-101A-B69C-00AA00341D07"; - /// IID_IEnumIDList - public const string EnumIdList = "000214F2-0000-0000-C000-000000000046"; - /// IID_IEnumObjects - public const string EnumObjects = "2c1c7e2e-2d0e-4059-831e-1e6f82335c2e"; - /// IID_IFileDialog - public const string FileDialog = "42f85136-db7e-439c-85f1-e4075d135fc8"; - /// IID_IFileDialogEvents - public const string FileDialogEvents = "973510DB-7D7F-452B-8975-74A85828D354"; - /// IID_IFileOpenDialog - public const string FileOpenDialog = "d57c7288-d4ad-4768-be02-9d969532d960"; - /// IID_IFileSaveDialog - public const string FileSaveDialog = "84bccd23-5fde-4cdb-aea4-af64b83d78ab"; - /// IID_IHTMLDocument - public const string HtmlDocument = "626FC520-A41E-11CF-A731-00A0C9082637"; - /// IID_IHTMLDocument2 - public const string HtmlDocument2 = "332C4425-26CB-11D0-B483-00C04FD90119"; - /// IID_IModalWindow - public const string ModalWindow = "b4db1657-70d7-485e-8e3e-6fcb5a5c1802"; - /// IID_IObjectArray - public const string ObjectArray = "92CA9DCD-5622-4bba-A805-5E9F541BD8C9"; - /// IID_IObjectCollection - public const string ObjectCollection = "5632b1a4-e38a-400a-928a-d4cd63230295"; - /// IID_IPropertyNotifySink - public const string PropertyNotifySink = "9BFBBC02-EFF1-101A-84ED-00AA00341D07"; - /// IID_IPropertyStore - public const string PropertyStore = "886d8eeb-8cf2-4446-8d02-cdba1dbdcf99"; - /// IID_IServiceProvider - public const string ServiceProvider = "6d5140c1-7436-11ce-8034-00aa006009fa"; - /// IID_IShellFolder - public const string ShellFolder = "000214E6-0000-0000-C000-000000000046"; - /// IID_IShellLink - public const string ShellLink = "000214F9-0000-0000-C000-000000000046"; - /// IID_IShellItem - public const string ShellItem = "43826d1e-e718-42ee-bc55-a1e261c37bfe"; - /// IID_IShellItem2 - public const string ShellItem2 = "7e9fb0d3-919f-4307-ab2e-9b1860310c93"; - /// IID_IShellItemArray - public const string ShellItemArray = "B63EA76D-1F85-456F-A19C-48159EFA858B"; - /// IID_ITaskbarList - public const string TaskbarList = "56FDF342-FD6D-11d0-958A-006097C9A090"; - /// IID_ITaskbarList2 - public const string TaskbarList2 = "602D4995-B13A-429b-A66E-1935E44F4317"; - /// IID_IUnknown - public const string Unknown = "00000000-0000-0000-C000-000000000046"; - /// IID_IWebBrowser2 - public const string WebBrowser2 = "D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"; - /// DIID_DWebBrowserEvents - public const string WebBrowserEvents = "EAB22AC2-30C1-11CF-A7EB-0000C05BAE0B"; - /// IID_DWebBrowserEvents2 - public const string WebBrowserEvents2 = "34A715A0-6587-11D0-924A-0020AFC7AC4D"; - /// IID_IWICBitmapDecoder - public const string WICBitmapDecoder = "9EDDE9E7-8DEE-47ea-99DF-E6FAF2ED44BF"; - /// IID_IWICBitmapFlipRotator - public const string WICBitmapFlipRotator = "5009834F-2D6A-41ce-9E1B-17C5AFF7A782"; - /// IID_IWICBitmapFrameDecode - public const string WICBitmapFrameDecode = "3B16811B-6A43-4ec9-A813-3D930C13B940"; - /// IID_IWICBitmap - public const string WICBitmap = "00000121-a8f2-4877-ba0a-fd2b6645fb94"; - /// IID_IWICBitmapSource - public const string WICBitmapSource = "00000120-a8f2-4877-ba0a-fd2b6645fb94"; - /// IID_IWICFormatConverter - public const string WICFormatConverter = "00000301-a8f2-4877-ba0a-fd2b6645fb94"; - /// IID_IWICImagingFactory - public const string WICImagingFactory = "ec5ec8a9-c395-4314-9c77-54d7a935ff70"; - /// IID_IWICStream - public const string WICStream = "135FF860-22B7-4ddf-B0F6-218F4F299A43"; - - #region Win7 IIDs - - /// IID_IApplicationDestinations - public const string ApplicationDestinations = "12337d35-94c6-48a0-bce7-6a9c69d4d600"; - /// IID_IApplicationDocumentLists - public const string ApplicationDocumentLists = "3c594f9f-9f30-47a1-979a-c9e83d3d0a06"; - /// IID_ICustomDestinationList - public const string CustomDestinationList = "6332debf-87b5-4670-90c0-5e57b408a49e"; - /// IID_IObjectWithAppUserModelID - public const string ObjectWithAppUserModelId = "36db0196-9665-46d1-9ba7-d3709eecf9ed"; - /// IID_IObjectWithProgID - public const string ObjectWithProgId = "71e806fb-8dee-46fc-bf8c-7748a8a1ae13"; - /// IID_ITaskbarList3 - public const string TaskbarList3 = "ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf"; - /// IID_ITaskbarList4 - public const string TaskbarList4 = "c43dc798-95d1-4bea-9030-bb99e2983a1a"; - - #endregion - } - - internal static partial class SID - { - /// SID_SWebBrowserApp - public const string SWebBrowserApp = "0002DF05-0000-0000-C000-000000000046"; - } - - internal static partial class CLSID - { - public static T CoCreateInstance(string clsid) - { - return (T)System.Activator.CreateInstance(System.Type.GetTypeFromCLSID(new System.Guid(clsid))); - } - - /// CLSID_ApplicationAssociationRegistration - /// IID_IApplicationAssociationRegistration - public const string ApplicationAssociationRegistration = "591209c7-767b-42b2-9fba-44ee4615f2c7"; - /// CLSID_DragDropHelper - public const string DragDropHelper = "4657278A-411B-11d2-839A-00C04FD918D0"; - /// CLSID_FileOpenDialog - /// IID_IFileOpenDialog - public const string FileOpenDialog = "DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7"; - /// CLSID_FileSaveDialog - /// IID_IFileSaveDialog - public const string FileSaveDialog = "C0B4E2F3-BA21-4773-8DBA-335EC946EB8B"; - /// CLSID_TaskbarList - /// IID_ITaskbarList - public const string TaskbarList = "56FDF344-FD6D-11d0-958A-006097C9A090"; - /// CLSID_EnumerableObjectCollection - /// IID_IEnumObjects. - public const string EnumerableObjectCollection = "2d3468c1-36a7-43b6-ac24-d3f02fd9607a"; - /// CLSID_ShellLink - /// IID_IShellLink - public const string ShellLink = "00021401-0000-0000-C000-000000000046"; - - /// CLSID_WICImagingFactory - public const string WICImagingFactory = "cacaf262-9370-4615-a13b-9f5539da4c0a"; - - #region Win7 CLSIDs - - /// CLSID_DestinationList - /// IID_ICustomDestinationList - public const string DestinationList = "77f10cf0-3db5-4966-b520-b7c54fd35ed6"; - /// CLSID_ApplicationDestinations - /// IID_IApplicationDestinations - public const string ApplicationDestinations = "86c14003-4d6b-4ef3-a7b4-0506663b2e68"; - /// CLSID_ApplicationDocumentLists - /// IID_IApplicationDocumentLists - public const string ApplicationDocumentLists = "86bec222-30f2-47e0-9f25-60d11cd75c28"; - - #endregion - } -} diff --git a/Microsoft.Windows.Shell/Standard/Debug.cs b/Microsoft.Windows.Shell/Standard/Debug.cs deleted file mode 100644 index 88ac5b1..0000000 --- a/Microsoft.Windows.Shell/Standard/Debug.cs +++ /dev/null @@ -1,398 +0,0 @@ -// Conditional to use more aggressive fail-fast behaviors when debugging. -#define DEV_DEBUG - -// This file contains general utilities to aid in development. -// It is distinct from unit test Assert classes. -// Classes here generally shouldn't be exposed publicly since -// they're not particular to any library functionality. -// Because the classes here are internal, it's likely this file -// might be included in multiple assemblies. -namespace Standard -{ - using System; - using System.Diagnostics; - using System.Threading; - - /// A static class for verifying assumptions. - internal static class Assert - { - // Blend and VS don't like Debugger.Break being called on their design surfaces. Badness will happen. - //private static readonly bool _isNotAtRuntime = (bool)System.ComponentModel.DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(System.Windows.DependencyObject)).DefaultValue; - - private static void _Break() - { - //if (!_isNotAtRuntime) - { -#if DEV_DEBUG - Debugger.Break(); -#else - Debug.Assert(false); -#endif - } - } - - /// A function signature for Assert.Evaluate. - public delegate void EvaluateFunction(); - - /// A function signature for Assert.Implies. - /// Returns the truth of a predicate. - public delegate bool ImplicationFunction(); - - /// - /// Executes the specified argument. - /// - /// The function to execute. - [Conditional("DEBUG")] - public static void Evaluate(EvaluateFunction argument) - { - IsNotNull(argument); - argument(); - } - - /// Obsolete: Use Standard.Assert.AreEqual instead of Assert.Equals - /// The generic type to compare for equality. - /// The first generic type data to compare. This is is the expected value. - /// The second generic type data to compare. This is the actual value. - [ - Obsolete("Use Assert.AreEqual instead of Assert.Equals", false), - Conditional("DEBUG") - ] - public static void Equals(T expected, T actual) - { - AreEqual(expected, actual); - } - - /// - /// Verifies that two generic type data are equal. The assertion fails if they are not. - /// - /// The generic type to compare for equality. - /// The first generic type data to compare. This is is the expected value. - /// The second generic type data to compare. This is the actual value. - /// This breaks into the debugger in the case of a failed assertion. - [Conditional("DEBUG")] - public static void AreEqual(T expected, T actual) - { - if (null == expected) - { - // Two nulls are considered equal, regardless of type semantics. - if (null != actual && !actual.Equals(expected)) - { - _Break(); - } - } - else if (!expected.Equals(actual)) - { - _Break(); - } - } - - [Conditional("DEBUG")] - public static void LazyAreEqual(Func expectedResult, Func actualResult) - { - Assert.IsNotNull(expectedResult); - Assert.IsNotNull(actualResult); - - T actual = actualResult(); - T expected = expectedResult(); - - if (null == expected) - { - // Two nulls are considered equal, regardless of type semantics. - if (null != actual && !actual.Equals(expected)) - { - _Break(); - } - } - else if (!expected.Equals(actual)) - { - _Break(); - } - } - - /// - /// Verifies that two generic type data are not equal. The assertion fails if they are. - /// - /// The generic type to compare for inequality. - /// The first generic type data to compare. This is is the value that's not expected. - /// The second generic type data to compare. This is the actual value. - /// This breaks into the debugger in the case of a failed assertion. - [Conditional("DEBUG")] - public static void AreNotEqual(T notExpected, T actual) - { - if (null == notExpected) - { - // Two nulls are considered equal, regardless of type semantics. - if (null == actual || actual.Equals(notExpected)) - { - _Break(); - } - } - else if (notExpected.Equals(actual)) - { - _Break(); - } - } - - /// - /// Verifies that if the specified condition is true, then so is the result. - /// The assertion fails if the condition is true but the result is false. - /// - /// if set to true [condition]. - /// - /// A second Boolean statement. If the first was true then so must this be. - /// If the first statement was false then the value of this is ignored. - /// - /// This breaks into the debugger in the case of a failed assertion. - [Conditional("DEBUG")] - public static void Implies(bool condition, bool result) - { - if (condition && !result) - { - _Break(); - } - } - - /// - /// Lazy evaluation overload. Verifies that if a condition is true, then so is a secondary value. - /// - /// The conditional value. - /// A function to be evaluated for truth if the condition argument is true. - /// - /// This overload only evaluates the result if the first condition is true. - /// - [Conditional("DEBUG")] - public static void Implies(bool condition, ImplicationFunction result) - { - if (condition && !result()) - { - _Break(); - } - } - - /// - /// Verifies that a string has content. I.e. it is not null and it is not empty. - /// - /// The string to verify. - [Conditional("DEBUG")] - public static void IsNeitherNullNorEmpty(string value) - { - IsFalse(string.IsNullOrEmpty(value)); - } - - /// - /// Verifies that a string has content. I.e. it is not null and it is not purely whitespace. - /// - /// The string to verify. - [Conditional("DEBUG")] - public static void IsNeitherNullNorWhitespace(string value) - { - if (string.IsNullOrEmpty(value)) - { - _Break(); - } - - if (value.Trim().Length == 0) - { - _Break(); - } - } - - /// - /// Verifies the specified value is not null. The assertion fails if it is. - /// - /// The generic reference type. - /// The value to check for nullness. - /// This breaks into the debugger in the case of a failed assertion. - [Conditional("DEBUG")] - public static void IsNotNull(T value) where T : class - { - if (null == value) - { - _Break(); - } - } - - [Conditional("DEBUG")] - public static void IsDefault(T value) where T : struct - { - if (!value.Equals(default(T))) - { - Assert.Fail(); - } - } - - [Conditional("DEBUG")] - public static void IsNotDefault(T value) where T : struct - { - if (value.Equals(default(T))) - { - Assert.Fail(); - } - } - - /// - /// Verifies that the specified condition is false. The assertion fails if it is true. - /// - /// The expression that should be false. - /// This breaks into the debugger in the case of a failed assertion. - [Conditional("DEBUG")] - public static void IsFalse(bool condition) - { - if (condition) - { - _Break(); - } - } - - /// - /// Verifies that the specified condition is false. The assertion fails if it is true. - /// - /// The expression that should be false. - /// The message to display if the condition is true. - /// This breaks into the debugger in the case of a failed assertion. - [Conditional("DEBUG")] - public static void IsFalse(bool condition, string message) - { - if (condition) - { - _Break(); - } - } - - /// - /// Verifies that the specified condition is true. The assertion fails if it is not. - /// - /// A condition that is expected to be true. - /// This breaks into the debugger in the case of a failed assertion. - [Conditional("DEBUG")] - public static void IsTrue(bool condition) - { - if (!condition) - { - _Break(); - } - } - - [Conditional("DEBUG")] - public static void IsTrue(Predicate predicate, T arg) - { - if (!predicate(arg)) - { - _Break(); - } - } - - /// - /// Verifies that the specified condition is true. The assertion fails if it is not. - /// - /// A condition that is expected to be true. - /// The message to write in case the condition is false. - /// This breaks into the debugger in the case of a failed assertion. - [Conditional("DEBUG")] - public static void IsTrue(bool condition, string message) - { - if (!condition) - { - _Break(); - } - } - - /// - /// This line should never be executed. The assertion always fails. - /// - /// This breaks into the debugger in the case of a failed assertion. - [Conditional("DEBUG")] - public static void Fail() - { - _Break(); - } - - /// - /// This line should never be executed. The assertion always fails. - /// - /// The message to display if this function is executed. - /// This breaks into the debugger in the case of a failed assertion. - [Conditional("DEBUG")] - public static void Fail(string message) - { - _Break(); - } - - /// - /// Verifies that the specified object is null. The assertion fails if it is not. - /// - /// The item to verify is null. - [Conditional("DEBUG")] - public static void IsNull(T item) where T : class - { - if (null != item) - { - _Break(); - } - } - - /// - /// Verifies that the specified value is within the expected range. The assertion fails if it isn't. - /// - /// The lower bound inclusive value. - /// The value to verify. - /// The upper bound inclusive value. - [Conditional("DEBUG")] - public static void BoundedDoubleInc(double lowerBoundInclusive, double value, double upperBoundInclusive) - { - if (value < lowerBoundInclusive || value > upperBoundInclusive) - { - _Break(); - } - } - - /// - /// Verifies that the specified value is within the expected range. The assertion fails if it isn't. - /// - /// The lower bound inclusive value. - /// The value to verify. - /// The upper bound exclusive value. - [Conditional("DEBUG")] - public static void BoundedInteger(int lowerBoundInclusive, int value, int upperBoundExclusive) - { - if (value < lowerBoundInclusive || value >= upperBoundExclusive) - { - _Break(); - } - } - - /// - /// Verify the current thread's apartment state is what's expected. The assertion fails if it isn't - /// - /// - /// The expected apartment state for the current thread. - /// - /// This breaks into the debugger in the case of a failed assertion. - [Conditional("DEBUG")] - public static void IsApartmentState(ApartmentState expectedState) - { - if (Thread.CurrentThread.GetApartmentState() != expectedState) - { - _Break(); - } - } - - [Conditional("DEBUG")] - public static void NullableIsNotNull(T? value) where T : struct - { - if (null == value) - { - _Break(); - } - } - - [Conditional("DEBUG")] - public static void NullableIsNull(T? value) where T : struct - { - if (null != value) - { - _Break(); - } - } - } -} diff --git a/Microsoft.Windows.Shell/Standard/DoubleUtil.cs b/Microsoft.Windows.Shell/Standard/DoubleUtil.cs deleted file mode 100644 index 47ec6ef..0000000 --- a/Microsoft.Windows.Shell/Standard/DoubleUtil.cs +++ /dev/null @@ -1,140 +0,0 @@ - -namespace Standard -{ - using System; - - /// - /// DoubleUtil uses fixed eps to provide fuzzy comparison functionality for doubles. - /// Note that FP noise is a big problem and using any of these compare - /// methods is not a complete solution, but rather the way to reduce - /// the probability of repeating unnecessary work. - /// - internal static class DoubleUtilities - { - /// - /// Epsilon - more or less random, more or less small number. - /// - private const double Epsilon = 0.00000153; - - /// - /// AreClose returns whether or not two doubles are "close". That is, whether or - /// not they are within epsilon of each other. - /// There are plenty of ways for this to return false even for numbers which - /// are theoretically identical, so no code calling this should fail to work if this - /// returns false. - /// - /// The first double to compare. - /// The second double to compare. - /// The result of the AreClose comparision. - public static bool AreClose(double value1, double value2) - { - if (value1 == value2) - { - return true; - } - - double delta = value1 - value2; - return (delta < Epsilon) && (delta > -Epsilon); - } - - public static bool IsCloseTo(this double value1, double value2) - { - return AreClose(value1, value2); - } - - /// - /// LessThan returns whether or not the first double is less than the second double. - /// That is, whether or not the first is strictly less than *and* not within epsilon of - /// the other number. - /// There are plenty of ways for this to return false even for numbers which - /// are theoretically identical, so no code calling this should fail to work if this - /// returns false. - /// - /// The first double to compare. - /// The second double to compare. - /// The result of the LessThan comparision. - public static bool IsStrictlyLessThan(this double value1, double value2) - { - return (value1 < value2) && !AreClose(value1, value2); - } - - /// - /// GreaterThan returns whether or not the first double is greater than the second double. - /// That is, whether or not the first is strictly greater than *and* not within epsilon of - /// the other number. - /// There are plenty of ways for this to return false even for numbers which - /// are theoretically identical, so no code calling this should fail to work if this - /// returns false. - /// - /// The first double to compare. - /// The second double to compare. - /// The result of the GreaterThan comparision. - public static bool IsStrictlyGreaterThan(this double value1, double value2) - { - return (value1 > value2) && !AreClose(value1, value2); - } - - /// - /// LessThanOrClose returns whether or not the first double is less than or close to - /// the second double. That is, whether or not the first is strictly less than or within - /// epsilon of the other number. - /// There are plenty of ways for this to return false even for numbers which - /// are theoretically identical, so no code calling this should fail to work if this - /// returns false. - /// - /// The first double to compare. - /// The second double to compare. - /// The result of the LessThanOrClose comparision. - public static bool IsLessThanOrCloseTo(this double value1, double value2) - { - return (value1 < value2) || AreClose(value1, value2); - } - - /// - /// GreaterThanOrClose returns whether or not the first double is greater than or close to - /// the second double. That is, whether or not the first is strictly greater than or within - /// epsilon of the other number. - /// There are plenty of ways for this to return false even for numbers which - /// are theoretically identical, so no code calling this should fail to work if this - /// returns false. - /// - /// The first double to compare. - /// The second double to compare. - /// The result of the GreaterThanOrClose comparision. - public static bool IsGreaterThanOrCloseTo(this double value1, double value2) - { - return (value1 > value2) || AreClose(value1, value2); - } - - /// - /// Test to see if a double is a finite number (is not NaN or Infinity). - /// - /// The value to test. - /// Whether or not the value is a finite number. - public static bool IsFinite(this double value) - { - return !double.IsNaN(value) && !double.IsInfinity(value); - } - - /// - /// Test to see if a double a valid size value (is finite and > 0). - /// - /// The value to test. - /// Whether or not the value is a valid size value. - public static bool IsValidSize(this double value) - { - return IsFinite(value) && value.IsGreaterThanOrCloseTo(0); - } - - public static bool IsFiniteAndNonNegative(this double d) - { - if (double.IsNaN(d) || double.IsInfinity(d) || d < 0) - { - return false; - } - - return true; - } - - } -} diff --git a/Microsoft.Windows.Shell/Standard/Enumerable2.cs b/Microsoft.Windows.Shell/Standard/Enumerable2.cs deleted file mode 100644 index c046baf..0000000 --- a/Microsoft.Windows.Shell/Standard/Enumerable2.cs +++ /dev/null @@ -1,288 +0,0 @@ - -namespace Standard -{ - using System; - using System.Collections.Generic; - using System.Linq; - using System.Text; - - /// - /// Further LINQ extensions - /// - internal static class Enumerable2 - { - // Unnecessary in .Net 4. - //public static IEnumerable Zip(this IEnumerable first, IEnumerable second, Func func) - //{ - // Verify.IsNotNull(first, "first"); - // Verify.IsNotNull(second, "second"); - - // return _Zip(first, second, func); - //} - - //private static IEnumerable _Zip(this IEnumerable first, IEnumerable second, Func func) - //{ - // IEnumerator ie1 = first.GetEnumerator(); - // IEnumerator ie2 = second.GetEnumerator(); - // while (ie1.MoveNext() && ie2.MoveNext()) - // { - // yield return func(ie1.Current, ie2.Current); - // } - //} - - /// Partition a collection into two, based on whether the items match a predicate. - /// The type of the enumeration. - /// The original collection to split. - /// The condition to use for the split. - /// A collection of all items in the original collection that do not satisfy the condition. - /// A collection of all items in the original collection that satisfy the condition. - /// Unlike most extension methods of this nature, this does not perform the operation lazily. - public static IEnumerable SplitWhere(this IEnumerable collection, Predicate condition, out IEnumerable rest) - { - Verify.IsNotNull(collection, "collection"); - Verify.IsNotNull(condition, "condition"); - - var passList = new List(); - var failList = new List(); - - foreach (T t in collection) - { - if (condition(t)) - { - passList.Add(t); - } - else - { - failList.Add(t); - } - } - - rest = failList; - return passList; - } - - /// - /// Limit an enumeration to be constrained to a subset after a given index. - /// - /// The type of items being enumerated. - /// The collection to be enumerated. - /// The index (inclusive) of the first item to be returned. - /// - public static IEnumerable Sublist(this IEnumerable enumerable, int startIndex) - { - return Sublist(enumerable, startIndex, null); - } - - /// - /// Limit an enumeration to be within a set of indices. - /// - /// The type of items being enumerated. - /// The collection to be enumerated. - /// The index (inclusive) of the first item to be returned. - /// - /// The index (exclusive) of the last item to be returned. - /// If this is null then the full collection after startIndex is returned. - /// If this is greater than the count of the collection after startIndex, then the full collection after startIndex is returned. - /// - /// - public static IEnumerable Sublist(this IEnumerable enumerable, int startIndex, int? endIndex) - { - Verify.IsNotNull(enumerable, "enumerable"); - Verify.BoundedInteger(0, startIndex, int.MaxValue, "startIndex"); - if (endIndex != null) - { - Verify.BoundedInteger(startIndex, endIndex.Value, int.MaxValue, "endIndex"); - } - - // If this supports indexing then just use that. - var list = enumerable as IList; - if (list != null) - { - return _SublistList(list, startIndex, endIndex); - } - - return _SublistEnum(enumerable, startIndex, endIndex); - } - - private static IEnumerable _SublistEnum(this IEnumerable enumerable, int startIndex, int? endIndex) - { - int currentIndex = 0; - IEnumerator enumerator = enumerable.GetEnumerator(); - while (currentIndex < startIndex && enumerator.MoveNext()) - { - ++currentIndex; - } - - int trueEndIndex = endIndex ?? int.MaxValue; - - while (currentIndex < trueEndIndex && enumerator.MoveNext()) - { - yield return enumerator.Current; - ++currentIndex; - } - } - - private static IEnumerable _SublistList(this IList list, int startIndex, int? endIndex) - { - int trueEndIndex = Math.Min(list.Count, endIndex ?? int.MaxValue); - for (int i = startIndex; i < trueEndIndex; ++i) - { - yield return list[i]; - } - } - - public static bool AreSorted(this IEnumerable enumerable) - { - return _AreSorted(enumerable); - } - - public static bool AreSorted(this IEnumerable enumerable, Comparison comparison) - { - Verify.IsNotNull(enumerable, "enumerable"); - if (comparison == null) - { - if (typeof(T).GetInterface(typeof(IComparable).Name) == null) - { - // Not comparable for a sort. - return true; - } - - return _AreSorted(enumerable); - } - - return _AreSorted(enumerable, comparison); - } - - private static bool _AreSorted(IEnumerable enumerable, Comparison comparison) - { - T last = default(T); - bool isFirst = true; - foreach (var item in enumerable) - { - if (isFirst) - { - last = item; - isFirst = false; - } - else - { - if (comparison(last, item) > 0) - { - return false; - } - last = item; - } - } - - return true; - } - - private static bool _AreSorted(IEnumerable enumerable) - { - IComparable last = null; - bool isFirstNonNull = true; - foreach (var item in enumerable) - { - if (isFirstNonNull) - { - last = (IComparable)item; - if (last != null) - { - isFirstNonNull = false; - } - } - else - { - if (last.CompareTo(item) > 0) - { - return false; - } - last = (IComparable)item; - if (last == null) - { - return false; - } - } - } - - return true; - } - - public static void AddRange(this ICollection collection, params T[] items) - { - Verify.IsNotNull(collection, "collection"); - _AddRange(collection, items); - } - - public static void AddRange(this ICollection collection, IEnumerable items) - { - Verify.IsNotNull(collection, "collection"); - _AddRange(collection, items); - } - - private static void _AddRange(ICollection collection, IEnumerable items) - { - if (items == null) - { - return; - } - - foreach (var item in items) - { - collection.Add(item); - } - } - - public static IEnumerable Reverse(this IList list) - { - Verify.IsNotNull(list, "list"); - return _Reverse(list); - } - - private static IEnumerable _Reverse(IList list) - { - for (int i = list.Count - 1; i >= 0; --i) - { - yield return list[i]; - } - } - - public static IList Shuffle(this IList list) - { - var r = new Random(); - return Shuffle(list, () => r.Next(list.Count)); - } - - public static IList Shuffle(this IList list, Func numberGenerator) - { - Verify.IsNotNull(list, "list"); - Verify.IsNotNull(numberGenerator, "numberGenerator"); - - var swapIndices = new int[list.Count]; - for (int i = 0; i < list.Count; ++i) - { - int j = numberGenerator(); - if (j < 0 || j >= list.Count) - { - throw new ArgumentException("The number generator function generated a number outside the valid range."); - } - swapIndices[i] = j; - } - return _Shuffle(list, swapIndices); - } - - private static IList _Shuffle(IList list, int[] swapIndices) - { - Assert.AreEqual(list.Count, swapIndices.Length); - for (int i = swapIndices.Length; i > 1; --i) - { - int k = swapIndices[i-1]; - T temp = list[k]; - list[k] = list[i-1]; - list[i-1] = temp; - } - - return list; - } - } -} diff --git a/Microsoft.Windows.Shell/Standard/ErrorCodes.cs b/Microsoft.Windows.Shell/Standard/ErrorCodes.cs deleted file mode 100644 index 90ca9c2..0000000 --- a/Microsoft.Windows.Shell/Standard/ErrorCodes.cs +++ /dev/null @@ -1,631 +0,0 @@ -namespace Standard -{ - using System; - using System.ComponentModel; - using System.Diagnostics.CodeAnalysis; - using System.Globalization; - using System.Reflection; - using System.Runtime.InteropServices; - - /// - /// Wrapper for common Win32 status codes. - /// - [StructLayout(LayoutKind.Explicit)] - internal struct Win32Error - { - [FieldOffset(0)] - private readonly int _value; - - // NOTE: These public static field declarations are automatically - // picked up by (HRESULT's) ToString through reflection. - - /// The operation completed successfully. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_SUCCESS = new Win32Error(0); - /// Incorrect function. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_INVALID_FUNCTION = new Win32Error(1); - /// The system cannot find the file specified. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_FILE_NOT_FOUND = new Win32Error(2); - /// The system cannot find the path specified. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_PATH_NOT_FOUND = new Win32Error(3); - /// The system cannot open the file. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_TOO_MANY_OPEN_FILES = new Win32Error(4); - /// Access is denied. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_ACCESS_DENIED = new Win32Error(5); - /// The handle is invalid. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_INVALID_HANDLE = new Win32Error(6); - /// Not enough storage is available to complete this operation. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_OUTOFMEMORY = new Win32Error(14); - /// There are no more files. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_NO_MORE_FILES = new Win32Error(18); - /// The process cannot access the file because it is being used by another process. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_SHARING_VIOLATION = new Win32Error(32); - /// The parameter is incorrect. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_INVALID_PARAMETER = new Win32Error(87); - /// The data area passed to a system call is too small. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_INSUFFICIENT_BUFFER = new Win32Error(122); - /// Cannot nest calls to LoadModule. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_NESTING_NOT_ALLOWED = new Win32Error(215); - /// Illegal operation attempted on a registry key that has been marked for deletion. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_KEY_DELETED = new Win32Error(1018); - /// Element not found. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_NOT_FOUND = new Win32Error(1168); - /// There was no match for the specified key in the index. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_NO_MATCH = new Win32Error(1169); - /// An invalid device was specified. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_BAD_DEVICE = new Win32Error(1200); - /// The operation was canceled by the user. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_CANCELLED = new Win32Error(1223); - /// Cannot find window class. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_CANNOT_FIND_WND_CLASS = new Win32Error(1407); - /// The window class was already registered. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_CLASS_ALREADY_EXISTS = new Win32Error(1410); - /// The specified datatype is invalid. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly Win32Error ERROR_INVALID_DATATYPE = new Win32Error(1804); - - /// - /// Create a new Win32 error. - /// - /// The integer value of the error. - public Win32Error(int i) - { - _value = i; - } - - /// Performs HRESULT_FROM_WIN32 conversion. - /// The Win32 error being converted to an HRESULT. - /// The equivilent HRESULT value. - public static explicit operator HRESULT(Win32Error error) - { - // #define __HRESULT_FROM_WIN32(x) - // ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000))) - if (error._value <= 0) - { - return new HRESULT((uint)error._value); - } - return HRESULT.Make(true, Facility.Win32, error._value & 0x0000FFFF); - } - - // Method version of the cast operation - /// Performs HRESULT_FROM_WIN32 conversion. - /// The Win32 error being converted to an HRESULT. - /// The equivilent HRESULT value. - public HRESULT ToHRESULT() - { - return (HRESULT)this; - } - - /// Performs the equivalent of Win32's GetLastError() - /// A Win32Error instance with the result of the native GetLastError - public static Win32Error GetLastError() - { - return new Win32Error(Marshal.GetLastWin32Error()); - } - - public override bool Equals(object obj) - { - try - { - return ((Win32Error)obj)._value == _value; - } - catch (InvalidCastException) - { - return false; - } - } - - public override int GetHashCode() - { - return _value.GetHashCode(); - } - - /// - /// Compare two Win32 error codes for equality. - /// - /// The first error code to compare. - /// The second error code to compare. - /// Whether the two error codes are the same. - public static bool operator ==(Win32Error errLeft, Win32Error errRight) - { - return errLeft._value == errRight._value; - } - - /// - /// Compare two Win32 error codes for inequality. - /// - /// The first error code to compare. - /// The second error code to compare. - /// Whether the two error codes are not the same. - public static bool operator !=(Win32Error errLeft, Win32Error errRight) - { - return !(errLeft == errRight); - } - } - - internal enum Facility - { - /// FACILITY_NULL - Null = 0, - /// FACILITY_RPC - Rpc = 1, - /// FACILITY_DISPATCH - Dispatch = 2, - /// FACILITY_STORAGE - Storage = 3, - /// FACILITY_ITF - Itf = 4, - /// FACILITY_WIN32 - Win32 = 7, - /// FACILITY_WINDOWS - Windows = 8, - /// FACILITY_CONTROL - Control = 10, - /// MSDN doced facility code for ESE errors. - Ese = 0xE5E, - /// FACILITY_WINCODEC (WIC) - WinCodec = 0x898, - } - - /// Wrapper for HRESULT status codes. - [StructLayout(LayoutKind.Explicit)] - internal struct HRESULT - { - [FieldOffset(0)] - private readonly uint _value; - - // NOTE: These public static field declarations are automatically - // picked up by ToString through reflection. - /// S_OK - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT S_OK = new HRESULT(0x00000000); - /// S_FALSE - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT S_FALSE = new HRESULT(0x00000001); - /// E_PENDING - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT E_PENDING = new HRESULT(0x8000000A); - /// E_NOTIMPL - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT E_NOTIMPL = new HRESULT(0x80004001); - /// E_NOINTERFACE - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT E_NOINTERFACE = new HRESULT(0x80004002); - /// E_POINTER - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT E_POINTER = new HRESULT(0x80004003); - /// E_ABORT - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT E_ABORT = new HRESULT(0x80004004); - /// E_FAIL - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT E_FAIL = new HRESULT(0x80004005); - /// E_UNEXPECTED - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT E_UNEXPECTED = new HRESULT(0x8000FFFF); - /// STG_E_INVALIDFUNCTION - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT STG_E_INVALIDFUNCTION = new HRESULT(0x80030001); - - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT OLE_E_ADVISENOTSUPPORTED = new HRESULT(0x80040003); - - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT DV_E_FORMATETC = new HRESULT(0x80040064); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT DV_E_TYMED = new HRESULT(0x80040069); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT DV_E_CLIPFORMAT = new HRESULT(0x8004006A); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT DV_E_DVASPECT = new HRESULT(0x8004006B); - - /// REGDB_E_CLASSNOTREG - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT REGDB_E_CLASSNOTREG = new HRESULT(0x80040154); - - /// DESTS_E_NO_MATCHING_ASSOC_HANDLER. Win7 internal error code for Jump Lists. - /// There is no Assoc Handler for the given item registered by the specified application. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT DESTS_E_NO_MATCHING_ASSOC_HANDLER = new HRESULT(0x80040F03); - /// DESTS_E_NORECDOCS. Win7 internal error code for Jump Lists. - /// The given item is excluded from the recent docs folder by the NoRecDocs bit on its registration. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT DESTS_E_NORECDOCS = new HRESULT(0x80040F04); - /// DESTS_E_NOTALLCLEARED. Win7 internal error code for Jump Lists. - /// Not all of the items were successfully cleared - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT DESTS_E_NOTALLCLEARED = new HRESULT(0x80040F05); - - /// E_ACCESSDENIED - /// Win32Error ERROR_ACCESS_DENIED. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT E_ACCESSDENIED = new HRESULT(0x80070005); - /// E_OUTOFMEMORY - /// Win32Error ERROR_OUTOFMEMORY. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT E_OUTOFMEMORY = new HRESULT(0x8007000E); - /// E_INVALIDARG - /// Win32Error ERROR_INVALID_PARAMETER. - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT E_INVALIDARG = new HRESULT(0x80070057); - /// INTSAFE_E_ARITHMETIC_OVERFLOW - public static readonly HRESULT INTSAFE_E_ARITHMETIC_OVERFLOW = new HRESULT(0x80070216); - /// COR_E_OBJECTDISPOSED - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT COR_E_OBJECTDISPOSED = new HRESULT(0x80131622); - /// WC_E_GREATERTHAN - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WC_E_GREATERTHAN = new HRESULT(0xC00CEE23); - /// WC_E_SYNTAX - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WC_E_SYNTAX = new HRESULT(0xC00CEE2D); - - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_GENERIC_ERROR = E_FAIL; - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_INVALIDPARAMETER = E_INVALIDARG; - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_OUTOFMEMORY = E_OUTOFMEMORY; - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_NOTIMPLEMENTED = E_NOTIMPL; - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_ABORTED = E_ABORT; - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_ACCESSDENIED = E_ACCESSDENIED; - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_VALUEOVERFLOW = INTSAFE_E_ARITHMETIC_OVERFLOW; - - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_WRONGSTATE = Make(true, Facility.WinCodec, 0x2f04); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_VALUEOUTOFRANGE = Make(true, Facility.WinCodec, 0x2f05); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_UNKNOWNIMAGEFORMAT = Make(true, Facility.WinCodec, 0x2f07); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_UNSUPPORTEDVERSION = Make(true, Facility.WinCodec, 0x2f0B); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_NOTINITIALIZED = Make(true, Facility.WinCodec, 0x2f0C); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_ALREADYLOCKED = Make(true, Facility.WinCodec, 0x2f0D); - - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_PROPERTYNOTFOUND = Make(true, Facility.WinCodec, 0x2f40); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_PROPERTYNOTSUPPORTED = Make(true, Facility.WinCodec, 0x2f41); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_PROPERTYSIZE = Make(true, Facility.WinCodec, 0x2f42); - - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_CODECPRESENT = Make(true, Facility.WinCodec, 0x2f43); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_CODECNOTHUMBNAIL = Make(true, Facility.WinCodec, 0x2f44); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_PALETTEUNAVAILABLE = Make(true, Facility.WinCodec, 0x2f45); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_CODECTOOMANYSCANLINES = Make(true, Facility.WinCodec, 0x2f46); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_INTERNALERROR = Make(true, Facility.WinCodec, 0x2f48); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_SOURCERECTDOESNOTMATCHDIMENSIONS = Make(true, Facility.WinCodec, 0x2f49); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_COMPONENTNOTFOUND = Make(true, Facility.WinCodec, 0x2f50); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_IMAGESIZEOUTOFRANGE = Make(true, Facility.WinCodec, 0x2f51); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_TOOMUCHMETADATA = Make(true, Facility.WinCodec, 0x2f52); - - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_BADIMAGE = Make(true, Facility.WinCodec, 0x2f60); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_BADHEADER = Make(true, Facility.WinCodec, 0x2f61); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_FRAMEMISSING = Make(true, Facility.WinCodec, 0x2f62); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_BADMETADATAHEADER = Make(true, Facility.WinCodec, 0x2f63); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_BADSTREAMDATA = Make(true, Facility.WinCodec, 0x2f70); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_STREAMWRITE = Make(true, Facility.WinCodec, 0x2f71); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_STREAMREAD = Make(true, Facility.WinCodec, 0x2f72); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_STREAMNOTAVAILABLE = Make(true, Facility.WinCodec, 0x2f73); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT = Make(true, Facility.WinCodec, 0x2f80); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_UNSUPPORTEDOPERATION = Make(true, Facility.WinCodec, 0x2f81); - - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_INVALIDREGISTRATION = Make(true, Facility.WinCodec, 0x2f8A); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_COMPONENTINITIALIZEFAILURE = Make(true, Facility.WinCodec, 0x2f8B); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_INSUFFICIENTBUFFER = Make(true, Facility.WinCodec, 0x2f8C); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_DUPLICATEMETADATAPRESENT = Make(true, Facility.WinCodec, 0x2f8D); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE = Make(true, Facility.WinCodec, 0x2f8E); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_UNEXPECTEDSIZE = Make(true, Facility.WinCodec, 0x2f8F); - - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_INVALIDQUERYREQUEST = Make(true, Facility.WinCodec, 0x2f90); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_UNEXPECTEDMETADATATYPE = Make(true, Facility.WinCodec, 0x2f91); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_REQUESTONLYVALIDATMETADATAROOT = Make(true, Facility.WinCodec, 0x2f92); - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - public static readonly HRESULT WINCODEC_ERR_INVALIDQUERYCHARACTER = Make(true, Facility.WinCodec, 0x2f93); - - /// - /// Create an HRESULT from an integer value. - /// - /// - public HRESULT(uint i) - { - _value = i; - } - - public HRESULT(int i) - { - _value = unchecked((uint)i); - } - - /// - /// Convert an HRESULT to an int. Used for COM interface declarations out of our control. - /// - public static explicit operator int(HRESULT hr) - { - unchecked - { - return (int)hr._value; - } - } - - public static HRESULT Make(bool severe, Facility facility, int code) - { - //#define MAKE_HRESULT(sev,fac,code) \ - // ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) - - // Severity has 1 bit reserved. - // bitness is enforced by the boolean parameter. - - // Facility has 11 bits reserved (different than SCODES, which have 4 bits reserved) - // MSDN documentation incorrectly uses 12 bits for the ESE facility (e5e), so go ahead and let that one slide. - // And WIC also ignores it the documented size... - Assert.Implies((int)facility != (int)((int)facility & 0x1FF), facility == Facility.Ese || facility == Facility.WinCodec); - // Code has 4 bits reserved. - Assert.AreEqual(code, code & 0xFFFF); - - return new HRESULT((uint)((severe ? (1 << 31) : 0) | ((int)facility << 16) | code)); - } - - /// - /// retrieve HRESULT_FACILITY - /// - public Facility Facility - { - get - { - return GetFacility((int)_value); - } - } - - public static Facility GetFacility(int errorCode) - { - // #define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) - return (Facility)((errorCode >> 16) & 0x1fff); - } - - /// - /// retrieve HRESULT_CODE - /// - public int Code - { - get - { - return GetCode((int)_value); - } - } - - public static int GetCode(int error) - { - // #define HRESULT_CODE(hr) ((hr) & 0xFFFF) - return (int)(error & 0xFFFF); - } - - #region Object class override members - - /// - /// Get a string representation of this HRESULT. - /// - /// - public override string ToString() - { - // Use reflection to try to name this HRESULT. - // This is expensive, but if someone's ever printing HRESULT strings then - // I think it's a fair guess that they're not in a performance critical area - // (e.g. printing exception strings). - // This is less error prone than trying to keep the list in the function. - // To properly add an HRESULT's name to the ToString table, just add the HRESULT - // like all the others above. - // - // CONSIDER: This data is static. It could be cached - // after first usage for fast lookup since the keys are unique. - // - foreach (FieldInfo publicStaticField in typeof(HRESULT).GetFields(BindingFlags.Static | BindingFlags.Public)) - { - if (publicStaticField.FieldType == typeof(HRESULT)) - { - var hr = (HRESULT)publicStaticField.GetValue(null); - if (hr == this) - { - return publicStaticField.Name; - } - } - } - - // Try Win32 error codes also - if (Facility == Facility.Win32) - { - foreach (FieldInfo publicStaticField in typeof(Win32Error).GetFields(BindingFlags.Static | BindingFlags.Public)) - { - if (publicStaticField.FieldType == typeof(Win32Error)) - { - var error = (Win32Error)publicStaticField.GetValue(null); - if ((HRESULT)error == this) - { - return "HRESULT_FROM_WIN32(" + publicStaticField.Name + ")"; - } - } - } - } - - // If there's no good name for this HRESULT, - // return the string as readable hex (0x########) format. - return string.Format(CultureInfo.InvariantCulture, "0x{0:X8}", _value); - } - - public override bool Equals(object obj) - { - try - { - return ((HRESULT)obj)._value == _value; - } - catch (InvalidCastException) - { - return false; - } - } - - public override int GetHashCode() - { - return _value.GetHashCode(); - } - - #endregion - - public static bool operator ==(HRESULT hrLeft, HRESULT hrRight) - { - return hrLeft._value == hrRight._value; - } - - public static bool operator !=(HRESULT hrLeft, HRESULT hrRight) - { - return !(hrLeft == hrRight); - } - - public bool Succeeded - { - get { return (int)_value >= 0; } - } - - public bool Failed - { - get { return (int)_value < 0; } - } - - public void ThrowIfFailed() - { - ThrowIfFailed(null); - } - - [ - SuppressMessage( - "Microsoft.Usage", - "CA2201:DoNotRaiseReservedExceptionTypes", - Justification="Only recreating Exceptions that were already raised."), - SuppressMessage( - "Microsoft.Security", - "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands") - ] - public void ThrowIfFailed(string message) - { - if (Failed) - { - if (string.IsNullOrEmpty(message)) - { - message = ToString(); - } -#if DEBUG - else - { - message += " (" + ToString() + ")"; - } -#endif - // Wow. Reflection in a throw call. Later on this may turn out to have been a bad idea. - // If you're throwing an exception I assume it's OK for me to take some time to give it back. - // I want to convert the HRESULT to a more appropriate exception type than COMException. - // Marshal.ThrowExceptionForHR does this for me, but the general call uses GetErrorInfo - // if it's set, and then ignores the HRESULT that I've provided. This makes it so this - // call works the first time but you get burned on the second. To avoid this, I use - // the overload that explicitly ignores the IErrorInfo. - // In addition, the function doesn't allow me to set the Message unless I go through - // the process of implementing an IErrorInfo and then use that. There's no stock - // implementations of IErrorInfo available and I don't think it's worth the maintenance - // overhead of doing it, nor would it have significant value over this approach. - Exception e = Marshal.GetExceptionForHR((int)_value, new IntPtr(-1)); - Assert.IsNotNull(e); - // ArgumentNullException doesn't have the right constructor parameters, - // (nor does Win32Exception...) - // but E_POINTER gets mapped to NullReferenceException, - // so I don't think it will ever matter. - Assert.IsFalse(e is ArgumentNullException); - - // If we're not getting anything better than a COMException from Marshal, - // then at least check the facility and attempt to do better ourselves. - if (e.GetType() == typeof(COMException)) - { - switch (Facility) - { - case Facility.Win32: - e = new Win32Exception(Code, message); - break; - default: - e = new COMException(message, (int)_value); - break; - } - } - else - { - ConstructorInfo cons = e.GetType().GetConstructor(new[] { typeof(string) }); - if (null != cons) - { - e = cons.Invoke(new object[] { message }) as Exception; - Assert.IsNotNull(e); - } - } - throw e; - } - } - - /// - /// Convert the result of Win32 GetLastError() into a raised exception. - /// - public static void ThrowLastError() - { - ((HRESULT)Win32Error.GetLastError()).ThrowIfFailed(); - // Only expecting to call this when we're expecting a failed GetLastError() - Assert.Fail(); - } - } -} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/Standard/FileWalker.cs b/Microsoft.Windows.Shell/Standard/FileWalker.cs deleted file mode 100644 index a703fc8..0000000 --- a/Microsoft.Windows.Shell/Standard/FileWalker.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Cribbed heavily from MSDN magazine's .Net Matters (12/2005) by Stephen Toub. -// http://msdn.microsoft.com/msdnmag/issues/05/12/NETMatters/ -// This started off an excellent implementation, I'd rather not unnecessarily rewrite it. -// Some small stylistic changes were made to make it more consistent with the rest of the code -// and also changed the recurse criteria. - -namespace Standard -{ - using System.Collections.Generic; - using System.IO; - using System.Security.Permissions; - - internal class FileWalker - { - public static IEnumerable GetFiles(DirectoryInfo startDirectory, string pattern, bool recurse) - { - // We suppressed this demand for each p/invoke call, so demand it upfront once - new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); - - // Validate parameters - Verify.IsNotNull(startDirectory, "startDirectory"); - Verify.IsNeitherNullNorEmpty(pattern, "pattern"); - - // Setup - var findData = new WIN32_FIND_DATAW(); - var directories = new Stack(); - directories.Push(startDirectory); - - // Process each directory. Only push new directories if we're recursing. - ErrorModes origErrorMode = NativeMethods.SetErrorMode(ErrorModes.FailCriticalErrors); - try - { - while (directories.Count > 0) - { - // Get the name of the next directory and the corresponding search pattern - DirectoryInfo dir = directories.Pop(); - string dirPath = dir.FullName.Trim(); - if (dirPath.Length == 0) - { - continue; - } - char lastChar = dirPath[dirPath.Length - 1]; - if (lastChar != Path.DirectorySeparatorChar && lastChar != Path.AltDirectorySeparatorChar) - { - dirPath += Path.DirectorySeparatorChar; - } - - // Process all files in that directory - using (SafeFindHandle handle = NativeMethods.FindFirstFileW(dirPath + pattern, findData)) - { - Win32Error error; - if (handle.IsInvalid) - { - error = Win32Error.GetLastError(); - if (error == Win32Error.ERROR_ACCESS_DENIED || error == Win32Error.ERROR_FILE_NOT_FOUND) - { - continue; - } - Assert.AreNotEqual(Win32Error.ERROR_SUCCESS, error); - ((HRESULT)error).ThrowIfFailed(); - } - - do - { - if (!Utility.IsFlagSet((int)findData.dwFileAttributes, (int)FileAttributes.Directory)) - { - yield return new FileInfo(dirPath + findData.cFileName); - } - } - while (NativeMethods.FindNextFileW(handle, findData)); - error = Win32Error.GetLastError(); - if (error != Win32Error.ERROR_NO_MORE_FILES) - { - ((HRESULT)error).ThrowIfFailed(); - } - } - - // Push subdirectories onto the stack if we are recursing. - if (recurse) - { - // In a volatile system we can't count on all the file information staying valid. - // Catch reasonable exceptions and move on. - try - { - foreach (DirectoryInfo childDir in dir.GetDirectories()) - { - try - { - FileAttributes attrib = File.GetAttributes(childDir.FullName); - // If it's not a hidden, system folder, nor a reparse point - if (!Utility.IsFlagSet((int)attrib, (int)(FileAttributes.Hidden | FileAttributes.System | FileAttributes.ReparsePoint))) - { - directories.Push(childDir); - } - } - catch (FileNotFoundException) - { - // Shouldn't see this. - Assert.Fail(); - } - catch (DirectoryNotFoundException) { } - } - } - catch (DirectoryNotFoundException) { } - } - } - } - finally - { - NativeMethods.SetErrorMode(origErrorMode); - } - } - } -} diff --git a/Microsoft.Windows.Shell/Standard/MergeableCollection.cs b/Microsoft.Windows.Shell/Standard/MergeableCollection.cs deleted file mode 100644 index 3139779..0000000 --- a/Microsoft.Windows.Shell/Standard/MergeableCollection.cs +++ /dev/null @@ -1,628 +0,0 @@ -namespace Standard -{ - using System; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Collections.Specialized; - using System.ComponentModel; - using System.Linq; - - internal interface IMergeable : IEquatable where TKey : IEquatable - { - /// Immutable foreign key for the object - TKey FKID { get; } - - /// Merge the properties of another object of like type with this one. - /// The object to merge - void Merge(TItem other); - } - - internal class MergeableCollection : IList, INotifyCollectionChanged where TItem : class where TKey : IEquatable - { - private class _Comparer : IComparer - { - private bool _dontCompare = false; - private Comparison _defaultComparison; - private Comparison _customComparison; - private Comparison _trueComparison; - - public _Comparer() - { - if (Utility.IsInterfaceImplemented(typeof(TItem), typeof(IComparable))) - { - _defaultComparison = (left, right) => - { - if (object.ReferenceEquals(left, right)) - { - return 0; - } - - var comparableLeft = (IComparable)left; - if (comparableLeft == null) - { - return -1; - } - - return comparableLeft.CompareTo(right); - }; - } - - _trueComparison = _defaultComparison; - } - - public Comparison Comparison - { - get { return _trueComparison; } - set - { - Assert.IsFalse(_dontCompare); - if (!_dontCompare) - { - _customComparison = value; - _trueComparison = _customComparison ?? _defaultComparison; - } - } - } - - public bool CanCompare - { - get { return _trueComparison != null; } - } - - public void StopComparisons() - { - _trueComparison = null; - _dontCompare = true; - } - - public int Compare(TItem x, TItem y) - { - Assert.IsTrue(CanCompare); - return _trueComparison(x, y); - } - - public IEnumerable OrderedList(IEnumerable original) - { - Assert.IsNotNull(original); - - if (!CanCompare) - { - return original; - } - - return original.OrderBy(x => x, this); - } - } - - private readonly bool _areItemsMergable; - private readonly bool _areItemsNotifiable; - private readonly ObservableCollection _items; - private readonly Dictionary _fkidLookup; - private _Comparer _itemComparer = new _Comparer(); - - // Block reentrancy that would cause the collection to be reordered. - // If while we're doing a merge we get change notifications that the item has changed, ignore it. - private IMergeable _suspendNotificationsForMergeableObject; - - public object SyncRoot { get; private set; } - - public MergeableCollection() - : this(null, true) - {} - - public MergeableCollection(bool sort) - : this(null, sort) - {} - - public MergeableCollection(IEnumerable dataObjects) - : this(dataObjects, true) - {} - - public MergeableCollection(IEnumerable dataObjects, bool sort) - { - SyncRoot = new object(); - - if (!sort) - { - _itemComparer.StopComparisons(); - } - - // We don't really want to constrain based on the type being IMergeable or comparable - // This is a very specific check. We want to ensure that this type supports IMergeable, not IMergeable - _areItemsMergable = Utility.IsInterfaceImplemented(typeof(TItem), typeof(IMergeable)); - _areItemsNotifiable = Utility.IsInterfaceImplemented(typeof(TItem), typeof(INotifyPropertyChanged)); - - if (dataObjects == null) - { - _items = new ObservableCollection(); - } - else - { - _items = new ObservableCollection(_itemComparer.OrderedList(dataObjects)); - if (_areItemsNotifiable) - { - lock (SyncRoot) - { - foreach (INotifyPropertyChanged item in _items) - { - item.PropertyChanged += _OnItemChanged; - } - } - } - } - - if (_areItemsMergable) - { - _fkidLookup = new Dictionary(); - foreach (IMergeable item in _items) - { - //Assert.IsNotNull(item.FKID); - _fkidLookup.Add(item.FKID, (TItem)item); - } - } - } - - public Comparison CustomComparison - { - get { return _itemComparer.Comparison; } - set - { - if (_itemComparer.Comparison != value) - { - _itemComparer.Comparison = value; - RefreshSort(); - } - } - } - - public void RefreshSort() - { - if (_itemComparer.CanCompare) - { - lock (SyncRoot) - { - if (!_AreItemsSortedUpToIndex(_items.Count)) - { - var copyList = new List(_items); - // Clear the list first so we don't bubble-sort just to reorder. - _Merge(null, false, null); - _Merge(copyList, false, null); - } - } - } - } - - /// - /// Merges data from another collection. - /// - /// The data object collection that contains new data. - /// - /// If true, combine the new collection with existing content, otherwise replace the list. - /// - public void Merge(IEnumerable newCollection, bool add) - { - _Merge(newCollection, add, null); - } - - public void Merge(IEnumerable newCollection, bool add, int? maxCount) - { - _Merge(newCollection, add, maxCount); - } - - private void _Merge(IEnumerable newCollection, bool add, int? maxCount) - { - // These should never get out of sync. - Assert.Implies(_areItemsMergable, () => _items.Count == _fkidLookup.Count); - - lock (SyncRoot) - { - // Go-go partial template specialization! - if (_areItemsMergable) - { - _RichMerge(newCollection, add, maxCount); - } - else - { - _SimpleMerge(newCollection, add, maxCount); - } - } - } - - public TItem FindFKID(TKey id) - { - lock (SyncRoot) - { - if (!_areItemsMergable) - { - throw new InvalidOperationException("This can only be used on collections with Mergeable items."); - } - - TItem ret; - if (_fkidLookup.TryGetValue(id, out ret)) - { - return ret; - } - return null; - } - } - - private int _FindIndex(int startIndex, Predicate> match) - { - int count = Count - startIndex; - for (int i = startIndex; i < startIndex + count; ++i) - { - if (match((IMergeable)this[i])) - { - return i; - } - } - - return -1; - } - - private bool _VerifyInsertionPoint(int index) - { - lock (SyncRoot) - { - if (_itemComparer.Comparison == null) - { - // We don't have any way of determining a correct order. Whatever we have is fine. - return true; - } - - // Make sure that the item at index is not less than the one before it - // and not greater than the one after it. - // If this fails, we need to update the list. - - if (index != 0) - { - if (_itemComparer.Compare(_items[index - 1], _items[index]) > 0) - { - return false; - } - } - - if (index < _items.Count - 1) - { - if (_itemComparer.Compare(_items[index], _items[index+1]) > 0) - { - return false; - } - } - - return true; - } - } - - private int _FindInsertionPoint(TItem item) - { - Assert.IsNotNull(item); - - if (_itemComparer.Comparison != null) - { - for (int i = 0; i < _items.Count; ++i) - { - if (_itemComparer.Compare(item, _items[i]) <= 0) - { - return i; - } - } - } - - return -1; - } - - /// - /// Safe version of Clear that removes references to this from the items being removed. - /// - private void _MergeClear() - { - if (_areItemsNotifiable) - { - foreach (var item in _items) - { - _SafeRemoveNotifyAndLookup(item); - } - } - _items.Clear(); - - if (_fkidLookup != null) - { - _fkidLookup.Clear(); - } - } - - private void _RichMerge(IEnumerable newCollection, bool additive, int? maxCount) - { - lock (SyncRoot) - { - if (newCollection == null) - { - _MergeClear(); - return; - } - - if (!additive) - { - int index = -1; - foreach (TItem newItem in _itemComparer.OrderedList(newCollection).Sublist(0, maxCount)) - { - var mergeableItem = newItem as IMergeable; - - ++index; - //Assert.IsNotNull(mergeableItem.FKID); - int oldIndex = _FindIndex(index, p => mergeableItem.FKID.Equals(p.FKID)); - if (oldIndex == -1) - { - _items.Insert(index, newItem); - _SafeAddNotifyAndLookup(newItem); - continue; - } - else if (oldIndex != index) - { - _items.Move(oldIndex, index); - } - - _suspendNotificationsForMergeableObject = (IMergeable)this[index]; - _suspendNotificationsForMergeableObject.Merge(newItem); - _suspendNotificationsForMergeableObject = null; - - Assert.IsTrue(unused => _AreItemsSortedUpToIndex(index), null); - } - - if (index != -1) - { - ++index; - _RemoveRange(index); - } - else - { - _MergeClear(); - } - } - else - { - foreach (var item in newCollection) - { - var mergableItem = (IMergeable)item; - - int index = _FindIndex(0, p => p.FKID.Equals(mergableItem.FKID)); - if (index == -1) - { - index = _FindInsertionPoint(item); - - if (-1 == index) - { - _items.Add(item); - } - else - { - _items.Insert(index, item); - } - _SafeAddNotifyAndLookup(item); - } - else - { - _suspendNotificationsForMergeableObject = (IMergeable)this[index]; - _suspendNotificationsForMergeableObject.Merge(item); - _suspendNotificationsForMergeableObject = null; - } - } - } - - if (maxCount != null && _items.Count > maxCount.Value) - { - _RemoveRange(maxCount.Value); - } - - //Assert.Implies(_areItemsComparable || _customComparison != null, () => _items.AreSorted(_customComparison)); - } - } - - private bool _AreItemsSortedUpToIndex(int index) - { - if (_itemComparer.CanCompare) - { - for (int i = 1; i < index; ++i) - { - if (_itemComparer.Comparison(_items[i - 1], _items[i]) > 0) - { - return false; - } - } - } - return true; - } - - private void _RemoveRange(int index) - { - while (index < _items.Count) - { - _SafeRemoveNotifyAndLookup(_items[index]); - _items.RemoveAt(index); - } - } - - private void _SimpleMerge(IEnumerable newCollection, bool add, int? maxCount) - { - lock (SyncRoot) - { - if (!add) - { - // This just replaces the entire collection. - _MergeClear(); - - if (newCollection == null) - { - return; - } - - foreach (TItem item in _itemComparer.OrderedList(newCollection).Sublist(0, maxCount)) - { - _items.Add(item); - _SafeAddNotifyAndLookup(item); - } - } - else - { - foreach (var item in newCollection) - { - if (!_items.Contains(item)) - { - int index = _FindInsertionPoint(item); - - if (-1 == index) - { - _items.Add(item); - } - else - { - _items.Insert(index, item); - } - _SafeAddNotifyAndLookup(item); - } - } - - if (maxCount != null && _items.Count > maxCount.Value) - { - _RemoveRange(maxCount.Value); - } - } - //Assert.Implies(_areItemsComparable || _customComparison != null, () => _items.AreSorted(_customComparison)); - } - } - - private void _SafeAddNotifyAndLookup(TItem item) - { - Assert.IsNotNull(item); - if (_areItemsNotifiable) - { - ((INotifyPropertyChanged)item).PropertyChanged += _OnItemChanged; - } - - if (_areItemsMergable) - { - //Assert.IsNotNull(((IMergeable)item).FKID); - _fkidLookup.Add(((IMergeable)item).FKID, item); - } - } - - private void _SafeRemoveNotifyAndLookup(TItem item) - { - Assert.IsNotNull(item); - if (_areItemsNotifiable) - { - ((INotifyPropertyChanged)item).PropertyChanged -= _OnItemChanged; - } - - if (_areItemsMergable) - { - //Assert.IsNotNull(((IMergeable)item).FKID); - _fkidLookup.Remove(((IMergeable)item).FKID); - } - } - - private void _OnItemChanged(object sender, PropertyChangedEventArgs e) - { - var item = sender as TItem; - // If we're doing a merge of this item then we expect that properties may change. - // Don't reorder because of this. We expect the merge is putting the item in the right place. - if (item != null && item != _suspendNotificationsForMergeableObject) - { - lock (SyncRoot) - { - int currentIndex = _items.IndexOf(item); - if (-1 != currentIndex) - { - if (!_VerifyInsertionPoint(currentIndex)) - { - _items.RemoveAt(currentIndex); - int newIndex = _FindInsertionPoint(item); - if (newIndex == -1 || newIndex == _items.Count) - { - _items.Add(item); - } - else - { - _items.Insert(newIndex, item); - } - } - } - - //Assert.IsTrue(_items.AreSorted(_customComparison)); - } - } - } - - #region IList Members - - public int IndexOf(TItem item) { return _items.IndexOf(item); } - - public TItem this[int index] - { - get { return _items[index]; } - set { throw new NotSupportedException(); } - } - - #region Unsupported Mutable IList Members - void IList.Insert(int index, TItem item) { throw new NotSupportedException(); } - void IList.RemoveAt(int index) { throw new NotSupportedException(); } - #endregion - - #endregion - - #region ICollection Members - - public bool Contains(TItem item) { return _items.Contains(item); } - public void CopyTo(TItem[] array, int arrayIndex) { _items.CopyTo(array, arrayIndex); } - public int Count { get { return _items.Count; } } - public bool IsReadOnly { get { return true; } } - - public void Clear() { Merge(null, false); } - - public void Add(TItem item) - { - Verify.IsNotNull(item, "item"); - Merge(new [] { item }, true); - } - - public bool Remove(TItem item) - { - Verify.IsNotNull(item, "item"); - - lock (SyncRoot) - { - if (_items.Remove(item)) - { - _SafeRemoveNotifyAndLookup(item); - return true; - } - return false; - } - } - - #endregion - - #region IEnumerable Members - - public IEnumerator GetEnumerator() { return _items.GetEnumerator(); } - - #endregion - - #region IEnumerable Members - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } - - #endregion - - #region INotifyCollectionChanged Members - - public event NotifyCollectionChangedEventHandler CollectionChanged - { - add { _items.CollectionChanged += value; } - remove { _items.CollectionChanged -= value; } - } - - #endregion - } -} diff --git a/Microsoft.Windows.Shell/Standard/MessageWindow.cs b/Microsoft.Windows.Shell/Standard/MessageWindow.cs deleted file mode 100644 index 6551359..0000000 --- a/Microsoft.Windows.Shell/Standard/MessageWindow.cs +++ /dev/null @@ -1,165 +0,0 @@ -namespace Standard -{ - using System; - using System.Collections.Generic; - using System.Diagnostics.CodeAnalysis; - using System.Runtime.InteropServices; - using System.Windows; - using System.Windows.Threading; - - internal sealed class MessageWindow : DispatcherObject, IDisposable - { - // Alias this to a static so the wrapper doesn't get GC'd - private static readonly WndProc s_WndProc = new WndProc(_WndProc); - private static readonly Dictionary s_windowLookup = new Dictionary(); - - private WndProc _wndProcCallback; - private string _className; - private bool _isDisposed; - - public IntPtr Handle { get; private set; } - - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] - public MessageWindow(CS classStyle, WS style, WS_EX exStyle, Rect location, string name, WndProc callback) - { - // A null callback means just use DefWindowProc. - _wndProcCallback = callback; - _className = "MessageWindowClass+" + Guid.NewGuid().ToString(); - - var wc = new WNDCLASSEX - { - cbSize = Marshal.SizeOf(typeof(WNDCLASSEX)), - style = classStyle, - lpfnWndProc = s_WndProc, - hInstance = NativeMethods.GetModuleHandle(null), - hbrBackground = NativeMethods.GetStockObject(StockObject.NULL_BRUSH), - lpszMenuName = "", - lpszClassName = _className, - }; - - NativeMethods.RegisterClassEx(ref wc); - - GCHandle gcHandle = default(GCHandle); - try - { - gcHandle = GCHandle.Alloc(this); - IntPtr pinnedThisPtr = (IntPtr)gcHandle; - - Handle = NativeMethods.CreateWindowEx( - exStyle, - _className, - name, - style, - (int)location.X, - (int)location.Y, - (int)location.Width, - (int)location.Height, - IntPtr.Zero, - IntPtr.Zero, - IntPtr.Zero, - pinnedThisPtr); - } - finally - { - gcHandle.Free(); - } - } - - ~MessageWindow() - { - _Dispose(false, false); - } - - public void Dispose() - { - _Dispose(true, false); - GC.SuppressFinalize(this); - } - - // This isn't right if the Dispatcher has already started shutting down. - // The HWND itself will get cleaned up on thread completion, but it will wind up leaking the class ATOM... - [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disposing")] - private void _Dispose(bool disposing, bool isHwndBeingDestroyed) - { - if (_isDisposed) - { - // Block against reentrancy. - return; - } - - _isDisposed = true; - - IntPtr hwnd = Handle; - string className = _className; - - if (isHwndBeingDestroyed) - { - Dispatcher.BeginInvoke(DispatcherPriority.Normal, (DispatcherOperationCallback)(arg => _DestroyWindow(IntPtr.Zero, className))); - } - else if (Handle != IntPtr.Zero) - { - if (CheckAccess()) - { - _DestroyWindow(hwnd, className); - } - else - { - Dispatcher.BeginInvoke(DispatcherPriority.Normal, (DispatcherOperationCallback)(arg => _DestroyWindow(hwnd, className))); - } - } - - s_windowLookup.Remove(hwnd); - - _className = null; - Handle = IntPtr.Zero; - } - - [SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly")] - private static IntPtr _WndProc(IntPtr hwnd, WM msg, IntPtr wParam, IntPtr lParam) - { - IntPtr ret = IntPtr.Zero; - MessageWindow hwndWrapper = null; - - if (msg == WM.CREATE) - { - var createStruct = (CREATESTRUCT)Marshal.PtrToStructure(lParam, typeof(CREATESTRUCT)); - GCHandle gcHandle = GCHandle.FromIntPtr(createStruct.lpCreateParams); - hwndWrapper = (MessageWindow)gcHandle.Target; - s_windowLookup.Add(hwnd, hwndWrapper); - } - else - { - if (!s_windowLookup.TryGetValue(hwnd, out hwndWrapper)) - { - return NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam); - } - } - Assert.IsNotNull(hwndWrapper); - - WndProc callback = hwndWrapper._wndProcCallback; - if (callback != null) - { - ret = callback(hwnd, msg, wParam, lParam); - } - else - { - ret = NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam); - } - - if (msg == WM.NCDESTROY) - { - hwndWrapper._Dispose(true, true); - GC.SuppressFinalize(hwndWrapper); - } - - return ret; - } - - private static object _DestroyWindow(IntPtr hwnd, string className) - { - Utility.SafeDestroyWindow(ref hwnd); - NativeMethods.UnregisterClass(className, NativeMethods.GetModuleHandle(null)); - return null; - } - } -} diff --git a/Microsoft.Windows.Shell/Standard/NativeMethods.cs b/Microsoft.Windows.Shell/Standard/NativeMethods.cs deleted file mode 100644 index bce4301..0000000 --- a/Microsoft.Windows.Shell/Standard/NativeMethods.cs +++ /dev/null @@ -1,3629 +0,0 @@ - -namespace Standard -{ - using System; - using System.ComponentModel; - using System.Diagnostics.CodeAnalysis; - using System.IO; - using System.Runtime.ConstrainedExecution; - using System.Runtime.InteropServices; - using System.Runtime.InteropServices.ComTypes; - using System.Security.Permissions; - using System.Text; - using Microsoft.Win32.SafeHandles; - - // Some COM interfaces and Win32 structures are already declared in the framework. - // Interesting ones to remember in System.Runtime.InteropServices.ComTypes are: - using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; - using IPersistFile = System.Runtime.InteropServices.ComTypes.IPersistFile; - using IStream = System.Runtime.InteropServices.ComTypes.IStream; - - #region Native Values - - internal static class Win32Value - { - public const uint MAX_PATH = 260; - public const uint INFOTIPSIZE = 1024; - public const int TRUE = 1; - public const int FALSE = 0; - public const uint sizeof_WCHAR = 2; - public const uint sizeof_CHAR = 1; - public const uint sizeof_BOOL = 4; - } - - /// - /// HIGHCONTRAST flags - /// - [Flags] - internal enum HCF - { - HIGHCONTRASTON = 0x00000001, - AVAILABLE = 0x00000002, - HOTKEYACTIVE = 0x00000004, - CONFIRMHOTKEY = 0x00000008, - HOTKEYSOUND = 0x00000010, - INDICATOR = 0x00000020, - HOTKEYAVAILABLE = 0x00000040, - } - - internal enum DROPEFFECT - { - NONE = 0, - COPY = 1, - MOVE = 2, - LINK = 4, - SCROLL = unchecked((int)0x80000000), - } - - /// - /// DROPIMAGE_* - /// - internal enum DROPIMAGETYPE - { - INVALID = -1, - NONE = 0, - COPY = DROPEFFECT.COPY, - MOVE = DROPEFFECT.MOVE, - LINK = DROPEFFECT.LINK, - LABEL = 6, - WARNING = 7, - // Windows 7 and later - NOIMAGE = 8, - } - - /// - /// BITMAPINFOHEADER Compression type. BI_*. - /// - internal enum BI - { - RGB = 0, - } - - /// - /// CombingRgn flags. RGN_* - /// - internal enum RGN - { - /// - /// Creates the intersection of the two combined regions. - /// - AND = 1, - /// - /// Creates the union of two combined regions. - /// - OR = 2, - /// - /// Creates the union of two combined regions except for any overlapping areas. - /// - XOR = 3, - /// - /// Combines the parts of hrgnSrc1 that are not part of hrgnSrc2. - /// - DIFF = 4, - /// - /// Creates a copy of the region identified by hrgnSrc1. - /// - COPY = 5, - } - - internal enum CombineRgnResult - { - ERROR = 0, - NULLREGION = 1, - SIMPLEREGION = 2, - COMPLEXREGION = 3, - } - - /// - /// For IWebBrowser2. OLECMDEXECOPT_* - /// - internal enum OLECMDEXECOPT - { - DODEFAULT = 0, - PROMPTUSER = 1, - DONTPROMPTUSER = 2, - SHOWHELP = 3 - } - - /// - /// For IWebBrowser2. OLECMDF_* - /// - internal enum OLECMDF - { - SUPPORTED = 1, - ENABLED = 2, - LATCHED = 4, - NINCHED = 8, - INVISIBLE = 16, - DEFHIDEONCTXTMENU = 32 - } - - /// - /// For IWebBrowser2. OLECMDID_* - /// - internal enum OLECMDID - { - OPEN = 1, - NEW = 2, - SAVE = 3, - SAVEAS = 4, - SAVECOPYAS = 5, - PRINT = 6, - PRINTPREVIEW = 7, - PAGESETUP = 8, - SPELL = 9, - PROPERTIES = 10, - CUT = 11, - COPY = 12, - PASTE = 13, - PASTESPECIAL = 14, - UNDO = 15, - REDO = 16, - SELECTALL = 17, - CLEARSELECTION = 18, - ZOOM = 19, - GETZOOMRANGE = 20, - UPDATECOMMANDS = 21, - REFRESH = 22, - STOP = 23, - HIDETOOLBARS = 24, - SETPROGRESSMAX = 25, - SETPROGRESSPOS = 26, - SETPROGRESSTEXT = 27, - SETTITLE = 28, - SETDOWNLOADSTATE = 29, - STOPDOWNLOAD = 30, - ONTOOLBARACTIVATED = 31, - FIND = 32, - DELETE = 33, - HTTPEQUIV = 34, - HTTPEQUIV_DONE = 35, - ENABLE_INTERACTION = 36, - ONUNLOAD = 37, - PROPERTYBAG2 = 38, - PREREFRESH = 39, - SHOWSCRIPTERROR = 40, - SHOWMESSAGE = 41, - SHOWFIND = 42, - SHOWPAGESETUP = 43, - SHOWPRINT = 44, - CLOSE = 45, - ALLOWUILESSSAVEAS = 46, - DONTDOWNLOADCSS = 47, - UPDATEPAGESTATUS = 48, - PRINT2 = 49, - PRINTPREVIEW2 = 50, - SETPRINTTEMPLATE = 51, - GETPRINTTEMPLATE = 52, - PAGEACTIONBLOCKED = 55, - PAGEACTIONUIQUERY = 56, - FOCUSVIEWCONTROLS = 57, - FOCUSVIEWCONTROLSQUERY = 58, - SHOWPAGEACTIONMENU = 59 - } - - /// - /// For IWebBrowser2. READYSTATE_* - /// - enum READYSTATE - { - UNINITIALIZED = 0, - LOADING = 1, - LOADED = 2, - INTERACTIVE = 3, - COMPLETE = 4 - } - - /// - /// DATAOBJ_GET_ITEM_FLAGS. DOGIF_*. - /// - internal enum DOGIF - { - DEFAULT = 0x0000, - TRAVERSE_LINK = 0x0001, // if the item is a link get the target - NO_HDROP = 0x0002, // don't fallback and use CF_HDROP clipboard format - NO_URL = 0x0004, // don't fallback and use URL clipboard format - ONLY_IF_ONE = 0x0008, // only return the item if there is one item in the array - } - - internal enum DWM_SIT - { - None, - DISPLAYFRAME = 1, - } - - [Flags] - internal enum ErrorModes - { - /// Use the system default, which is to display all error dialog boxes. - Default = 0x0, - /// - /// The system does not display the critical-error-handler message box. - /// Instead, the system sends the error to the calling process. - /// - FailCriticalErrors = 0x1, - /// - /// 64-bit Windows: The system automatically fixes memory alignment faults and makes them - /// invisible to the application. It does this for the calling process and any descendant processes. - /// After this value is set for a process, subsequent attempts to clear the value are ignored. - /// - NoGpFaultErrorBox = 0x2, - /// - /// The system does not display the general-protection-fault message box. - /// This flag should only be set by debugging applications that handle general - /// protection (GP) faults themselves with an exception handler. - /// - NoAlignmentFaultExcept = 0x4, - /// - /// The system does not display a message box when it fails to find a file. - /// Instead, the error is returned to the calling process. - /// - NoOpenFileErrorBox = 0x8000 - } - - /// - /// Non-client hit test values, HT* - /// - internal enum HT - { - ERROR = -2, - TRANSPARENT = -1, - NOWHERE = 0, - CLIENT = 1, - CAPTION = 2, - SYSMENU = 3, - GROWBOX = 4, - MENU = 5, - HSCROLL = 6, - VSCROLL = 7, - MINBUTTON = 8, - MAXBUTTON = 9, - LEFT = 10, - RIGHT = 11, - TOP = 12, - TOPLEFT = 13, - TOPRIGHT = 14, - BOTTOM = 15, - BOTTOMLEFT = 16, - BOTTOMRIGHT = 17, - BORDER = 18, - OBJECT = 19, - CLOSE = 20, - HELP = 21 - } - - /// - /// GetClassLongPtr values, GCLP_* - /// - internal enum GCLP - { - HBRBACKGROUND = -10, - } - - /// - /// GetWindowLongPtr values, GWL_* - /// - internal enum GWL - { - WNDPROC = (-4), - HINSTANCE = (-6), - HWNDPARENT = (-8), - STYLE = (-16), - EXSTYLE = (-20), - USERDATA = (-21), - ID = (-12) - } - - /// - /// SystemMetrics. SM_* - /// - 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, - } - - /// - /// SystemParameterInfo values, SPI_* - /// - internal enum SPI - { - GETBEEP = 0x0001, - SETBEEP = 0x0002, - GETMOUSE = 0x0003, - SETMOUSE = 0x0004, - GETBORDER = 0x0005, - SETBORDER = 0x0006, - GETKEYBOARDSPEED = 0x000A, - SETKEYBOARDSPEED = 0x000B, - LANGDRIVER = 0x000C, - ICONHORIZONTALSPACING = 0x000D, - GETSCREENSAVETIMEOUT = 0x000E, - SETSCREENSAVETIMEOUT = 0x000F, - GETSCREENSAVEACTIVE = 0x0010, - SETSCREENSAVEACTIVE = 0x0011, - GETGRIDGRANULARITY = 0x0012, - SETGRIDGRANULARITY = 0x0013, - SETDESKWALLPAPER = 0x0014, - SETDESKPATTERN = 0x0015, - GETKEYBOARDDELAY = 0x0016, - SETKEYBOARDDELAY = 0x0017, - ICONVERTICALSPACING = 0x0018, - GETICONTITLEWRAP = 0x0019, - SETICONTITLEWRAP = 0x001A, - GETMENUDROPALIGNMENT = 0x001B, - SETMENUDROPALIGNMENT = 0x001C, - SETDOUBLECLKWIDTH = 0x001D, - SETDOUBLECLKHEIGHT = 0x001E, - GETICONTITLELOGFONT = 0x001F, - SETDOUBLECLICKTIME = 0x0020, - SETMOUSEBUTTONSWAP = 0x0021, - SETICONTITLELOGFONT = 0x0022, - GETFASTTASKSWITCH = 0x0023, - SETFASTTASKSWITCH = 0x0024, - - SETDRAGFULLWINDOWS = 0x0025, - GETDRAGFULLWINDOWS = 0x0026, - GETNONCLIENTMETRICS = 0x0029, - SETNONCLIENTMETRICS = 0x002A, - GETMINIMIZEDMETRICS = 0x002B, - SETMINIMIZEDMETRICS = 0x002C, - GETICONMETRICS = 0x002D, - SETICONMETRICS = 0x002E, - SETWORKAREA = 0x002F, - GETWORKAREA = 0x0030, - SETPENWINDOWS = 0x0031, - GETHIGHCONTRAST = 0x0042, - SETHIGHCONTRAST = 0x0043, - GETKEYBOARDPREF = 0x0044, - SETKEYBOARDPREF = 0x0045, - GETSCREENREADER = 0x0046, - SETSCREENREADER = 0x0047, - GETANIMATION = 0x0048, - SETANIMATION = 0x0049, - GETFONTSMOOTHING = 0x004A, - SETFONTSMOOTHING = 0x004B, - SETDRAGWIDTH = 0x004C, - SETDRAGHEIGHT = 0x004D, - SETHANDHELD = 0x004E, - GETLOWPOWERTIMEOUT = 0x004F, - GETPOWEROFFTIMEOUT = 0x0050, - SETLOWPOWERTIMEOUT = 0x0051, - SETPOWEROFFTIMEOUT = 0x0052, - GETLOWPOWERACTIVE = 0x0053, - GETPOWEROFFACTIVE = 0x0054, - SETLOWPOWERACTIVE = 0x0055, - SETPOWEROFFACTIVE = 0x0056, - SETCURSORS = 0x0057, - SETICONS = 0x0058, - GETDEFAULTINPUTLANG = 0x0059, - SETDEFAULTINPUTLANG = 0x005A, - SETLANGTOGGLE = 0x005B, - GETWINDOWSEXTENSION = 0x005C, - SETMOUSETRAILS = 0x005D, - GETMOUSETRAILS = 0x005E, - SETSCREENSAVERRUNNING = 0x0061, - SCREENSAVERRUNNING = SETSCREENSAVERRUNNING, - GETFILTERKEYS = 0x0032, - SETFILTERKEYS = 0x0033, - GETTOGGLEKEYS = 0x0034, - SETTOGGLEKEYS = 0x0035, - GETMOUSEKEYS = 0x0036, - SETMOUSEKEYS = 0x0037, - GETSHOWSOUNDS = 0x0038, - SETSHOWSOUNDS = 0x0039, - GETSTICKYKEYS = 0x003A, - SETSTICKYKEYS = 0x003B, - GETACCESSTIMEOUT = 0x003C, - SETACCESSTIMEOUT = 0x003D, - - GETSERIALKEYS = 0x003E, - SETSERIALKEYS = 0x003F, - GETSOUNDSENTRY = 0x0040, - SETSOUNDSENTRY = 0x0041, - GETSNAPTODEFBUTTON = 0x005F, - SETSNAPTODEFBUTTON = 0x0060, - GETMOUSEHOVERWIDTH = 0x0062, - SETMOUSEHOVERWIDTH = 0x0063, - GETMOUSEHOVERHEIGHT = 0x0064, - SETMOUSEHOVERHEIGHT = 0x0065, - GETMOUSEHOVERTIME = 0x0066, - SETMOUSEHOVERTIME = 0x0067, - GETWHEELSCROLLLINES = 0x0068, - SETWHEELSCROLLLINES = 0x0069, - GETMENUSHOWDELAY = 0x006A, - SETMENUSHOWDELAY = 0x006B, - - GETWHEELSCROLLCHARS = 0x006C, - SETWHEELSCROLLCHARS = 0x006D, - - GETSHOWIMEUI = 0x006E, - SETSHOWIMEUI = 0x006F, - - GETMOUSESPEED = 0x0070, - SETMOUSESPEED = 0x0071, - GETSCREENSAVERRUNNING = 0x0072, - GETDESKWALLPAPER = 0x0073, - - GETAUDIODESCRIPTION = 0x0074, - SETAUDIODESCRIPTION = 0x0075, - - GETSCREENSAVESECURE = 0x0076, - SETSCREENSAVESECURE = 0x0077, - - GETHUNGAPPTIMEOUT = 0x0078, - SETHUNGAPPTIMEOUT = 0x0079, - GETWAITTOKILLTIMEOUT = 0x007A, - SETWAITTOKILLTIMEOUT = 0x007B, - GETWAITTOKILLSERVICETIMEOUT = 0x007C, - SETWAITTOKILLSERVICETIMEOUT = 0x007D, - GETMOUSEDOCKTHRESHOLD = 0x007E, - SETMOUSEDOCKTHRESHOLD = 0x007F, - GETPENDOCKTHRESHOLD = 0x0080, - SETPENDOCKTHRESHOLD = 0x0081, - GETWINARRANGING = 0x0082, - SETWINARRANGING = 0x0083, - GETMOUSEDRAGOUTTHRESHOLD = 0x0084, - SETMOUSEDRAGOUTTHRESHOLD = 0x0085, - GETPENDRAGOUTTHRESHOLD = 0x0086, - SETPENDRAGOUTTHRESHOLD = 0x0087, - GETMOUSESIDEMOVETHRESHOLD = 0x0088, - SETMOUSESIDEMOVETHRESHOLD = 0x0089, - GETPENSIDEMOVETHRESHOLD = 0x008A, - SETPENSIDEMOVETHRESHOLD = 0x008B, - GETDRAGFROMMAXIMIZE = 0x008C, - SETDRAGFROMMAXIMIZE = 0x008D, - GETSNAPSIZING = 0x008E, - SETSNAPSIZING = 0x008F, - GETDOCKMOVING = 0x0090, - SETDOCKMOVING = 0x0091, - - GETACTIVEWINDOWTRACKING = 0x1000, - SETACTIVEWINDOWTRACKING = 0x1001, - GETMENUANIMATION = 0x1002, - SETMENUANIMATION = 0x1003, - GETCOMBOBOXANIMATION = 0x1004, - SETCOMBOBOXANIMATION = 0x1005, - GETLISTBOXSMOOTHSCROLLING = 0x1006, - SETLISTBOXSMOOTHSCROLLING = 0x1007, - GETGRADIENTCAPTIONS = 0x1008, - SETGRADIENTCAPTIONS = 0x1009, - GETKEYBOARDCUES = 0x100A, - SETKEYBOARDCUES = 0x100B, - GETMENUUNDERLINES = GETKEYBOARDCUES, - SETMENUUNDERLINES = SETKEYBOARDCUES, - GETACTIVEWNDTRKZORDER = 0x100C, - SETACTIVEWNDTRKZORDER = 0x100D, - GETHOTTRACKING = 0x100E, - SETHOTTRACKING = 0x100F, - GETMENUFADE = 0x1012, - SETMENUFADE = 0x1013, - GETSELECTIONFADE = 0x1014, - SETSELECTIONFADE = 0x1015, - GETTOOLTIPANIMATION = 0x1016, - SETTOOLTIPANIMATION = 0x1017, - GETTOOLTIPFADE = 0x1018, - SETTOOLTIPFADE = 0x1019, - GETCURSORSHADOW = 0x101A, - SETCURSORSHADOW = 0x101B, - GETMOUSESONAR = 0x101C, - SETMOUSESONAR = 0x101D, - GETMOUSECLICKLOCK = 0x101E, - SETMOUSECLICKLOCK = 0x101F, - GETMOUSEVANISH = 0x1020, - SETMOUSEVANISH = 0x1021, - GETFLATMENU = 0x1022, - SETFLATMENU = 0x1023, - GETDROPSHADOW = 0x1024, - SETDROPSHADOW = 0x1025, - GETBLOCKSENDINPUTRESETS = 0x1026, - SETBLOCKSENDINPUTRESETS = 0x1027, - - GETUIEFFECTS = 0x103E, - SETUIEFFECTS = 0x103F, - - GETDISABLEOVERLAPPEDCONTENT = 0x1040, - SETDISABLEOVERLAPPEDCONTENT = 0x1041, - GETCLIENTAREAANIMATION = 0x1042, - SETCLIENTAREAANIMATION = 0x1043, - GETCLEARTYPE = 0x1048, - SETCLEARTYPE = 0x1049, - GETSPEECHRECOGNITION = 0x104A, - SETSPEECHRECOGNITION = 0x104B, - - GETFOREGROUNDLOCKTIMEOUT = 0x2000, - SETFOREGROUNDLOCKTIMEOUT = 0x2001, - GETACTIVEWNDTRKTIMEOUT = 0x2002, - SETACTIVEWNDTRKTIMEOUT = 0x2003, - GETFOREGROUNDFLASHCOUNT = 0x2004, - SETFOREGROUNDFLASHCOUNT = 0x2005, - GETCARETWIDTH = 0x2006, - SETCARETWIDTH = 0x2007, - - GETMOUSECLICKLOCKTIME = 0x2008, - SETMOUSECLICKLOCKTIME = 0x2009, - GETFONTSMOOTHINGTYPE = 0x200A, - SETFONTSMOOTHINGTYPE = 0x200B, - - GETFONTSMOOTHINGCONTRAST = 0x200C, - SETFONTSMOOTHINGCONTRAST = 0x200D, - - GETFOCUSBORDERWIDTH = 0x200E, - SETFOCUSBORDERWIDTH = 0x200F, - GETFOCUSBORDERHEIGHT = 0x2010, - SETFOCUSBORDERHEIGHT = 0x2011, - - GETFONTSMOOTHINGORIENTATION = 0x2012, - SETFONTSMOOTHINGORIENTATION = 0x2013, - - GETMINIMUMHITRADIUS = 0x2014, - SETMINIMUMHITRADIUS = 0x2015, - GETMESSAGEDURATION = 0x2016, - SETMESSAGEDURATION = 0x2017, - } - - /// - /// SystemParameterInfo flag values, SPIF_* - /// - [Flags] - internal enum SPIF - { - None = 0, - UPDATEINIFILE = 0x01, - SENDWININICHANGE = 0x02, - } - - [Flags] - internal enum STATE_SYSTEM - { - UNAVAILABLE = 0x00000001, // Disabled - SELECTED = 0x00000002, - FOCUSED = 0x00000004, - PRESSED = 0x00000008, - CHECKED = 0x00000010, - MIXED = 0x00000020, // 3-state checkbox or toolbar button - INDETERMINATE = MIXED, - READONLY = 0x00000040, - HOTTRACKED = 0x00000080, - DEFAULT = 0x00000100, - EXPANDED = 0x00000200, - COLLAPSED = 0x00000400, - BUSY = 0x00000800, - FLOATING = 0x00001000, // Children "owned" not "contained" by parent - MARQUEED = 0x00002000, - ANIMATED = 0x00004000, - INVISIBLE = 0x00008000, - OFFSCREEN = 0x00010000, - SIZEABLE = 0x00020000, - MOVEABLE = 0x00040000, - SELFVOICING = 0x00080000, - FOCUSABLE = 0x00100000, - SELECTABLE = 0x00200000, - LINKED = 0x00400000, - TRAVERSED = 0x00800000, - MULTISELECTABLE = 0x01000000, // Supports multiple selection - EXTSELECTABLE = 0x02000000, // Supports extended selection - ALERT_LOW = 0x04000000, // This information is of low priority - ALERT_MEDIUM = 0x08000000, // This information is of medium priority - ALERT_HIGH = 0x10000000, // This information is of high priority - PROTECTED = 0x20000000, // access to this is restricted - VALID = 0x3FFFFFFF, - } - - internal enum StockObject : int - { - WHITE_BRUSH = 0, - LTGRAY_BRUSH = 1, - GRAY_BRUSH = 2, - DKGRAY_BRUSH = 3, - BLACK_BRUSH = 4, - NULL_BRUSH = 5, - HOLLOW_BRUSH = NULL_BRUSH, - WHITE_PEN = 6, - BLACK_PEN = 7, - NULL_PEN = 8, - SYSTEM_FONT = 13, - DEFAULT_PALETTE = 15, - } - - /// - /// CS_* - /// - [Flags] - internal enum CS : uint - { - VREDRAW = 0x0001, - HREDRAW = 0x0002, - DBLCLKS = 0x0008, - OWNDC = 0x0020, - CLASSDC = 0x0040, - PARENTDC = 0x0080, - NOCLOSE = 0x0200, - SAVEBITS = 0x0800, - BYTEALIGNCLIENT = 0x1000, - BYTEALIGNWINDOW = 0x2000, - GLOBALCLASS = 0x4000, - IME = 0x00010000, - DROPSHADOW = 0x00020000 - } - - /// - /// WindowStyle values, WS_* - /// - [Flags] - internal enum WS : uint - { - OVERLAPPED = 0x00000000, - POPUP = 0x80000000, - CHILD = 0x40000000, - MINIMIZE = 0x20000000, - VISIBLE = 0x10000000, - DISABLED = 0x08000000, - CLIPSIBLINGS = 0x04000000, - CLIPCHILDREN = 0x02000000, - MAXIMIZE = 0x01000000, - BORDER = 0x00800000, - DLGFRAME = 0x00400000, - VSCROLL = 0x00200000, - HSCROLL = 0x00100000, - SYSMENU = 0x00080000, - THICKFRAME = 0x00040000, - GROUP = 0x00020000, - TABSTOP = 0x00010000, - - MINIMIZEBOX = 0x00020000, - MAXIMIZEBOX = 0x00010000, - - CAPTION = BORDER | DLGFRAME, - TILED = OVERLAPPED, - ICONIC = MINIMIZE, - SIZEBOX = THICKFRAME, - TILEDWINDOW = OVERLAPPEDWINDOW, - - OVERLAPPEDWINDOW = OVERLAPPED | CAPTION | SYSMENU | THICKFRAME | MINIMIZEBOX | MAXIMIZEBOX, - POPUPWINDOW = POPUP | BORDER | SYSMENU, - CHILDWINDOW = CHILD, - } - - /// - /// Window message values, WM_* - /// - internal enum WM - { - NULL = 0x0000, - CREATE = 0x0001, - DESTROY = 0x0002, - MOVE = 0x0003, - SIZE = 0x0005, - ACTIVATE = 0x0006, - SETFOCUS = 0x0007, - KILLFOCUS = 0x0008, - ENABLE = 0x000A, - SETREDRAW = 0x000B, - SETTEXT = 0x000C, - GETTEXT = 0x000D, - GETTEXTLENGTH = 0x000E, - PAINT = 0x000F, - CLOSE = 0x0010, - QUERYENDSESSION = 0x0011, - QUIT = 0x0012, - QUERYOPEN = 0x0013, - ERASEBKGND = 0x0014, - SYSCOLORCHANGE = 0x0015, - SHOWWINDOW = 0x0018, - CTLCOLOR = 0x0019, - WININICHANGE = 0x001A, - SETTINGCHANGE = 0x001A, - ACTIVATEAPP = 0x001C, - SETCURSOR = 0x0020, - MOUSEACTIVATE = 0x0021, - CHILDACTIVATE = 0x0022, - QUEUESYNC = 0x0023, - GETMINMAXINFO = 0x0024, - - WINDOWPOSCHANGING = 0x0046, - WINDOWPOSCHANGED = 0x0047, - - CONTEXTMENU = 0x007B, - STYLECHANGING = 0x007C, - STYLECHANGED = 0x007D, - DISPLAYCHANGE = 0x007E, - GETICON = 0x007F, - SETICON = 0x0080, - NCCREATE = 0x0081, - NCDESTROY = 0x0082, - NCCALCSIZE = 0x0083, - NCHITTEST = 0x0084, - NCPAINT = 0x0085, - NCACTIVATE = 0x0086, - GETDLGCODE = 0x0087, - SYNCPAINT = 0x0088, - NCMOUSEMOVE = 0x00A0, - NCLBUTTONDOWN = 0x00A1, - NCLBUTTONUP = 0x00A2, - NCLBUTTONDBLCLK = 0x00A3, - NCRBUTTONDOWN = 0x00A4, - NCRBUTTONUP = 0x00A5, - NCRBUTTONDBLCLK = 0x00A6, - NCMBUTTONDOWN = 0x00A7, - NCMBUTTONUP = 0x00A8, - NCMBUTTONDBLCLK = 0x00A9, - - SYSKEYDOWN = 0x0104, - SYSKEYUP = 0x0105, - SYSCHAR = 0x0106, - SYSDEADCHAR = 0x0107, - COMMAND = 0x0111, - SYSCOMMAND = 0x0112, - - MOUSEMOVE = 0x0200, - LBUTTONDOWN = 0x0201, - LBUTTONUP = 0x0202, - LBUTTONDBLCLK = 0x0203, - RBUTTONDOWN = 0x0204, - RBUTTONUP = 0x0205, - RBUTTONDBLCLK = 0x0206, - MBUTTONDOWN = 0x0207, - MBUTTONUP = 0x0208, - MBUTTONDBLCLK = 0x0209, - MOUSEWHEEL = 0x020A, - XBUTTONDOWN = 0x020B, - XBUTTONUP = 0x020C, - XBUTTONDBLCLK = 0x020D, - MOUSEHWHEEL = 0x020E, - PARENTNOTIFY = 0x0210, - - CAPTURECHANGED = 0x0215, - POWERBROADCAST = 0x0218, - DEVICECHANGE = 0x0219, - - ENTERSIZEMOVE = 0x0231, - EXITSIZEMOVE = 0x0232, - - IME_SETCONTEXT = 0x0281, - IME_NOTIFY = 0x0282, - IME_CONTROL = 0x0283, - IME_COMPOSITIONFULL = 0x0284, - IME_SELECT = 0x0285, - IME_CHAR = 0x0286, - IME_REQUEST = 0x0288, - IME_KEYDOWN = 0x0290, - IME_KEYUP = 0x0291, - - NCMOUSELEAVE = 0x02A2, - - TABLET_DEFBASE = 0x02C0, - //WM_TABLET_MAXOFFSET = 0x20, - - TABLET_ADDED = TABLET_DEFBASE + 8, - TABLET_DELETED = TABLET_DEFBASE + 9, - TABLET_FLICK = TABLET_DEFBASE + 11, - TABLET_QUERYSYSTEMGESTURESTATUS = TABLET_DEFBASE + 12, - - CUT = 0x0300, - COPY = 0x0301, - PASTE = 0x0302, - CLEAR = 0x0303, - UNDO = 0x0304, - RENDERFORMAT = 0x0305, - RENDERALLFORMATS = 0x0306, - DESTROYCLIPBOARD = 0x0307, - DRAWCLIPBOARD = 0x0308, - PAINTCLIPBOARD = 0x0309, - VSCROLLCLIPBOARD = 0x030A, - SIZECLIPBOARD = 0x030B, - ASKCBFORMATNAME = 0x030C, - CHANGECBCHAIN = 0x030D, - HSCROLLCLIPBOARD = 0x030E, - QUERYNEWPALETTE = 0x030F, - PALETTEISCHANGING = 0x0310, - PALETTECHANGED = 0x0311, - HOTKEY = 0x0312, - PRINT = 0x0317, - PRINTCLIENT = 0x0318, - APPCOMMAND = 0x0319, - THEMECHANGED = 0x031A, - - DWMCOMPOSITIONCHANGED = 0x031E, - DWMNCRENDERINGCHANGED = 0x031F, - DWMCOLORIZATIONCOLORCHANGED = 0x0320, - DWMWINDOWMAXIMIZEDCHANGE = 0x0321, - - GETTITLEBARINFOEX = 0x033F, - - #region Windows 7 - DWMSENDICONICTHUMBNAIL = 0x0323, - DWMSENDICONICLIVEPREVIEWBITMAP = 0x0326, - #endregion - - USER = 0x0400, - - // This is the hard-coded message value used by WinForms for Shell_NotifyIcon. - // It's relatively safe to reuse. - TRAYMOUSEMESSAGE = 0x800, //WM_USER + 1024 - APP = 0x8000, - } - - /// - /// Window style extended values, WS_EX_* - /// - [Flags] - internal enum WS_EX : uint - { - None = 0, - DLGMODALFRAME = 0x00000001, - NOPARENTNOTIFY = 0x00000004, - TOPMOST = 0x00000008, - ACCEPTFILES = 0x00000010, - TRANSPARENT = 0x00000020, - MDICHILD = 0x00000040, - TOOLWINDOW = 0x00000080, - WINDOWEDGE = 0x00000100, - CLIENTEDGE = 0x00000200, - CONTEXTHELP = 0x00000400, - RIGHT = 0x00001000, - LEFT = 0x00000000, - RTLREADING = 0x00002000, - LTRREADING = 0x00000000, - LEFTSCROLLBAR = 0x00004000, - RIGHTSCROLLBAR = 0x00000000, - CONTROLPARENT = 0x00010000, - STATICEDGE = 0x00020000, - APPWINDOW = 0x00040000, - LAYERED = 0x00080000, - NOINHERITLAYOUT = 0x00100000, // Disable inheritence of mirroring by children - LAYOUTRTL = 0x00400000, // Right to left mirroring - COMPOSITED = 0x02000000, - NOACTIVATE = 0x08000000, - OVERLAPPEDWINDOW = (WINDOWEDGE | CLIENTEDGE), - PALETTEWINDOW = (WINDOWEDGE | TOOLWINDOW | TOPMOST), - } - - /// - /// GetDeviceCaps nIndex values. - /// - internal enum DeviceCap - { - /// Number of bits per pixel - /// - BITSPIXEL = 12, - /// - /// Number of planes - /// - PLANES = 14, - /// - /// Logical pixels inch in X - /// - LOGPIXELSX = 88, - /// - /// Logical pixels inch in Y - /// - LOGPIXELSY = 90, - } - - internal enum FO : int - { - MOVE = 0x0001, - COPY = 0x0002, - DELETE = 0x0003, - RENAME = 0x0004, - } - - /// - /// "FILEOP_FLAGS", FOF_*. - /// - internal enum FOF : ushort - { - MULTIDESTFILES = 0x0001, - CONFIRMMOUSE = 0x0002, - SILENT = 0x0004, - RENAMEONCOLLISION = 0x0008, - NOCONFIRMATION = 0x0010, - WANTMAPPINGHANDLE = 0x0020, - ALLOWUNDO = 0x0040, - FILESONLY = 0x0080, - SIMPLEPROGRESS = 0x0100, - NOCONFIRMMKDIR = 0x0200, - NOERRORUI = 0x0400, - NOCOPYSECURITYATTRIBS = 0x0800, - NORECURSION = 0x1000, - NO_CONNECTED_ELEMENTS = 0x2000, - WANTNUKEWARNING = 0x4000, - NORECURSEREPARSE = 0x8000, - } - - /// - /// EnableMenuItem uEnable values, MF_* - /// - [Flags] - internal enum MF : uint - { - /// - /// Possible return value for EnableMenuItem - /// - DOES_NOT_EXIST = unchecked((uint)-1), - ENABLED = 0, - BYCOMMAND = 0, - GRAYED = 1, - DISABLED = 2, - } - - /// Specifies the type of visual style attribute to set on a window. - internal enum WINDOWTHEMEATTRIBUTETYPE : uint - { - /// Non-client area window attributes will be set. - WTA_NONCLIENT = 1, - } - - /// - /// DWMFLIP3DWINDOWPOLICY. DWMFLIP3D_* - /// - internal enum DWMFLIP3D - { - DEFAULT, - EXCLUDEBELOW, - EXCLUDEABOVE, - //LAST - } - - /// - /// DWMNCRENDERINGPOLICY. DWMNCRP_* - /// - internal enum DWMNCRP - { - USEWINDOWSTYLE, - DISABLED, - ENABLED, - //LAST - } - - /// - /// DWMWINDOWATTRIBUTE. DWMWA_* - /// - internal enum DWMWA - { - NCRENDERING_ENABLED = 1, - NCRENDERING_POLICY, - TRANSITIONS_FORCEDISABLED, - ALLOW_NCPAINT, - CAPTION_BUTTON_BOUNDS, - NONCLIENT_RTL_LAYOUT, - FORCE_ICONIC_REPRESENTATION, - FLIP3D_POLICY, - EXTENDED_FRAME_BOUNDS, - - // New to Windows 7: - - HAS_ICONIC_BITMAP, - DISALLOW_PEEK, - EXCLUDED_FROM_PEEK, - - // LAST - } - - /// - /// WindowThemeNonClientAttributes - /// - [Flags] - internal enum WTNCA : uint - { - /// Prevents the window caption from being drawn. - NODRAWCAPTION = 0x00000001, - /// Prevents the system icon from being drawn. - NODRAWICON = 0x00000002, - /// Prevents the system icon menu from appearing. - NOSYSMENU = 0x00000004, - /// Prevents mirroring of the question mark, even in right-to-left (RTL) layout. - NOMIRRORHELP = 0x00000008, - /// A mask that contains all the valid bits. - VALIDBITS = NODRAWCAPTION | NODRAWICON | NOMIRRORHELP | NOSYSMENU, - } - - /// - /// SetWindowPos options - /// - [Flags] - internal enum SWP - { - ASYNCWINDOWPOS = 0x4000, - DEFERERASE = 0x2000, - DRAWFRAME = 0x0020, - FRAMECHANGED = 0x0020, - HIDEWINDOW = 0x0080, - NOACTIVATE = 0x0010, - NOCOPYBITS = 0x0100, - NOMOVE = 0x0002, - NOOWNERZORDER = 0x0200, - NOREDRAW = 0x0008, - NOREPOSITION = 0x0200, - NOSENDCHANGING = 0x0400, - NOSIZE = 0x0001, - NOZORDER = 0x0004, - SHOWWINDOW = 0x0040, - } - - /// - /// ShowWindow options - /// - internal enum SW - { - HIDE = 0, - SHOWNORMAL = 1, - NORMAL = 1, - SHOWMINIMIZED = 2, - SHOWMAXIMIZED = 3, - MAXIMIZE = 3, - SHOWNOACTIVATE = 4, - SHOW = 5, - MINIMIZE = 6, - SHOWMINNOACTIVE = 7, - SHOWNA = 8, - RESTORE = 9, - SHOWDEFAULT = 10, - FORCEMINIMIZE = 11, - } - - internal enum SC - { - SIZE = 0xF000, - MOVE = 0xF010, - MINIMIZE = 0xF020, - MAXIMIZE = 0xF030, - NEXTWINDOW = 0xF040, - PREVWINDOW = 0xF050, - CLOSE = 0xF060, - VSCROLL = 0xF070, - HSCROLL = 0xF080, - MOUSEMENU = 0xF090, - KEYMENU = 0xF100, - ARRANGE = 0xF110, - RESTORE = 0xF120, - TASKLIST = 0xF130, - SCREENSAVE = 0xF140, - HOTKEY = 0xF150, - DEFAULT = 0xF160, - MONITORPOWER = 0xF170, - CONTEXTHELP = 0xF180, - SEPARATOR = 0xF00F, - /// - /// SCF_ISSECURE - /// - F_ISSECURE = 0x00000001, - ICON = MINIMIZE, - ZOOM = MAXIMIZE, - } - - /// - /// GDI+ Status codes - /// - internal enum Status - { - 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, - ProfileNotFound = 21, - } - - internal enum MOUSEEVENTF : int - { - //mouse event constants - LEFTDOWN = 2, - LEFTUP = 4 - } - - /// - /// MSGFLT_*. New in Vista. Realiased in Windows 7. - /// - internal enum MSGFLT - { - // Win7 versions of this enum: - RESET = 0, - ALLOW = 1, - DISALLOW = 2, - - // Vista versions of this enum: - // ADD = 1, - // REMOVE = 2, - } - - internal enum MSGFLTINFO - { - NONE = 0, - ALREADYALLOWED_FORWND = 1, - ALREADYDISALLOWED_FORWND = 2, - ALLOWED_HIGHER = 3, - } - - internal enum INPUT_TYPE : uint - { - MOUSE = 0, - } - - /// - /// Shell_NotifyIcon messages. NIM_* - /// - internal enum NIM : uint - { - ADD = 0, - MODIFY = 1, - DELETE = 2, - SETFOCUS = 3, - SETVERSION = 4, - } - - /// - /// SHAddToRecentDocuments flags. SHARD_* - /// - internal enum SHARD - { - PIDL = 0x00000001, - PATHA = 0x00000002, - PATHW = 0x00000003, - APPIDINFO = 0x00000004, // indicates the data type is a pointer to a SHARDAPPIDINFO structure - APPIDINFOIDLIST = 0x00000005, // indicates the data type is a pointer to a SHARDAPPIDINFOIDLIST structure - LINK = 0x00000006, // indicates the data type is a pointer to an IShellLink instance - APPIDINFOLINK = 0x00000007, // indicates the data type is a pointer to a SHARDAPPIDINFOLINK structure - } - - [Flags] - enum SLGP - { - SHORTPATH = 0x1, - UNCPRIORITY = 0x2, - RAWPATH = 0x4 - } - - /// - /// Shell_NotifyIcon flags. NIF_* - /// - [Flags] - internal enum NIF : uint - { - MESSAGE = 0x0001, - ICON = 0x0002, - TIP = 0x0004, - STATE = 0x0008, - INFO = 0x0010, - GUID = 0x0020, - - /// - /// Vista only. - /// - REALTIME = 0x0040, - /// - /// Vista only. - /// - SHOWTIP = 0x0080, - - XP_MASK = MESSAGE | ICON | STATE | INFO | GUID, - VISTA_MASK = XP_MASK | REALTIME | SHOWTIP, - } - - /// - /// Shell_NotifyIcon info flags. NIIF_* - /// - internal enum NIIF - { - NONE = 0x00000000, - INFO = 0x00000001, - WARNING = 0x00000002, - ERROR = 0x00000003, - /// XP SP2 and later. - USER = 0x00000004, - /// XP and later. - NOSOUND = 0x00000010, - /// Vista and later. - LARGE_ICON = 0x00000020, - /// Windows 7 and later - NIIF_RESPECT_QUIET_TIME = 0x00000080, - /// XP and later. Native version called NIIF_ICON_MASK. - XP_ICON_MASK = 0x0000000F, - } - - /// - /// AC_* - /// - internal enum AC : byte - { - SRC_OVER = 0, - SRC_ALPHA = 1, - } - - internal enum ULW - { - ALPHA = 2, - COLORKEY = 1, - OPAQUE = 4, - } - - internal enum WVR - { - ALIGNTOP = 0x0010, - ALIGNLEFT = 0x0020, - ALIGNBOTTOM = 0x0040, - ALIGNRIGHT = 0x0080, - HREDRAW = 0x0100, - VREDRAW = 0x0200, - VALIDRECTS = 0x0400, - REDRAW = HREDRAW | VREDRAW, - } - - internal enum DSH - { - ALLOWDROPDESCRIPTIONTEXT = 1, - } - - #endregion - - #region SafeHandles - - internal sealed class SafeFindHandle : SafeHandleZeroOrMinusOneIsInvalid - { - [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] - private SafeFindHandle() : base(true) { } - - protected override bool ReleaseHandle() - { - return NativeMethods.FindClose(handle); - } - } - - internal sealed class SafeDC : SafeHandleZeroOrMinusOneIsInvalid - { - private static class NativeMethods - { - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll")] - public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll")] - public static extern SafeDC GetDC(IntPtr hwnd); - - // Weird legacy function, documentation is unclear about how to use it... - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdi32.dll", CharSet = CharSet.Unicode)] - public static extern SafeDC CreateDC([MarshalAs(UnmanagedType.LPWStr)] string lpszDriver, [MarshalAs(UnmanagedType.LPWStr)] string lpszDevice, IntPtr lpszOutput, IntPtr lpInitData); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern SafeDC CreateCompatibleDC(IntPtr hdc); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdi32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool DeleteDC(IntPtr hdc); - } - - private IntPtr? _hwnd; - private bool _created; - - public IntPtr Hwnd - { - set - { - Assert.NullableIsNull(_hwnd); - _hwnd = value; - } - } - - private SafeDC() : base(true) { } - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - protected override bool ReleaseHandle() - { - if (_created) - { - return NativeMethods.DeleteDC(handle); - } - - if (!_hwnd.HasValue || _hwnd.Value == IntPtr.Zero) - { - return true; - } - - return NativeMethods.ReleaseDC(_hwnd.Value, handle) == 1; - } - - [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes"), SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static SafeDC CreateDC(string deviceName) - { - SafeDC dc = null; - try - { - // Should this really be on the driver parameter? - dc = NativeMethods.CreateDC(deviceName, null, IntPtr.Zero, IntPtr.Zero); - } - finally - { - if (dc != null) - { - dc._created = true; - } - } - - if (dc.IsInvalid) - { - dc.Dispose(); - throw new SystemException("Unable to create a device context from the specified device information."); - } - - return dc; - } - - [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes"), SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static SafeDC CreateCompatibleDC(SafeDC hdc) - { - SafeDC dc = null; - try - { - IntPtr hPtr = IntPtr.Zero; - if (hdc != null) - { - hPtr = hdc.handle; - } - dc = NativeMethods.CreateCompatibleDC(hPtr); - if (dc == null) - { - HRESULT.ThrowLastError(); - } - } - finally - { - if (dc != null) - { - dc._created = true; - } - } - - if (dc.IsInvalid) - { - dc.Dispose(); - throw new SystemException("Unable to create a device context from the specified device information."); - } - - return dc; - } - - public static SafeDC GetDC(IntPtr hwnd) - { - SafeDC dc = null; - try - { - dc = NativeMethods.GetDC(hwnd); - } - finally - { - if (dc != null) - { - dc.Hwnd = hwnd; - } - } - - if (dc.IsInvalid) - { - // GetDC does not set the last error... - HRESULT.E_FAIL.ThrowIfFailed(); - } - - return dc; - } - - public static SafeDC GetDesktop() - { - return GetDC(IntPtr.Zero); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static SafeDC WrapDC(IntPtr hdc) - { - // This won't actually get released by the class, but it allows an IntPtr to be converted for signatures. - return new SafeDC - { - handle = hdc, - _created = false, - _hwnd = IntPtr.Zero, - }; - } - } - - internal sealed class SafeHBITMAP : SafeHandleZeroOrMinusOneIsInvalid - { - private SafeHBITMAP() : base(true) { } - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - protected override bool ReleaseHandle() - { - return NativeMethods.DeleteObject(handle); - } - } - - internal sealed class SafeGdiplusStartupToken : SafeHandleZeroOrMinusOneIsInvalid - { - private SafeGdiplusStartupToken() : base(true) { } - - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - protected override bool ReleaseHandle() - { - Status s = NativeMethods.GdiplusShutdown(this.handle); - return s == Status.Ok; - } - - [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")] - public static SafeGdiplusStartupToken Startup() - { - SafeGdiplusStartupToken safeHandle = new SafeGdiplusStartupToken(); - IntPtr unsafeHandle; - StartupOutput output; - Status s = NativeMethods.GdiplusStartup(out unsafeHandle, new StartupInput(), out output); - if (s == Status.Ok) - { - safeHandle.handle = unsafeHandle; - return safeHandle; - } - safeHandle.Dispose(); - throw new Exception("Unable to initialize GDI+"); - } - } - - internal sealed class SafeConnectionPointCookie : SafeHandleZeroOrMinusOneIsInvalid - { - private IConnectionPoint _cp; - // handle holds the cookie value. - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "IConnectionPoint")] - public SafeConnectionPointCookie(IConnectionPointContainer target, object sink, Guid eventId) - : base(true) - { - Verify.IsNotNull(target, "target"); - Verify.IsNotNull(sink, "sink"); - Verify.IsNotDefault(eventId, "eventId"); - - handle = IntPtr.Zero; - - IConnectionPoint cp = null; - try - { - int dwCookie; - target.FindConnectionPoint(ref eventId, out cp); - cp.Advise(sink, out dwCookie); - if (dwCookie == 0) - { - throw new InvalidOperationException("IConnectionPoint::Advise returned an invalid cookie."); - } - handle = new IntPtr(dwCookie); - _cp = cp; - cp = null; - } - finally - { - Utility.SafeRelease(ref cp); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public void Disconnect() - { - ReleaseHandle(); - } - - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] - protected override bool ReleaseHandle() - { - try - { - if (!this.IsInvalid) - { - int dwCookie = handle.ToInt32(); - handle = IntPtr.Zero; - - Assert.IsNotNull(_cp); - try - { - _cp.Unadvise(dwCookie); - } - finally - { - Utility.SafeRelease(ref _cp); - } - } - return true; - } - catch - { - return false; - } - } - } - - #endregion - - #region Native Types - - [StructLayout(LayoutKind.Sequential)] - internal struct BLENDFUNCTION - { - // Must be AC_SRC_OVER - public AC BlendOp; - // Must be 0. - public byte BlendFlags; - // Alpha transparency between 0 (transparent) - 255 (opaque) - public byte SourceConstantAlpha; - // Must be AC_SRC_ALPHA - public AC AlphaFormat; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct HIGHCONTRAST - { - public int cbSize; - public HCF dwFlags; - //[MarshalAs(UnmanagedType.LPWStr, SizeConst=80)] - //public String lpszDefaultScheme; - public IntPtr lpszDefaultScheme; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct RGBQUAD - { - public byte rgbBlue; - public byte rgbGreen; - public byte rgbRed; - public byte rgbReserved; - } - - [StructLayout(LayoutKind.Sequential, Pack=2)] - internal struct BITMAPINFOHEADER - { - public int biSize; - public int biWidth; - public int biHeight; - public short biPlanes; - public short biBitCount; - public BI biCompression; - public int biSizeImage; - public int biXPelsPerMeter; - public int biYPelsPerMeter; - public int biClrUsed; - public int biClrImportant; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct BITMAPINFO - { - public BITMAPINFOHEADER bmiHeader; - public RGBQUAD bmiColors; - } - - // Win7 only. - [StructLayout(LayoutKind.Sequential)] - internal struct CHANGEFILTERSTRUCT - { - public uint cbSize; - public MSGFLTINFO ExtStatus; - } - - [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] - internal struct CREATESTRUCT - { - public IntPtr lpCreateParams; - public IntPtr hInstance; - public IntPtr hMenu; - public IntPtr hwndParent; - public int cy; - public int cx; - public int y; - public int x; - public WS style; - [MarshalAs(UnmanagedType.LPWStr)] public string lpszName; - [MarshalAs(UnmanagedType.LPWStr)] public string lpszClass; - public WS_EX dwExStyle; - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] - internal struct SHFILEOPSTRUCT - { - public IntPtr hwnd; - [MarshalAs(UnmanagedType.U4)] - public FO wFunc; - // double-null terminated arrays of LPWSTRS - public string pFrom; - public string pTo; - [MarshalAs(UnmanagedType.U2)] - public FOF fFlags; - [MarshalAs(UnmanagedType.Bool)] - public int fAnyOperationsAborted; - public IntPtr hNameMappings; - public string lpszProgressTitle; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct TITLEBARINFO - { - public int cbSize; - public RECT rcTitleBar; - public STATE_SYSTEM rgstate_TitleBar; - public STATE_SYSTEM rgstate_Reserved; - public STATE_SYSTEM rgstate_MinimizeButton; - public STATE_SYSTEM rgstate_MaximizeButton; - public STATE_SYSTEM rgstate_HelpButton; - public STATE_SYSTEM rgstate_CloseButton; - } - - // New to Vista. - [StructLayout(LayoutKind.Sequential)] - internal struct TITLEBARINFOEX - { - public int cbSize; - public RECT rcTitleBar; - public STATE_SYSTEM rgstate_TitleBar; - public STATE_SYSTEM rgstate_Reserved; - public STATE_SYSTEM rgstate_MinimizeButton; - public STATE_SYSTEM rgstate_MaximizeButton; - public STATE_SYSTEM rgstate_HelpButton; - public STATE_SYSTEM rgstate_CloseButton; - public RECT rgrect_TitleBar; - public RECT rgrect_Reserved; - public RECT rgrect_MinimizeButton; - public RECT rgrect_MaximizeButton; - public RECT rgrect_HelpButton; - public RECT rgrect_CloseButton; - } - - [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] - [StructLayout(LayoutKind.Sequential)] - internal class NOTIFYICONDATA - { - public int cbSize; - public IntPtr hWnd; - public int uID; - public NIF uFlags; - public int uCallbackMessage; - public IntPtr hIcon; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] - public char[] szTip = new char[128]; - /// - /// The state of the icon. There are two flags that can be set independently. - /// NIS_HIDDEN = 1. The icon is hidden. - /// NIS_SHAREDICON = 2. The icon is shared. - /// - public uint dwState; - public uint dwStateMask; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] - public char[] szInfo = new char[256]; - // Prior to Vista this was a union of uTimeout and uVersion. As of Vista, uTimeout has been deprecated. - public uint uVersion; // Used with Shell_NotifyIcon flag NIM_SETVERSION. - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] - public char[] szInfoTitle = new char[64]; - public uint dwInfoFlags; - public Guid guidItem; - // Vista only - IntPtr hBalloonIcon; - } - - [StructLayout(LayoutKind.Explicit)] - internal class PROPVARIANT : IDisposable - { - private static class NativeMethods - { - [DllImport("ole32.dll")] - internal static extern HRESULT PropVariantClear(PROPVARIANT pvar); - } - - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - [FieldOffset(0)] - private ushort vt; - [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - [FieldOffset(8)] - private IntPtr pointerVal; - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - [FieldOffset(8)] - private byte byteVal; - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - [FieldOffset(8)] - private long longVal; - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] - [FieldOffset(8)] - private short boolVal; - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public VarEnum VarType - { - get { return (VarEnum)vt; } - } - - // Right now only using this for strings. - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] - public string GetValue() - { - if (vt == (ushort)VarEnum.VT_LPWSTR) - { - return Marshal.PtrToStringUni(pointerVal); - } - - return null; - } - - public void SetValue(bool f) - { - Clear(); - vt = (ushort)VarEnum.VT_BOOL; - boolVal = (short)(f ? -1 : 0); - } - - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] - public void SetValue(string val) - { - Clear(); - vt = (ushort)VarEnum.VT_LPWSTR; - pointerVal = Marshal.StringToCoTaskMemUni(val); - } - - public void Clear() - { - HRESULT hr = NativeMethods.PropVariantClear(this); - Assert.IsTrue(hr.Succeeded); - } - - #region IDisposable Pattern - - public void Dispose() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - ~PROPVARIANT() - { - Dispose(false); - } - - [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disposing")] - private void Dispose(bool disposing) - { - Clear(); - } - - #endregion - } - - [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] - [StructLayout(LayoutKind.Sequential, Pack = 4)] - internal class SHARDAPPIDINFO - { - [MarshalAs(UnmanagedType.Interface)] - object psi; // The namespace location of the the item that should be added to the recent docs folder. - [MarshalAs(UnmanagedType.LPWStr)] - string pszAppID; // The id of the application that should be associated with this recent doc. - } - - [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] - [StructLayout(LayoutKind.Sequential, Pack = 4)] - internal class SHARDAPPIDINFOIDLIST - { - /// The idlist for the shell item that should be added to the recent docs folder. - IntPtr pidl; - /// The id of the application that should be associated with this recent doc. - [MarshalAs(UnmanagedType.LPWStr)] - string pszAppID; - } - - [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] - [StructLayout(LayoutKind.Sequential, Pack = 4)] - internal class SHARDAPPIDINFOLINK - { - IntPtr psl; // An IShellLink instance that when launched opens a recently used item in the specified - // application. This link is not added to the recent docs folder, but will be added to the - // specified application's destination list. - [MarshalAs(UnmanagedType.LPWStr)] - string pszAppID; // The id of the application that should be associated with this recent doc. - } - - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - internal struct LOGFONT - { - public int lfHeight; - public int lfWidth; - public int lfEscapement; - public int lfOrientation; - public int lfWeight; - public byte lfItalic; - public byte lfUnderline; - public byte lfStrikeOut; - public byte lfCharSet; - public byte lfOutPrecision; - public byte lfClipPrecision; - public byte lfQuality; - public byte lfPitchAndFamily; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] - public string lfFaceName; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct MINMAXINFO - { - public POINT ptReserved; - public POINT ptMaxSize; - public POINT ptMaxPosition; - public POINT ptMinTrackSize; - public POINT ptMaxTrackSize; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NONCLIENTMETRICS - { - public int cbSize; - public int iBorderWidth; - public int iScrollWidth; - public int iScrollHeight; - public int iCaptionWidth; - public int iCaptionHeight; - public LOGFONT lfCaptionFont; - public int iSmCaptionWidth; - public int iSmCaptionHeight; - public LOGFONT lfSmCaptionFont; - public int iMenuWidth; - public int iMenuHeight; - public LOGFONT lfMenuFont; - public LOGFONT lfStatusFont; - public LOGFONT lfMessageFont; - // Vista only - public int iPaddedBorderWidth; - - public static NONCLIENTMETRICS VistaMetricsStruct - { - get - { - var ncm = new NONCLIENTMETRICS(); - ncm.cbSize = Marshal.SizeOf(typeof(NONCLIENTMETRICS)); - return ncm; - } - } - - public static NONCLIENTMETRICS XPMetricsStruct - { - get - { - var ncm = new NONCLIENTMETRICS(); - // Account for the missing iPaddedBorderWidth - ncm.cbSize = Marshal.SizeOf(typeof(NONCLIENTMETRICS)) - sizeof(int); - return ncm; - } - } - } - - /// Defines options that are used to set window visual style attributes. - [StructLayout(LayoutKind.Explicit)] - internal struct WTA_OPTIONS - { - // public static readonly uint Size = (uint)Marshal.SizeOf(typeof(WTA_OPTIONS)); - public const uint Size = 8; - - /// - /// A combination of flags that modify window visual style attributes. - /// Can be a combination of the WTNCA constants. - /// - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Used by native code.")] - [FieldOffset(0)] - public WTNCA dwFlags; - - /// - /// A bitmask that describes how the values specified in dwFlags should be applied. - /// If the bit corresponding to a value in dwFlags is 0, that flag will be removed. - /// If the bit is 1, the flag will be added. - /// - [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Used by native code.")] - [FieldOffset(4)] - public WTNCA dwMask; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct MARGINS - { - /// Width of left border that retains its size. - public int cxLeftWidth; - /// Width of right border that retains its size. - public int cxRightWidth; - /// Height of top border that retains its size. - public int cyTopHeight; - /// Height of bottom border that retains its size. - public int cyBottomHeight; - }; - - [StructLayout(LayoutKind.Sequential)] - internal class MONITORINFO - { - public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); - public RECT rcMonitor; - public RECT rcWork; - public int dwFlags; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct POINT - { - public int x; - public int y; - } - - [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] - [StructLayout(LayoutKind.Sequential)] - internal class RefPOINT - { - public int x; - public int y; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct RECT - { - private int _left; - private int _top; - private int _right; - private int _bottom; - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public void Offset(int dx, int dy) - { - _left += dx; - _top += dy; - _right += dx; - _bottom += dy; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public int Left - { - get { return _left; } - set { _left = value; } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public int Right - { - get { return _right; } - set { _right = value; } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public int Top - { - get { return _top; } - set { _top = value; } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public int Bottom - { - get { return _bottom; } - set { _bottom = value; } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public int Width - { - get { return _right - _left; } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public int Height - { - get { return _bottom - _top; } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public POINT Position - { - get { return new POINT { x = _left, y = _top }; } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public SIZE Size - { - get { return new SIZE { cx = Width, cy = Height }; } - } - - public static RECT Union(RECT rect1, RECT rect2) - { - return new RECT - { - Left = Math.Min(rect1.Left, rect2.Left), - Top = Math.Min(rect1.Top, rect2.Top), - Right = Math.Max(rect1.Right, rect2.Right), - Bottom = Math.Max(rect1.Bottom, rect2.Bottom), - }; - } - - public override bool Equals(object obj) - { - try - { - var rc = (RECT)obj; - return rc._bottom == _bottom - && rc._left == _left - && rc._right == _right - && rc._top == _top; - } - catch (InvalidCastException) - { - return false; - } - } - - public override int GetHashCode() - { - return (_left << 16 | Utility.LOWORD(_right)) ^ (_top << 16 | Utility.LOWORD(_bottom)); - } - } - - [StructLayout(LayoutKind.Sequential)] - internal class RefRECT - { - private int _left; - private int _top; - private int _right; - private int _bottom; - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public RefRECT(int left, int top, int right, int bottom) - { - _left = left; - _top = top; - _right = right; - _bottom = bottom; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public int Width - { - get { return _right - _left; } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public int Height - { - get { return _bottom - _top; } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public int Left - { - get { return _left; } - set { _left = value; } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public int Right - { - get { return _right; } - set { _right = value; } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public int Top - { - get { return _top; } - set { _top = value; } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public int Bottom - { - get { return _bottom; } - set { _bottom = value; } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public void Offset(int dx, int dy) - { - _left += dx; - _top += dy; - _right += dx; - _bottom += dy; - } - } - - [StructLayout(LayoutKind.Sequential)] - internal struct SIZE - { - public int cx; - public int cy; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct StartupOutput - { - public IntPtr hook; - public IntPtr unhook; - } - - [StructLayout(LayoutKind.Sequential)] - internal class StartupInput - { - public int GdiplusVersion = 1; - public IntPtr DebugEventCallback; - public bool SuppressBackgroundThread; - public bool SuppressExternalCodecs; - } - - [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - [BestFitMapping(false)] - internal class WIN32_FIND_DATAW - { - public FileAttributes dwFileAttributes; - public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime; - public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime; - public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime; - public int nFileSizeHigh; - public int nFileSizeLow; - public int dwReserved0; - public int dwReserved1; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public string cFileName; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] - public string cAlternateFileName; - } - - [StructLayout(LayoutKind.Sequential)] - internal class WINDOWPLACEMENT - { - public int length = Marshal.SizeOf(typeof(WINDOWPLACEMENT)); - public int flags; - public SW showCmd; - public POINT ptMinPosition; - public POINT ptMaxPosition; - public RECT rcNormalPosition; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct WINDOWPOS - { - public IntPtr hwnd; - public IntPtr hwndInsertAfter; - public int x; - public int y; - public int cx; - public int cy; - public int flags; - } - - [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] - internal struct WNDCLASSEX - { - public int cbSize; - public CS style; - public WndProc lpfnWndProc; - public int cbClsExtra; - public int cbWndExtra; - public IntPtr hInstance; - public IntPtr hIcon; - public IntPtr hCursor; - public IntPtr hbrBackground; - [MarshalAs(UnmanagedType.LPWStr)] - public string lpszMenuName; - [MarshalAs(UnmanagedType.LPWStr)] - public string lpszClassName; - public IntPtr hIconSm; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct MOUSEINPUT - { - public int dx; - public int dy; - public int mouseData; - public int dwFlags; - public int time; - public IntPtr dwExtraInfo; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct INPUT - { - public uint type; - public MOUSEINPUT mi; - }; - - [StructLayout(LayoutKind.Sequential)] - internal struct UNSIGNED_RATIO - { - public uint uiNumerator; - public uint uiDenominator; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct DWM_TIMING_INFO - { - public int cbSize; - public UNSIGNED_RATIO rateRefresh; - public ulong qpcRefreshPeriod; - public UNSIGNED_RATIO rateCompose; - public ulong qpcVBlank; - public ulong cRefresh; - public uint cDXRefresh; - public ulong qpcCompose; - public ulong cFrame; - public uint cDXPresent; - public ulong cRefreshFrame; - public ulong cFrameSubmitted; - public uint cDXPresentSubmitted; - public ulong cFrameConfirmed; - public uint cDXPresentConfirmed; - public ulong cRefreshConfirmed; - public uint cDXRefreshConfirmed; - public ulong cFramesLate; - public uint cFramesOutstanding; - public ulong cFrameDisplayed; - public ulong qpcFrameDisplayed; - public ulong cRefreshFrameDisplayed; - public ulong cFrameComplete; - public ulong qpcFrameComplete; - public ulong cFramePending; - public ulong qpcFramePending; - public ulong cFramesDisplayed; - public ulong cFramesComplete; - public ulong cFramesPending; - public ulong cFramesAvailable; - public ulong cFramesDropped; - public ulong cFramesMissed; - public ulong cRefreshNextDisplayed; - public ulong cRefreshNextPresented; - public ulong cRefreshesDisplayed; - public ulong cRefreshesPresented; - public ulong cRefreshStarted; - public ulong cPixelsReceived; - public ulong cPixelsDrawn; - public ulong cBuffersEmpty; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct SHDRAGIMAGE - { - public SIZE sizeDragImage; - public POINT ptOffset; - public IntPtr hbmpDragImage; - public int crColorKey; - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Size = 1044)] - internal struct DROPDESCRIPTION - { - public DROPIMAGETYPE type; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public string szMessage; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public string szInsert; - } - - #endregion - - #region Interfaces - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.ServiceProvider) - ] - internal interface IServiceProvider - { - [return: MarshalAs(UnmanagedType.IUnknown)] - object QueryService(ref Guid guidService, ref Guid riid); - } - - [ - ComImport, - Guid(IID.DragSourceHelper), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown) - ] - internal interface IDragSourceHelper - { - void InitializeFromBitmap([In] ref SHDRAGIMAGE pshdi, [In] IDataObject pDataObject); - void InitializeFromWindow(IntPtr hwnd, [In] ref POINT ppt, [In] IDataObject pDataObject); - } - - [ - ComImport, - Guid(IID.DragSourceHelper2), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown) - ] - internal interface IDragSourceHelper2 : IDragSourceHelper - { - #region IDragSourceHelper redeclaration - new void InitializeFromBitmap([In] ref SHDRAGIMAGE pshdi, [In] IDataObject pDataObject); - new void InitializeFromWindow(IntPtr hwnd, [In] ref POINT ppt, [In] IDataObject pDataObject); - #endregion - - void SetFlags(DSH dwFlags); - } - - [ - ComImport, - Guid(IID.DropTargetHelper), - InterfaceType(ComInterfaceType.InterfaceIsIUnknown) - ] - internal interface IDropTargetHelper - { - void DragEnter(IntPtr hwndTarget, IDataObject pDataObject, ref POINT ppt, int effect); - void DragLeave(); - void DragOver(ref POINT ppt, int effect); - void Drop(IDataObject dataObject, ref POINT ppt, int effect); - void Show([MarshalAs(UnmanagedType.Bool)] bool fShow); - } - - #endregion - - /// Delegate declaration that matches native WndProc signatures. - internal delegate IntPtr WndProc(IntPtr hwnd, WM uMsg, IntPtr wParam, IntPtr lParam); - - /// Delegate declaration that matches managed WndProc signatures. - internal delegate IntPtr MessageHandler(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled); - - // Some native methods are shimmed through public versions that handle converting failures into thrown exceptions. - internal static class NativeMethods - { - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "AdjustWindowRectEx", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _AdjustWindowRectEx(ref RECT lpRect, WS dwStyle, [MarshalAs(UnmanagedType.Bool)] bool bMenu, WS_EX dwExStyle); - - public static RECT AdjustWindowRectEx(RECT lpRect, WS dwStyle, bool bMenu, WS_EX dwExStyle) - { - // Native version modifies the parameter in place. - if (!_AdjustWindowRectEx(ref lpRect, dwStyle, bMenu, dwExStyle)) - { - HRESULT.ThrowLastError(); - } - - return lpRect; - } - - [DllImport("user32.dll", EntryPoint="AllowSetForegroundWindow", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _AllowSetForegroundWindow(int dwProcessId); - - public static void AllowSetForegroundWindow() - { - int ASFW_ANY = -1; - AllowSetForegroundWindow(ASFW_ANY); - } - - public static void AllowSetForegroundWindow(int dwProcessId) - { - if (!_AllowSetForegroundWindow(dwProcessId)) - { - HRESULT.ThrowLastError(); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "ChangeWindowMessageFilter", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _ChangeWindowMessageFilter(WM message, MSGFLT dwFlag); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "ChangeWindowMessageFilterEx", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _ChangeWindowMessageFilterEx(IntPtr hwnd, WM message, MSGFLT action, [In, Out, Optional] ref CHANGEFILTERSTRUCT pChangeFilterStruct); - - // Note that processes at or below SECURITY_MANDATORY_LOW_RID are not allowed to change the message filter. - // If those processes call this function, it will fail and generate the extended error code, ERROR_ACCESS_DENIED. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static HRESULT ChangeWindowMessageFilterEx(IntPtr hwnd, WM message, MSGFLT action, out MSGFLTINFO filterInfo) - { - filterInfo = MSGFLTINFO.NONE; - - bool ret; - - // This origins of this API were added for Vista. The Ex version was added for Windows 7. - // If we're not on either, then this message filter isolation doesn't exist. - if (!Utility.IsOSVistaOrNewer) - { - return HRESULT.S_FALSE; - } - - // If we're on Vista rather than Win7 then we can't use the Ex version of this function. - // The Ex version is preferred if possible because this results in process-wide modifications of the filter - // and is deprecated as of Win7. - if (!Utility.IsOSWindows7OrNewer) - { - // Note that the Win7 MSGFLT_ALLOW/DISALLOW enum values map to the Vista MSGFLT_ADD/REMOVE - ret = _ChangeWindowMessageFilter(message, action); - if (!ret) - { - return (HRESULT)Win32Error.GetLastError(); - } - return HRESULT.S_OK; - } - - var filterstruct = new CHANGEFILTERSTRUCT { cbSize = (uint)Marshal.SizeOf(typeof(CHANGEFILTERSTRUCT)) }; - ret = _ChangeWindowMessageFilterEx(hwnd, message, action, ref filterstruct); - if (!ret) - { - return (HRESULT)Win32Error.GetLastError(); - } - - filterInfo = filterstruct.ExtStatus; - return HRESULT.S_OK; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdi32.dll")] - public static extern CombineRgnResult CombineRgn(IntPtr hrgnDest, IntPtr hrgnSrc1, IntPtr hrgnSrc2, RGN fnCombineMode); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("shell32.dll", EntryPoint = "CommandLineToArgvW", CharSet = CharSet.Unicode)] - private static extern IntPtr _CommandLineToArgvW([MarshalAs(UnmanagedType.LPWStr)] string cmdLine, out int numArgs); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static string[] CommandLineToArgvW(string cmdLine) - { - IntPtr argv = IntPtr.Zero; - try - { - int numArgs = 0; - - argv = _CommandLineToArgvW(cmdLine, out numArgs); - if (argv == IntPtr.Zero) - { - throw new Win32Exception(); - } - var result = new string[numArgs]; - - for (int i = 0; i < numArgs; i++) - { - IntPtr currArg = Marshal.ReadIntPtr(argv, i * Marshal.SizeOf(typeof(IntPtr))); - result[i] = Marshal.PtrToStringUni(currArg); - } - - return result; - } - finally - { - - IntPtr p = _LocalFree(argv); - // Otherwise LocalFree failed. - Assert.AreEqual(IntPtr.Zero, p); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdi32.dll", EntryPoint = "CreateDIBSection", SetLastError = true)] - private static extern SafeHBITMAP _CreateDIBSection(SafeDC hdc, [In] ref BITMAPINFO bitmapInfo, int iUsage, [Out] out IntPtr ppvBits, IntPtr hSection, int dwOffset); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdi32.dll", EntryPoint = "CreateDIBSection", SetLastError = true)] - private static extern SafeHBITMAP _CreateDIBSectionIntPtr(IntPtr hdc, [In] ref BITMAPINFO bitmapInfo, int iUsage, [Out] out IntPtr ppvBits, IntPtr hSection, int dwOffset); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static SafeHBITMAP CreateDIBSection(SafeDC hdc, ref BITMAPINFO bitmapInfo, out IntPtr ppvBits, IntPtr hSection, int dwOffset) - { - const int DIB_RGB_COLORS = 0; - SafeHBITMAP hBitmap = null; - if (hdc == null) - { - hBitmap = _CreateDIBSectionIntPtr(IntPtr.Zero, ref bitmapInfo, DIB_RGB_COLORS, out ppvBits, hSection, dwOffset); - } - else - { - hBitmap = _CreateDIBSection(hdc, ref bitmapInfo, DIB_RGB_COLORS, out ppvBits, hSection, dwOffset); - } - - if (hBitmap.IsInvalid) - { - HRESULT.ThrowLastError(); - } - - return hBitmap; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdi32.dll", EntryPoint = "CreateRoundRectRgn", SetLastError = true)] - private static extern IntPtr _CreateRoundRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nWidthEllipse, int nHeightEllipse); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static IntPtr CreateRoundRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nWidthEllipse, int nHeightEllipse) - { - IntPtr ret = _CreateRoundRectRgn(nLeftRect, nTopRect, nRightRect, nBottomRect, nWidthEllipse, nHeightEllipse); - if (IntPtr.Zero == ret) - { - throw new Win32Exception(); - } - return ret; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdi32.dll", EntryPoint = "CreateRectRgn", SetLastError = true)] - private static extern IntPtr _CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect) - { - IntPtr ret = _CreateRectRgn(nLeftRect, nTopRect, nRightRect, nBottomRect); - if (IntPtr.Zero == ret) - { - throw new Win32Exception(); - } - return ret; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdi32.dll", EntryPoint = "CreateRectRgnIndirect", SetLastError = true)] - private static extern IntPtr _CreateRectRgnIndirect([In] ref RECT lprc); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static IntPtr CreateRectRgnIndirect(RECT lprc) - { - IntPtr ret = _CreateRectRgnIndirect(ref lprc); - if (IntPtr.Zero == ret) - { - throw new Win32Exception(); - } - return ret; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdi32.dll")] - public static extern IntPtr CreateSolidBrush(int crColor); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "CreateWindowExW")] - private static extern IntPtr _CreateWindowEx( - WS_EX dwExStyle, - [MarshalAs(UnmanagedType.LPWStr)] string lpClassName, - [MarshalAs(UnmanagedType.LPWStr)] string lpWindowName, - WS dwStyle, - int x, - int y, - int nWidth, - int nHeight, - IntPtr hWndParent, - IntPtr hMenu, - IntPtr hInstance, - IntPtr lpParam); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static IntPtr CreateWindowEx( - WS_EX dwExStyle, - string lpClassName, - string lpWindowName, - WS dwStyle, - int x, - int y, - int nWidth, - int nHeight, - IntPtr hWndParent, - IntPtr hMenu, - IntPtr hInstance, - IntPtr lpParam) - { - IntPtr ret = _CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); - if (IntPtr.Zero == ret) - { - HRESULT.ThrowLastError(); - } - - return ret; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "DefWindowProcW")] - public static extern IntPtr DefWindowProc(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdi32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool DeleteObject(IntPtr hObject); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool DestroyIcon(IntPtr handle); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool DestroyWindow(IntPtr hwnd); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWindow(IntPtr hwnd); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("dwmapi.dll", PreserveSig = false)] - public static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS pMarInset); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("dwmapi.dll", EntryPoint = "DwmGetColorizationColor", PreserveSig = true)] - private static extern HRESULT _DwmGetColorizationColor(out uint pcrColorization, [Out, MarshalAs(UnmanagedType.Bool)] out bool pfOpaqueBlend); - - public static bool DwmGetColorizationColor(out uint pcrColorization, out bool pfOpaqueBlend) - { - // Make this call safe to make on downlevel OSes... - if (Utility.IsOSVistaOrNewer && IsThemeActive()) - { - HRESULT hr = _DwmGetColorizationColor(out pcrColorization, out pfOpaqueBlend); - if (hr.Succeeded) - { - return true; - } - } - - // Default values. If for some reason the native DWM API fails it's never enough of a reason - // to bring down the app. Empirically it still sometimes returns errors even when the theme service is on. - // We'll still use the boolean return value to allow the caller to respond if they care. - pcrColorization = 0xFF000000; - pfOpaqueBlend = true; - - return false; - } - - //#define DWM_SIT_DISPLAYFRAME 0x00000001 // Display a window frame around the provided bitmap - - [DllImport("dwmapi.dll", EntryPoint = "DwmGetCompositionTimingInfo")] - private static extern HRESULT _DwmGetCompositionTimingInfo(IntPtr hwnd, ref DWM_TIMING_INFO pTimingInfo); - - public static DWM_TIMING_INFO? DwmGetCompositionTimingInfo(IntPtr hwnd) - { - if (!Utility.IsOSVistaOrNewer) - { - // API was new to Vista. - return null; - } - - var dti = new DWM_TIMING_INFO { cbSize = Marshal.SizeOf(typeof(DWM_TIMING_INFO)) }; - HRESULT hr = _DwmGetCompositionTimingInfo(hwnd, ref dti); - if (hr == HRESULT.E_PENDING) - { - // The system isn't yet ready to respond. Return null rather than throw. - return null; - } - hr.ThrowIfFailed(); - - return dti; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("dwmapi.dll", EntryPoint = "DwmIsCompositionEnabled", PreserveSig = false)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _DwmIsCompositionEnabled(); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool DwmIsCompositionEnabled() - { - // Make this call safe to make on downlevel OSes... - if (!Utility.IsOSVistaOrNewer) - { - return false; - } - return _DwmIsCompositionEnabled(); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("dwmapi.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool DwmDefWindowProc(IntPtr hwnd, WM msg, IntPtr wParam, IntPtr lParam, out IntPtr plResult); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("dwmapi.dll", EntryPoint = "DwmSetWindowAttribute")] - private static extern void _DwmSetWindowAttribute(IntPtr hwnd, DWMWA dwAttribute, ref int pvAttribute, int cbAttribute); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void DwmSetWindowAttributeFlip3DPolicy(IntPtr hwnd, DWMFLIP3D flip3dPolicy) - { - Assert.IsTrue(Utility.IsOSVistaOrNewer); - var dwPolicy = (int)flip3dPolicy; - _DwmSetWindowAttribute(hwnd, DWMWA.FLIP3D_POLICY, ref dwPolicy, sizeof(int)); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void DwmSetWindowAttributeDisallowPeek(IntPtr hwnd, bool disallowPeek) - { - Assert.IsTrue(Utility.IsOSWindows7OrNewer); - int dwDisallow = (int)(disallowPeek ? Win32Value.TRUE : Win32Value.FALSE); - _DwmSetWindowAttribute(hwnd, DWMWA.DISALLOW_PEEK, ref dwDisallow, sizeof(int)); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "EnableMenuItem")] - private static extern int _EnableMenuItem(IntPtr hMenu, SC uIDEnableItem, MF uEnable); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static MF EnableMenuItem(IntPtr hMenu, SC uIDEnableItem, MF uEnable) - { - // Returns the previous state of the menu item, or -1 if the menu item does not exist. - int iRet = _EnableMenuItem(hMenu, uIDEnableItem, uEnable); - return (MF)iRet; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "RemoveMenu", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void RemoveMenu(IntPtr hMenu, SC uPosition, MF uFlags) - { - if (!_RemoveMenu(hMenu, (uint)uPosition, (uint)uFlags)) - { - throw new Win32Exception(); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "DrawMenuBar", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _DrawMenuBar(IntPtr hWnd); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void DrawMenuBar(IntPtr hWnd) - { - if (!_DrawMenuBar(hWnd)) - { - throw new Win32Exception(); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("kernel32.dll")] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool FindClose(IntPtr handle); - - // Not shimming this SetLastError=true function because callers want to evaluate the reason for failure. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - public static extern SafeFindHandle FindFirstFileW(string lpFileName, [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_DATAW lpFindFileData); - - // Not shimming this SetLastError=true function because callers want to evaluate the reason for failure. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("kernel32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool FindNextFileW(SafeFindHandle hndFindFile, [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_DATAW lpFindFileData); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "GetClientRect", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _GetClientRect(IntPtr hwnd, [Out] out RECT lpRect); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static RECT GetClientRect(IntPtr hwnd) - { - RECT rc; - if (!_GetClientRect(hwnd, out rc)) - { - HRESULT.ThrowLastError(); - } - return rc; - } - - [DllImport("user32.dll", EntryPoint="GetCursorPos", SetLastError=true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _GetCursorPos(out POINT lpPoint); - - public static POINT GetCursorPos() - { - POINT pt; - if (!_GetCursorPos(out pt)) - { - HRESULT.ThrowLastError(); - } - - return pt; - } - - [DllImport("uxtheme.dll", EntryPoint = "GetCurrentThemeName", CharSet = CharSet.Unicode)] - private static extern HRESULT _GetCurrentThemeName( - StringBuilder pszThemeFileName, - int dwMaxNameChars, - StringBuilder pszColorBuff, - int cchMaxColorChars, - StringBuilder pszSizeBuff, - int cchMaxSizeChars); - - public static void GetCurrentThemeName(out string themeFileName, out string color, out string size) - { - // Not expecting strings longer than MAX_PATH. We will return the error - var fileNameBuilder = new StringBuilder((int)Win32Value.MAX_PATH); - var colorBuilder = new StringBuilder((int)Win32Value.MAX_PATH); - var sizeBuilder = new StringBuilder((int)Win32Value.MAX_PATH); - - // This will throw if the theme service is not active (e.g. not UxTheme!IsThemeActive). - _GetCurrentThemeName(fileNameBuilder, fileNameBuilder.Capacity, - colorBuilder, colorBuilder.Capacity, - sizeBuilder, sizeBuilder.Capacity) - .ThrowIfFailed(); - - themeFileName = fileNameBuilder.ToString(); - color = colorBuilder.ToString(); - size = sizeBuilder.ToString(); - } - - [DllImport("uxtheme.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsThemeActive(); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [Obsolete("Use SafeDC.GetDC instead.", true)] - public static void GetDC() { } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdi32.dll")] - public static extern int GetDeviceCaps(SafeDC hdc, DeviceCap nIndex); - - [DllImport("kernel32.dll", EntryPoint="GetModuleFileName", CharSet=CharSet.Unicode, SetLastError=true)] - private static extern int _GetModuleFileName(IntPtr hModule, StringBuilder lpFilename, int nSize); - - public static string GetModuleFileName(IntPtr hModule) - { - var buffer = new StringBuilder((int)Win32Value.MAX_PATH); - while (true) - { - int size = _GetModuleFileName(hModule, buffer, buffer.Capacity); - if (size == 0) - { - HRESULT.ThrowLastError(); - } - - // GetModuleFileName returns nSize when it's truncated but does NOT set the last error. - // MSDN documentation says this has changed in Windows 2000+. - if (size == buffer.Capacity) - { - // Enlarge the buffer and try again. - buffer.EnsureCapacity(buffer.Capacity * 2); - continue; - } - - return buffer.ToString(); - } - } - - [DllImport("kernel32.dll", EntryPoint = "GetModuleHandleW", CharSet = CharSet.Unicode, SetLastError = true)] - private static extern IntPtr _GetModuleHandle([MarshalAs(UnmanagedType.LPWStr)] string lpModuleName); - - public static IntPtr GetModuleHandle(string lpModuleName) - { - IntPtr retPtr = _GetModuleHandle(lpModuleName); - if (retPtr == IntPtr.Zero) - { - HRESULT.ThrowLastError(); - } - return retPtr; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "GetMonitorInfo", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _GetMonitorInfo(IntPtr hMonitor, [In, Out] MONITORINFO lpmi); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static MONITORINFO GetMonitorInfo(IntPtr hMonitor) - { - var mi = new MONITORINFO(); - if (!_GetMonitorInfo(hMonitor, mi)) - { - throw new Win32Exception(); - } - return mi; - } - - [DllImport("gdi32.dll", EntryPoint = "GetStockObject", SetLastError = true)] - private static extern IntPtr _GetStockObject(StockObject fnObject); - - public static IntPtr GetStockObject(StockObject fnObject) - { - IntPtr retPtr = _GetStockObject(fnObject); - if (retPtr == null) - { - HRESULT.ThrowLastError(); - } - return retPtr; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll")] - public static extern IntPtr GetSystemMenu(IntPtr hWnd, [MarshalAs(UnmanagedType.Bool)] bool bRevert); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll")] - public static extern int GetSystemMetrics(SM nIndex); - - // This is aliased as a macro in 32bit Windows. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static IntPtr GetWindowLongPtr(IntPtr hwnd, GWL nIndex) - { - IntPtr ret = IntPtr.Zero; - if (8 == IntPtr.Size) - { - ret = GetWindowLongPtr64(hwnd, nIndex); - } - else - { - ret = new IntPtr(GetWindowLongPtr32(hwnd, nIndex)); - } - if (IntPtr.Zero == ret) - { - throw new Win32Exception(); - } - return ret; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint="SetProp", CharSet=CharSet.Unicode, SetLastError=true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _SetProp(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] string lpString, IntPtr hData); - - public static void SetProp(IntPtr hwnd, string lpString, IntPtr hData) - { - if (!_SetProp(hwnd, lpString, hData)) - { - HRESULT.ThrowLastError(); - } - } - - /// - /// Sets attributes to control how visual styles are applied to a specified window. - /// - /// - /// Handle to a window to apply changes to. - /// - /// - /// Value of type WINDOWTHEMEATTRIBUTETYPE that specifies the type of attribute to set. - /// The value of this parameter determines the type of data that should be passed in the pvAttribute parameter. - /// Can be the following value: - /// WTA_NONCLIENT (Specifies non-client related attributes). - /// pvAttribute must be a pointer of type WTA_OPTIONS. - /// - /// - /// A pointer that specifies attributes to set. Type is determined by the value of the eAttribute value. - /// - /// - /// Specifies the size, in bytes, of the data pointed to by pvAttribute. - /// - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("uxtheme.dll", PreserveSig = false)] - public static extern void SetWindowThemeAttribute([In] IntPtr hwnd, [In] WINDOWTHEMEATTRIBUTETYPE eAttribute, [In] ref WTA_OPTIONS pvAttribute, [In] uint cbAttribute); - - [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "GetWindowLong", SetLastError = true)] - private static extern int GetWindowLongPtr32(IntPtr hWnd, GWL nIndex); - - [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", SetLastError = true)] - private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, GWL nIndex); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool GetWindowPlacement(IntPtr hwnd, WINDOWPLACEMENT lpwndpl); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static WINDOWPLACEMENT GetWindowPlacement(IntPtr hwnd) - { - WINDOWPLACEMENT wndpl = new WINDOWPLACEMENT(); - if (GetWindowPlacement(hwnd, wndpl)) - { - return wndpl; - } - throw new Win32Exception(); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "GetWindowRect", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _GetWindowRect(IntPtr hWnd, out RECT lpRect); - - public static RECT GetWindowRect(IntPtr hwnd) - { - RECT rc; - if (!_GetWindowRect(hwnd, out rc)) - { - HRESULT.ThrowLastError(); - } - return rc; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdiplus.dll")] - public static extern Status GdipCreateBitmapFromStream(IStream stream, out IntPtr bitmap); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdiplus.dll")] - public static extern Status GdipCreateHBITMAPFromBitmap(IntPtr bitmap, out IntPtr hbmReturn, Int32 background); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdiplus.dll")] - public static extern Status GdipCreateHICONFromBitmap(IntPtr bitmap, out IntPtr hbmReturn); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdiplus.dll")] - public static extern Status GdipDisposeImage(IntPtr image); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdiplus.dll")] - public static extern Status GdipImageForceValidation(IntPtr image); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdiplus.dll")] - public static extern Status GdiplusStartup(out IntPtr token, StartupInput input, out StartupOutput output); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdiplus.dll")] - public static extern Status GdiplusShutdown(IntPtr token); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool IsWindowVisible(IntPtr hwnd); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("kernel32.dll", EntryPoint = "LocalFree", SetLastError = true)] - private static extern IntPtr _LocalFree(IntPtr hMem); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll")] - public static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "PostMessage", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _PostMessage(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void PostMessage(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam) - { - if (!_PostMessage(hWnd, Msg, wParam, lParam)) - { - throw new Win32Exception(); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")] - private static extern short _RegisterClassEx([In] ref WNDCLASSEX lpwcx); - - // Note that this will throw HRESULT_FROM_WIN32(ERROR_CLASS_ALREADY_EXISTS) on duplicate registration. - // If needed, consider adding a Try* version of this function that returns the error code since that - // may be ignorable. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static short RegisterClassEx(ref WNDCLASSEX lpwcx) - { - short ret = _RegisterClassEx(ref lpwcx); - if (ret == 0) - { - HRESULT.ThrowLastError(); - } - - return ret; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "RegisterWindowMessage", SetLastError = true, CharSet = CharSet.Unicode)] - private static extern uint _RegisterWindowMessage([MarshalAs(UnmanagedType.LPWStr)] string lpString); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static WM RegisterWindowMessage(string lpString) - { - uint iRet = _RegisterWindowMessage(lpString); - if (iRet == 0) - { - HRESULT.ThrowLastError(); - } - return (WM)iRet; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "SetActiveWindow", SetLastError = true)] - private static extern IntPtr _SetActiveWindow(IntPtr hWnd); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static IntPtr SetActiveWindow(IntPtr hwnd) - { - Verify.IsNotDefault(hwnd, "hwnd"); - IntPtr ret = _SetActiveWindow(hwnd); - if (ret == IntPtr.Zero) - { - HRESULT.ThrowLastError(); - } - - return ret; - } - - // This is aliased as a macro in 32bit Windows. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static IntPtr SetClassLongPtr(IntPtr hwnd, GCLP nIndex, IntPtr dwNewLong) - { - if (8 == IntPtr.Size) - { - return SetClassLongPtr64(hwnd, nIndex, dwNewLong); - } - return new IntPtr(SetClassLongPtr32(hwnd, nIndex, dwNewLong.ToInt32())); - } - - [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "SetClassLong", SetLastError = true)] - private static extern int SetClassLongPtr32(IntPtr hWnd, GCLP nIndex, int dwNewLong); - - [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "SetClassLongPtr", SetLastError = true)] - private static extern IntPtr SetClassLongPtr64(IntPtr hWnd, GCLP nIndex, IntPtr dwNewLong); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("kernel32.dll", SetLastError = true)] - public static extern ErrorModes SetErrorMode(ErrorModes newMode); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "SetProcessWorkingSetSize")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _SetProcessWorkingSetSize(IntPtr hProcess, IntPtr dwMinimiumWorkingSetSize, IntPtr dwMaximumWorkingSetSize); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SetProcessWorkingSetSize(IntPtr hProcess, int dwMinimumWorkingSetSize, int dwMaximumWorkingSetSize) - { - if (!_SetProcessWorkingSetSize(hProcess, new IntPtr(dwMinimumWorkingSetSize), new IntPtr(dwMaximumWorkingSetSize))) - { - throw new Win32Exception(); - } - } - - // This is aliased as a macro in 32bit Windows. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static IntPtr SetWindowLongPtr(IntPtr hwnd, GWL nIndex, IntPtr dwNewLong) - { - if (8 == IntPtr.Size) - { - return SetWindowLongPtr64(hwnd, nIndex, dwNewLong); - } - return new IntPtr(SetWindowLongPtr32(hwnd, nIndex, dwNewLong.ToInt32())); - } - - [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)] - private static extern int SetWindowLongPtr32(IntPtr hWnd, GWL nIndex, int dwNewLong); - - [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)] - private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, GWL nIndex, IntPtr dwNewLong); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "SetWindowRgn", SetLastError = true)] - private static extern int _SetWindowRgn(IntPtr hWnd, IntPtr hRgn, [MarshalAs(UnmanagedType.Bool)] bool bRedraw); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool bRedraw) - { - int err = _SetWindowRgn(hWnd, hRgn, bRedraw); - if (0 == err) - { - throw new Win32Exception(); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "SetWindowPos", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags) - { - if (!_SetWindowPos(hWnd, hWndInsertAfter, x, y, cx, cy, uFlags)) - { - throw new Win32Exception(); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("shell32.dll", SetLastError = false)] - public static extern Win32Error SHFileOperation(ref SHFILEOPSTRUCT lpFileOp); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "SystemParametersInfoW", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _SystemParametersInfo_String(SPI uiAction, int uiParam, [MarshalAs(UnmanagedType.LPWStr)] string pvParam, SPIF fWinIni); - - /// Overload of SystemParametersInfo for getting and setting NONCLIENTMETRICS. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "SystemParametersInfoW", SetLastError = true, CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _SystemParametersInfo_NONCLIENTMETRICS(SPI uiAction, int uiParam, [In, Out] ref NONCLIENTMETRICS pvParam, SPIF fWinIni); - - /// Overload of SystemParametersInfo for getting and setting HIGHCONTRAST. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "SystemParametersInfoW", SetLastError = true, CharSet = CharSet.Unicode)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _SystemParametersInfo_HIGHCONTRAST(SPI uiAction, int uiParam, [In, Out] ref HIGHCONTRAST pvParam, SPIF fWinIni); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SystemParametersInfo(SPI uiAction, int uiParam, string pvParam, SPIF fWinIni) - { - if (!_SystemParametersInfo_String(uiAction, uiParam, pvParam, fWinIni)) - { - HRESULT.ThrowLastError(); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static NONCLIENTMETRICS SystemParameterInfo_GetNONCLIENTMETRICS() - { - var metrics = Utility.IsOSVistaOrNewer - ? NONCLIENTMETRICS.VistaMetricsStruct - : NONCLIENTMETRICS.XPMetricsStruct; - - if (!_SystemParametersInfo_NONCLIENTMETRICS(SPI.GETNONCLIENTMETRICS, metrics.cbSize, ref metrics, SPIF.None)) - { - HRESULT.ThrowLastError(); - } - - return metrics; - } - - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] - public static HIGHCONTRAST SystemParameterInfo_GetHIGHCONTRAST() - { - var hc = new HIGHCONTRAST { cbSize = Marshal.SizeOf(typeof(HIGHCONTRAST)) }; - - if (!_SystemParametersInfo_HIGHCONTRAST(SPI.GETHIGHCONTRAST, hc.cbSize, ref hc, SPIF.None)) - { - HRESULT.ThrowLastError(); - } - - return hc; - } - - // This function is strange in that it returns a BOOL if TPM_RETURNCMD isn't specified, but otherwise the command Id. - // Currently it's only used with TPM_RETURNCMD, so making the signature match that. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll")] - public static extern uint TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdi32.dll", EntryPoint = "SelectObject", SetLastError = true)] - private static extern IntPtr _SelectObject(SafeDC hdc, IntPtr hgdiobj); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static IntPtr SelectObject(SafeDC hdc, IntPtr hgdiobj) - { - IntPtr ret = _SelectObject(hdc, hgdiobj); - if (ret == IntPtr.Zero) - { - HRESULT.ThrowLastError(); - } - return ret; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("gdi32.dll", EntryPoint = "SelectObject", SetLastError = true)] - private static extern IntPtr _SelectObjectSafeHBITMAP(SafeDC hdc, SafeHBITMAP hgdiobj); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static IntPtr SelectObject(SafeDC hdc, SafeHBITMAP hgdiobj) - { - IntPtr ret = _SelectObjectSafeHBITMAP(hdc, hgdiobj); - if (ret == IntPtr.Zero) - { - HRESULT.ThrowLastError(); - } - return ret; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", SetLastError = true)] - public static extern int SendInput(int nInputs, ref INPUT pInputs, int cbSize); - - // Depending on the message, callers may want to call GetLastError based on the return value. - [DllImport("user32.dll", SetLastError = true)] - public static extern IntPtr SendMessage(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam); - - [DllImport("user32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool ShowWindow(IntPtr hwnd, SW nCmdShow); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "UnregisterClass", SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _UnregisterClassAtom(IntPtr lpClassName, IntPtr hInstance); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", EntryPoint = "UnregisterClass", CharSet = CharSet.Unicode, SetLastError = true)] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _UnregisterClassName(string lpClassName, IntPtr hInstance); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void UnregisterClass(short atom, IntPtr hinstance) - { - if (!_UnregisterClassAtom(new IntPtr(atom), hinstance)) - { - HRESULT.ThrowLastError(); - } - } - - public static void UnregisterClass(string lpClassName, IntPtr hInstance) - { - if (!_UnregisterClassName(lpClassName, hInstance)) - { - HRESULT.ThrowLastError(); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", SetLastError = true, EntryPoint = "UpdateLayeredWindow")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _UpdateLayeredWindow( - IntPtr hwnd, - SafeDC hdcDst, - [In] ref POINT pptDst, - [In] ref SIZE psize, - SafeDC hdcSrc, - [In] ref POINT pptSrc, - int crKey, - ref BLENDFUNCTION pblend, - ULW dwFlags); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("user32.dll", SetLastError = true, EntryPoint = "UpdateLayeredWindow")] - [return: MarshalAs(UnmanagedType.Bool)] - private static extern bool _UpdateLayeredWindowIntPtr( - IntPtr hwnd, - IntPtr hdcDst, - IntPtr pptDst, - IntPtr psize, - IntPtr hdcSrc, - IntPtr pptSrc, - int crKey, - ref BLENDFUNCTION pblend, - ULW dwFlags); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void UpdateLayeredWindow( - IntPtr hwnd, - SafeDC hdcDst, - ref POINT pptDst, - ref SIZE psize, - SafeDC hdcSrc, - ref POINT pptSrc, - int crKey, - ref BLENDFUNCTION pblend, - ULW dwFlags) - { - if (!_UpdateLayeredWindow(hwnd, hdcDst, ref pptDst, ref psize, hdcSrc, ref pptSrc, crKey, ref pblend, dwFlags)) - { - HRESULT.ThrowLastError(); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void UpdateLayeredWindow( - IntPtr hwnd, - int crKey, - ref BLENDFUNCTION pblend, - ULW dwFlags) - { - if (!_UpdateLayeredWindowIntPtr(hwnd, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, crKey, ref pblend, dwFlags)) - { - HRESULT.ThrowLastError(); - } - } - - [DllImport("user32.dll", SetLastError=true, EntryPoint="RegisterClipboardFormatW", CharSet=CharSet.Unicode)] - private static extern uint _RegisterClipboardFormat(string lpszFormatName); - - public static uint RegisterClipboardFormat(string formatName) - { - uint ret = _RegisterClipboardFormat(formatName); - if (ret == 0) - { - HRESULT.ThrowLastError(); - } - - return ret; - } - - [DllImport("ole32.dll")] - public static extern void ReleaseStgMedium(ref STGMEDIUM pmedium); - - [DllImport("ole32.dll")] - public static extern HRESULT CreateStreamOnHGlobal(IntPtr hGlobal, bool fDeleteOnRelease, out IStream ppstm); - - [DllImport("urlmon.dll")] - public static extern HRESULT CopyStgMedium(ref STGMEDIUM pcstgmedSrc, ref STGMEDIUM pstgmedDest); - - - #region Win7 declarations - - //#define DWM_SIT_DISPLAYFRAME 0x00000001 // Display a window frame around the provided bitmap - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("dwmapi.dll", PreserveSig = false)] - public static extern void DwmInvalidateIconicBitmaps(IntPtr hwnd); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("dwmapi.dll", PreserveSig = false)] - public static extern void DwmSetIconicThumbnail(IntPtr hwnd, IntPtr hbmp, DWM_SIT dwSITFlags); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("dwmapi.dll", PreserveSig = false)] - public static extern void DwmSetIconicLivePreviewBitmap(IntPtr hwnd, IntPtr hbmp, RefPOINT pptClient, DWM_SIT dwSITFlags); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("shell32.dll", PreserveSig = false)] - public static extern void SHGetItemFromDataObject(IDataObject pdtobj, DOGIF dwFlags, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object ppv); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("shell32.dll", PreserveSig = false, EntryPoint = "SHAddToRecentDocs")] - private static extern void _SHAddToRecentDocsObj(SHARD uFlags, object pv); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("shell32.dll", EntryPoint = "SHAddToRecentDocs")] - private static extern void _SHAddToRecentDocs_String(SHARD uFlags, [MarshalAs(UnmanagedType.LPWStr)] string pv); - - // This overload is required. There's a cast in the Shell code that causes the wrong vtbl to be used - // if we let the marshaller convert the parameter to an IUnknown. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("shell32.dll", EntryPoint = "SHAddToRecentDocs")] - private static extern void _SHAddToRecentDocs_ShellLink(SHARD uFlags, IShellLinkW pv); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SHAddToRecentDocs(string path) - { - _SHAddToRecentDocs_String(SHARD.PATHW, path); - } - - // Win7 only. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SHAddToRecentDocs(IShellLinkW shellLink) - { - _SHAddToRecentDocs_ShellLink(SHARD.LINK, shellLink); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SHAddToRecentDocs(SHARDAPPIDINFO info) - { - _SHAddToRecentDocsObj(SHARD.APPIDINFO, info); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SHAddToRecentDocs(SHARDAPPIDINFOIDLIST infodIdList) - { - _SHAddToRecentDocsObj(SHARD.APPIDINFOIDLIST, infodIdList); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("shell32.dll", PreserveSig = false)] - public static extern HRESULT SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IBindCtx pbc, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object ppv); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("shell32.dll")] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool Shell_NotifyIcon(NIM dwMessage, [In] NOTIFYICONDATA lpdata); - - /// - /// Sets the User Model AppID for the current process, enabling Windows to retrieve this ID - /// - /// - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("shell32.dll", PreserveSig = false)] - public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID); - - /// - /// Retrieves the User Model AppID that has been explicitly set for the current process via SetCurrentProcessExplicitAppUserModelID - /// - /// - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DllImport("shell32.dll")] - public static extern HRESULT GetCurrentProcessExplicitAppUserModelID([Out, MarshalAs(UnmanagedType.LPWStr)] out string AppID); - - #endregion - } -} diff --git a/Microsoft.Windows.Shell/Standard/NotifyingList.cs b/Microsoft.Windows.Shell/Standard/NotifyingList.cs deleted file mode 100644 index 697e018..0000000 --- a/Microsoft.Windows.Shell/Standard/NotifyingList.cs +++ /dev/null @@ -1,187 +0,0 @@ - -namespace Standard -{ - using System.Collections; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Collections.Specialized; - using System.ComponentModel; - - internal class NotifyingList : IList, INotifyCollectionChanged where T : INotifyPropertyChanged - { - private readonly ObservableCollection _list; - - public event PropertyChangedEventHandler ItemPropertyChanged; - - private void _SafeAddPropertyListener(T item) - { - if (item != null) - { - item.PropertyChanged += _OnItemPropertyChanged; - } - } - - private void _SafeRemovePropertyListener(T item) - { - if (item != null) - { - item.PropertyChanged -= _OnItemPropertyChanged; - } - } - - public NotifyingList() - { - _list = new ObservableCollection(); - } - - public NotifyingList(IEnumerable collection) - { - _list = new ObservableCollection(collection); - foreach (T item in collection) - { - _SafeAddPropertyListener(item); - } - } - - private void _OnItemPropertyChanged(object sender, PropertyChangedEventArgs e) - { - var handler = ItemPropertyChanged; - if (handler != null) - { - handler(sender, e); - } - } - - #region IList Members - - public int IndexOf(T item) - { - return _list.IndexOf(item); - } - - public void Insert(int index, T item) - { - _list.Insert(index, item); - _SafeAddPropertyListener(item); - } - - public void RemoveAt(int index) - { - T item = _list[index]; - _list.RemoveAt(index); - _SafeRemovePropertyListener(item); - } - - public T this[int index] - { - get { return _list[index]; } - set { _list[index] = value; } - } - - #endregion - - #region ICollection Members - - public void Add(T item) - { - _list.Add(item); - _SafeAddPropertyListener(item); - } - - public void Clear() - { - T[] items = new T[_list.Count]; - _list.CopyTo(items, 0); - _list.Clear(); - foreach (T item in items) - { - _SafeRemovePropertyListener(item); - } - } - - public bool Contains(T item) - { - return _list.Contains(item); - } - - public void CopyTo(T[] array, int arrayIndex) - { - _list.CopyTo(array, arrayIndex); - } - - public int Count { get { return _list.Count; } } - - public bool IsReadOnly { get { return false; } } - - public bool Remove(T item) - { - // Don't call through _list.Remove(). - // If equality has been overloaded then we may try removing the handler - // from a different object and we'll leak it. - // Ensure reference equality. - int index = _list.IndexOf(item); - if (index == -1) - { - return false; - } - - RemoveAt(index); - return true; - } - - #endregion - - #region IEnumerable Members - - public IEnumerator GetEnumerator() - { - return _list.GetEnumerator(); - } - - #endregion - - #region IEnumerable Members - - IEnumerator IEnumerable.GetEnumerator() - { - return _list.GetEnumerator(); - } - - #endregion - - #region INotifyCollectionChanged Members - - private event NotifyCollectionChangedEventHandler _sourceCollectionChanged; - - public event NotifyCollectionChangedEventHandler CollectionChanged - { - add - { - if (_sourceCollectionChanged == null) - { - _list.CollectionChanged += _OnSourceCollectionChanged; - } - _sourceCollectionChanged += value; - } - remove - { - _sourceCollectionChanged -= value; - if (_sourceCollectionChanged == null) - { - _list.CollectionChanged -= _OnSourceCollectionChanged; - } - } - } - - private void _OnSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) - { - var handler = _sourceCollectionChanged; - if (handler != null) - { - handler(this, e); - } - } - - #endregion - } -} diff --git a/Microsoft.Windows.Shell/Standard/ShellProvider.cs b/Microsoft.Windows.Shell/Standard/ShellProvider.cs deleted file mode 100644 index 520e0b6..0000000 --- a/Microsoft.Windows.Shell/Standard/ShellProvider.cs +++ /dev/null @@ -1,1309 +0,0 @@ -namespace Standard -{ - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - using System.Runtime.InteropServices.ComTypes; - using System.Text; - - using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; - - #region Enums and Static Property Classes - - /// ASSOCIATIONLEVEL, AL_* - internal enum AL - { - MACHINE, - EFFECTIVE, - USER, - } - - /// ASSOCIATIONTYPE, AT_* - internal enum AT - { - FILEEXTENSION, - URLPROTOCOL, - STARTMENUCLIENT, - MIMETYPE, - } - - /// FileDialog AddPlace options. FDAP_* - internal enum FDAP : uint - { - BOTTOM = 0x00000000, - TOP = 0x00000001, - } - - /// IFileDialog options. FOS_* - [Flags] - internal enum FOS : uint - { - OVERWRITEPROMPT = 0x00000002, - STRICTFILETYPES = 0x00000004, - NOCHANGEDIR = 0x00000008, - PICKFOLDERS = 0x00000020, - FORCEFILESYSTEM = 0x00000040, - ALLNONSTORAGEITEMS = 0x00000080, - NOVALIDATE = 0x00000100, - ALLOWMULTISELECT = 0x00000200, - PATHMUSTEXIST = 0x00000800, - FILEMUSTEXIST = 0x00001000, - CREATEPROMPT = 0x00002000, - SHAREAWARE = 0x00004000, - NOREADONLYRETURN = 0x00008000, - NOTESTFILECREATE = 0x00010000, - HIDEMRUPLACES = 0x00020000, - HIDEPINNEDPLACES = 0x00040000, - NODEREFERENCELINKS = 0x00100000, - DONTADDTORECENT = 0x02000000, - FORCESHOWHIDDEN = 0x10000000, - DEFAULTNOMINIMODE = 0x20000000, - FORCEPREVIEWPANEON = 0x40000000, - } - - /// FDE_OVERWRITE_RESPONSE. FDEOR_* - internal enum FDEOR - { - DEFAULT = 0x00000000, - ACCEPT = 0x00000001, - REFUSE = 0x00000002, - } - - /// FDE_SHAREVIOLATION_RESPONSE. FDESVR_* - internal enum FDESVR - { - DEFAULT = 0x00000000, - ACCEPT = 0x00000001, - REFUSE = 0x00000002, - } - - /// ShellItem attribute flags. SIATTRIBFLAGS_* - internal enum SIATTRIBFLAGS - { - AND = 0x00000001, - OR = 0x00000002, - APPCOMPAT = 0x00000003, - } - - internal enum APPDOCLISTTYPE - { - ADLT_RECENT = 0, // The recently used documents list - ADLT_FREQUENT, // The frequently used documents list - } - - /// - /// Flags for SetTabProperties. STPF_* - /// - /// The native enum was called STPFLAG. - [Flags] - internal enum STPF - { - NONE = 0x00000000, - USEAPPTHUMBNAILALWAYS = 0x00000001, - USEAPPTHUMBNAILWHENACTIVE = 0x00000002, - USEAPPPEEKALWAYS = 0x00000004, - USEAPPPEEKWHENACTIVE = 0x00000008, - } - - /// - /// Flags for Setting Taskbar Progress state. TBPF_* - /// - /// - /// The native enum was called TBPFLAG. - /// - internal enum TBPF - { - NOPROGRESS = 0x00000000, - INDETERMINATE = 0x00000001, - NORMAL = 0x00000002, - ERROR = 0x00000004, - PAUSED = 0x00000008, - } - - /// - /// THUMBBUTTON mask. THB_* - /// - [Flags] - internal enum THB : uint - { - BITMAP = 0x0001, - ICON = 0x0002, - TOOLTIP = 0x0004, - FLAGS = 0x0008, - } - - /// - /// THUMBBUTTON flags. THBF_* - /// - [Flags] - internal enum THBF : uint - { - ENABLED = 0x0000, - DISABLED = 0x0001, - DISMISSONCLICK = 0x0002, - NOBACKGROUND = 0x0004, - HIDDEN = 0x0008, - // Added post-beta - NONINTERACTIVE = 0x0010, - } - - /// - /// GetPropertyStoreFlags. GPS_*. - /// - /// - /// These are new for Vista, but are used in downlevel components - /// - internal enum GPS - { - // If no flags are specified (GPS_DEFAULT), a read-only property store is returned that includes properties for the file or item. - // In the case that the shell item is a file, the property store contains: - // 1. properties about the file from the file system - // 2. properties from the file itself provided by the file's property handler, unless that file is offline, - // see GPS_OPENSLOWITEM - // 3. if requested by the file's property handler and supported by the file system, properties stored in the - // alternate property store. - // - // Non-file shell items should return a similar read-only store - // - // Specifying other GPS_ flags modifies the store that is returned - DEFAULT = 0x00000000, - HANDLERPROPERTIESONLY = 0x00000001, // only include properties directly from the file's property handler - READWRITE = 0x00000002, // Writable stores will only include handler properties - TEMPORARY = 0x00000004, // A read/write store that only holds properties for the lifetime of the IShellItem object - FASTPROPERTIESONLY = 0x00000008, // do not include any properties from the file's property handler (because the file's property handler will hit the disk) - OPENSLOWITEM = 0x00000010, // include properties from a file's property handler, even if it means retrieving the file from offline storage. - DELAYCREATION = 0x00000020, // delay the creation of the file's property handler until those properties are read, written, or enumerated - BESTEFFORT = 0x00000040, // For readonly stores, succeed and return all available properties, even if one or more sources of properties fails. Not valid with GPS_READWRITE. - NO_OPLOCK = 0x00000080, // some data sources protect the read property store with an oplock, this disables that - MASK_VALID = 0x000000FF, - } - - /// - /// KNOWNDESTCATEGORY. KDC_* - /// - internal enum KDC - { - FREQUENT = 1, - RECENT, - } - - // IShellFolder::GetAttributesOf flags - [Flags] - internal enum SFGAO : uint - { - /// Objects can be copied - /// DROPEFFECT_COPY - CANCOPY = 0x1, - /// Objects can be moved - /// DROPEFFECT_MOVE - CANMOVE = 0x2, - /// Objects can be linked - /// - /// DROPEFFECT_LINK. - /// - /// If this bit is set on an item in the shell folder, a - /// 'Create Shortcut' menu item will be added to the File - /// menu and context menus for the item. If the user selects - /// that command, your IContextMenu::InvokeCommand() will be called - /// with 'link'. - /// That flag will also be used to determine if 'Create Shortcut' - /// should be added when the item in your folder is dragged to another - /// folder. - /// - CANLINK = 0x4, - /// supports BindToObject(IID_IStorage) - STORAGE = 0x00000008, - /// Objects can be renamed - CANRENAME = 0x00000010, - /// Objects can be deleted - CANDELETE = 0x00000020, - /// Objects have property sheets - HASPROPSHEET = 0x00000040, - - // unused = 0x00000080, - - /// Objects are drop target - DROPTARGET = 0x00000100, - CAPABILITYMASK = 0x00000177, - // unused = 0x00000200, - // unused = 0x00000400, - // unused = 0x00000800, - // unused = 0x00001000, - /// Object is encrypted (use alt color) - ENCRYPTED = 0x00002000, - /// 'Slow' object - ISSLOW = 0x00004000, - /// Ghosted icon - GHOSTED = 0x00008000, - /// Shortcut (link) - LINK = 0x00010000, - /// Shared - SHARE = 0x00020000, - /// Read-only - READONLY = 0x00040000, - /// Hidden object - HIDDEN = 0x00080000, - DISPLAYATTRMASK = 0x000FC000, - /// May contain children with SFGAO_FILESYSTEM - FILESYSANCESTOR = 0x10000000, - /// Support BindToObject(IID_IShellFolder) - FOLDER = 0x20000000, - /// Is a win32 file system object (file/folder/root) - FILESYSTEM = 0x40000000, - /// May contain children with SFGAO_FOLDER (may be slow) - HASSUBFOLDER = 0x80000000, - CONTENTSMASK = 0x80000000, - /// Invalidate cached information (may be slow) - VALIDATE = 0x01000000, - /// Is this removeable media? - REMOVABLE = 0x02000000, - /// Object is compressed (use alt color) - COMPRESSED = 0x04000000, - /// Supports IShellFolder, but only implements CreateViewObject() (non-folder view) - BROWSABLE = 0x08000000, - /// Is a non-enumerated object (should be hidden) - NONENUMERATED = 0x00100000, - /// Should show bold in explorer tree - NEWCONTENT = 0x00200000, - /// Obsolete - CANMONIKER = 0x00400000, - /// Obsolete - HASSTORAGE = 0x00400000, - /// Supports BindToObject(IID_IStream) - STREAM = 0x00400000, - /// May contain children with SFGAO_STORAGE or SFGAO_STREAM - STORAGEANCESTOR = 0x00800000, - /// For determining storage capabilities, ie for open/save semantics - STORAGECAPMASK = 0x70C50008, - /// - /// Attributes that are masked out for PKEY_SFGAOFlags because they are considered - /// to cause slow calculations or lack context - /// (SFGAO_VALIDATE | SFGAO_ISSLOW | SFGAO_HASSUBFOLDER and others) - /// - PKEYSFGAOMASK = 0x81044000, - } - - /// - /// IShellFolder::EnumObjects grfFlags bits. Also called SHCONT - /// - internal enum SHCONTF - { - CHECKING_FOR_CHILDREN = 0x0010, // hint that client is checking if (what) child items the folder contains - not all details (e.g. short file name) are needed - FOLDERS = 0x0020, // only want folders enumerated (SFGAO_FOLDER) - NONFOLDERS = 0x0040, // include non folders (items without SFGAO_FOLDER) - INCLUDEHIDDEN = 0x0080, // show items normally hidden (items with SFGAO_HIDDEN) - INIT_ON_FIRST_NEXT = 0x0100, // DEFUNCT - this is always assumed - NETPRINTERSRCH = 0x0200, // hint that client is looking for printers - SHAREABLE = 0x0400, // hint that client is looking sharable resources (local drives or hidden root shares) - STORAGE = 0x0800, // include all items with accessible storage and their ancestors - NAVIGATION_ENUM = 0x1000, // mark child folders to indicate that they should provide a "navigation" enumeration by default - FASTITEMS = 0x2000, // hint that client is only interested in items that can be enumerated quickly - FLATLIST = 0x4000, // enumerate items as flat list even if folder is stacked - ENABLE_ASYNC = 0x8000, // inform enumerator that client is listening for change notifications so enumerator does not need to be complete, items can be reported via change notifications - } - - /// - /// IShellFolder::GetDisplayNameOf/SetNameOf uFlags. Also called SHGDNF. - /// - /// - /// For compatibility with SIGDN, these bits must all sit in the LOW word. - /// - [Flags] - internal enum SHGDN - { - SHGDN_NORMAL = 0x0000, // default (display purpose) - SHGDN_INFOLDER = 0x0001, // displayed under a folder (relative) - SHGDN_FOREDITING = 0x1000, // for in-place editing - SHGDN_FORADDRESSBAR = 0x4000, // UI friendly parsing name (remove ugly stuff) - SHGDN_FORPARSING = 0x8000, // parsing name for ParseDisplayName() - } - - /// - /// SHELLITEMCOMPAREHINTF. SICHINT_*. - /// - internal enum SICHINT : uint - { - /// iOrder based on display in a folder view - DISPLAY = 0x00000000, - /// exact instance compare - ALLFIELDS = 0x80000000, - /// iOrder based on canonical name (better performance) - CANONICAL = 0x10000000, - TEST_FILESYSPATH_IF_NOT_EQUAL = 0x20000000, - }; - - /// - /// ShellItem enum. SIGDN_*. - /// - internal enum SIGDN : uint - { // lower word (& with 0xFFFF) - NORMALDISPLAY = 0x00000000, // SHGDN_NORMAL - PARENTRELATIVEPARSING = 0x80018001, // SHGDN_INFOLDER | SHGDN_FORPARSING - DESKTOPABSOLUTEPARSING = 0x80028000, // SHGDN_FORPARSING - PARENTRELATIVEEDITING = 0x80031001, // SHGDN_INFOLDER | SHGDN_FOREDITING - DESKTOPABSOLUTEEDITING = 0x8004c000, // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR - FILESYSPATH = 0x80058000, // SHGDN_FORPARSING - URL = 0x80068000, // SHGDN_FORPARSING - PARENTRELATIVEFORADDRESSBAR = 0x8007c001, // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR - PARENTRELATIVE = 0x80080001, // SHGDN_INFOLDER - } - - /// - /// STR_GPS_* - /// - /// - /// When requesting a property store through IShellFolder, you can specify the equivalent of - /// GPS_DEFAULT by passing in a null IBindCtx parameter. - /// - /// You can specify the equivalent of GPS_READWRITE by passing a mode of STGM_READWRITE | STGM_EXCLUSIVE - /// in the bind context - /// - /// Here are the string versions of GPS_ flags, passed to IShellFolder::BindToObject() via IBindCtx::RegisterObjectParam() - /// These flags are valid when requesting an IPropertySetStorage or IPropertyStore handler - /// - /// The meaning of these flags are described above. - /// - /// There is no STR_ equivalent for GPS_TEMPORARY because temporary property stores - /// are provided by IShellItem2 only -- not by the underlying IShellFolder. - /// - internal static class STR_GPS - { - public const string HANDLERPROPERTIESONLY = "GPS_HANDLERPROPERTIESONLY"; - public const string FASTPROPERTIESONLY = "GPS_FASTPROPERTIESONLY"; - public const string OPENSLOWITEM = "GPS_OPENSLOWITEM"; - public const string DELAYCREATION = "GPS_DELAYCREATION"; - public const string BESTEFFORT = "GPS_BESTEFFORT"; - public const string NO_OPLOCK = "GPS_NO_OPLOCK"; - } - - #endregion - - #region Structs - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - internal struct COMDLG_FILTERSPEC - { - [MarshalAs(UnmanagedType.LPWStr)] - public string pszName; - [MarshalAs(UnmanagedType.LPWStr)] - public string pszSpec; - } - - - [StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)] - internal struct THUMBBUTTON - { - /// - /// WPARAM value for a THUMBBUTTON being clicked. - /// - public const int THBN_CLICKED = 0x1800; - - public THB dwMask; - public uint iId; - public uint iBitmap; - public IntPtr hIcon; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] - public string szTip; - public THBF dwFlags; - } - - - [StructLayout(LayoutKind.Sequential, Pack = 4)] - internal struct PKEY - { - /// fmtid - private readonly Guid _fmtid; - /// pid - private readonly uint _pid; - - public PKEY(Guid fmtid, uint pid) - { - _fmtid = fmtid; - _pid = pid; - } - - /// PKEY_Title - public static readonly PKEY Title = new PKEY(new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9"), 2); - /// PKEY_AppUserModel_ID - public static readonly PKEY AppUserModel_ID = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 5); - /// PKEY_AppUserModel_IsDestListSeparator - public static readonly PKEY AppUserModel_IsDestListSeparator = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 6); - /// PKEY_AppUserModel_RelaunchCommand - public static readonly PKEY AppUserModel_RelaunchCommand = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 2); - /// PKEY_AppUserModel_RelaunchDisplayNameResource - public static readonly PKEY AppUserModel_RelaunchDisplayNameResource = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 4); - /// PKEY_AppUserModel_RelaunchIconResource - public static readonly PKEY AppUserModel_RelaunchIconResource = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 3); - } - - #endregion - - #region Interfaces - - // Application File Extension and URL Protocol Registration - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.ApplicationAssociationRegistration), - ] - internal interface IApplicationAssociationRegistration - { - [return: MarshalAs(UnmanagedType.LPWStr)] - string QueryCurrentDefault( - [MarshalAs(UnmanagedType.LPWStr)] string pszQuery, - AT atQueryType, - AL alQueryLevel); - - [return: MarshalAs(UnmanagedType.Bool)] - bool QueryAppIsDefault( - [MarshalAs(UnmanagedType.LPWStr)] string pszQuery, - AT atQueryType, - AL alQueryLevel, - [MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName); - - [return: MarshalAs(UnmanagedType.Bool)] - bool QueryAppIsDefaultAll( - AL alQueryLevel, - [MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName); - - void SetAppAsDefault( - [MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName, - [MarshalAs(UnmanagedType.LPWStr)] string pszSet, - AT atSetType); - - void SetAppAsDefaultAll([MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName); - - void ClearUserAssociations(); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.EnumIdList), - ] - internal interface IEnumIDList - { - [PreserveSig()] - HRESULT Next(uint celt, out IntPtr rgelt, out int pceltFetched); - [PreserveSig()] - HRESULT Skip(uint celt); - void Reset(); - void Clone([Out, MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenum); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.EnumObjects), - ] - internal interface IEnumObjects - { - //[local] - // This signature might not work... Hopefully don't need this interface though. - void Next(uint celt, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.IUnknown, IidParameterIndex = 1, SizeParamIndex = 0)] object[] rgelt, [Out] out uint pceltFetched); - - /* - [call_as(Next)] HRESULT RemoteNext( - [in] ULONG celt, - [in] REFIID riid, - [out, size_is(celt), length_is(*pceltFetched), iid_is(riid)] void **rgelt, - [out] ULONG *pceltFetched); - */ - - void Skip(uint celt); - - void Reset(); - - IEnumObjects Clone(); - } - - /// Unknown Object Array - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.ObjectArray), - ] - internal interface IObjectArray - { - uint GetCount(); - [return: MarshalAs(UnmanagedType.IUnknown)] - object GetAt([In] uint uiIndex, [In] ref Guid riid); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.ObjectArray), - ] - interface IObjectCollection : IObjectArray - { - #region IObjectArray redeclarations - new uint GetCount(); - [return: MarshalAs(UnmanagedType.IUnknown)] - new object GetAt([In] uint uiIndex, [In] ref Guid riid); - #endregion - - void AddObject([MarshalAs(UnmanagedType.IUnknown)] object punk); - void AddFromArray(IObjectArray poaSource); - void RemoveObjectAt(uint uiIndex); - void Clear(); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.PropertyStore) - ] - internal interface IPropertyStore - { - uint GetCount(); - PKEY GetAt(uint iProp); - void GetValue([In] ref PKEY pkey, [In, Out] PROPVARIANT pv); - void SetValue([In] ref PKEY pkey, PROPVARIANT pv); - void Commit(); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.ShellFolder), - ] - internal interface IShellFolder - { - void ParseDisplayName( - [In] IntPtr hwnd, - [In] IBindCtx pbc, - [In, MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, - [In, Out] ref int pchEaten, - [Out] out IntPtr ppidl, - [In, Out] ref uint pdwAttributes); - - IEnumIDList EnumObjects( - [In] IntPtr hwnd, - [In] SHCONTF grfFlags); - - // returns an instance of a sub-folder which is specified by the IDList (pidl). - // IShellFolder or derived interfaces - [return: MarshalAs(UnmanagedType.Interface)] - object BindToObject( - [In] IntPtr pidl, - [In] IBindCtx pbc, - [In] ref Guid riid); - - // produces the same result as BindToObject() - [return: MarshalAs(UnmanagedType.Interface)] - object BindToStorage([In] IntPtr pidl, [In] IBindCtx pbc, [In] ref Guid riid); - - // compares two IDLists and returns the result. The shell - // explorer always passes 0 as lParam, which indicates 'sort by name'. - // It should return 0 (as CODE of the scode), if two id indicates the - // same object; negative value if pidl1 should be placed before pidl2; - // positive value if pidl2 should be placed before pidl1. - // use the macro ResultFromShort() to extract the result comparison - // it deals with the casting and type conversion issues for you - [PreserveSig] - HRESULT CompareIDs([In] IntPtr lParam, [In] IntPtr pidl1, [In] IntPtr pidl2); - - // creates a view object of the folder itself. The view - // object is a difference instance from the shell folder object. - // 'hwndOwner' can be used as the owner window of its dialog box or - // menu during the lifetime of the view object. - // This member function should always create a new - // instance which has only one reference count. The explorer may create - // more than one instances of view object from one shell folder object - // and treat them as separate instances. - // returns IShellView derived interface - [return: MarshalAs(UnmanagedType.Interface)] - object CreateViewObject([In] IntPtr hwndOwner, [In] ref Guid riid); - - // returns the attributes of specified objects in that - // folder. 'cidl' and 'apidl' specifies objects. 'apidl' contains only - // simple IDLists. The explorer initializes *prgfInOut with a set of - // flags to be evaluated. The shell folder may optimize the operation - // by not returning unspecified flags. - void GetAttributesOf( - [In] uint cidl, - [In] IntPtr apidl, - [In, Out] ref SFGAO rgfInOut); - - // creates a UI object to be used for specified objects. - // The shell explorer passes either IID_IDataObject (for transfer operation) - // or IID_IContextMenu (for context menu operation) as riid - // and many other interfaces - [return: MarshalAs(UnmanagedType.Interface)] - object GetUIObjectOf( - [In] IntPtr hwndOwner, - [In] uint cidl, - [In, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.SysInt, SizeParamIndex = 2)] IntPtr apidl, - [In] ref Guid riid, - [In, Out] ref uint rgfReserved); - - // returns the display name of the specified object. - // If the ID contains the display name (in the locale character set), - // it returns the offset to the name. Otherwise, it returns a pointer - // to the display name string (UNICODE), which is allocated by the - // task allocator, or fills in a buffer. - // use the helper APIS StrRetToStr() or StrRetToBuf() to deal with the different - // forms of the STRRET structure - void GetDisplayNameOf([In] IntPtr pidl, [In] SHGDN uFlags, [Out] out IntPtr pName); - - // sets the display name of the specified object. - // If it changes the ID as well, it returns the new ID which is - // alocated by the task allocator. - void SetNameOf([In] IntPtr hwnd, - [In] IntPtr pidl, - [In, MarshalAs(UnmanagedType.LPWStr)] string pszName, - [In] SHGDN uFlags, - [Out] out IntPtr ppidlOut); - } - - /// - /// Shell Namespace helper - /// - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.ShellItem), - ] - internal interface IShellItem - { - [return: MarshalAs(UnmanagedType.Interface)] - object BindToHandler(IBindCtx pbc, [In] ref Guid bhid, [In] ref Guid riid); - - IShellItem GetParent(); - - [return: MarshalAs(UnmanagedType.LPWStr)] - string GetDisplayName(SIGDN sigdnName); - - SFGAO GetAttributes(SFGAO sfgaoMask); - - int Compare(IShellItem psi, SICHINT hint); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.ShellItemArray), - ] - internal interface IShellItemArray - { - [return: MarshalAs(UnmanagedType.Interface)] - object BindToHandler(IBindCtx pbc, [In] ref Guid rbhid, [In] ref Guid riid); - - [return: MarshalAs(UnmanagedType.Interface)] - object GetPropertyStore(int flags, [In] ref Guid riid); - - [return: MarshalAs(UnmanagedType.Interface)] - object GetPropertyDescriptionList([In] ref PKEY keyType, [In] ref Guid riid); - - uint GetAttributes(SIATTRIBFLAGS dwAttribFlags, uint sfgaoMask); - - uint GetCount(); - - IShellItem GetItemAt(uint dwIndex); - - [return: MarshalAs(UnmanagedType.Interface)] - object EnumItems(); - } - - /// - /// Shell Namespace helper 2 - /// - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.ShellItem2), - ] - interface IShellItem2 : IShellItem - { - #region IShellItem redeclarations - [return: MarshalAs(UnmanagedType.Interface)] - new object BindToHandler([In] IBindCtx pbc, [In] ref Guid bhid, [In] ref Guid riid); - new IShellItem GetParent(); - [return: MarshalAs(UnmanagedType.LPWStr)] - new string GetDisplayName(SIGDN sigdnName); - new SFGAO GetAttributes(SFGAO sfgaoMask); - new int Compare(IShellItem psi, SICHINT hint); - #endregion - - [return: MarshalAs(UnmanagedType.Interface)] - object GetPropertyStore( - GPS flags, - [In] ref Guid riid); - - [return: MarshalAs(UnmanagedType.Interface)] - object GetPropertyStoreWithCreateObject( - GPS flags, - [MarshalAs(UnmanagedType.IUnknown)] object punkCreateObject, // factory for low-rights creation of type ICreateObject - [In] ref Guid riid); - - [return: MarshalAs(UnmanagedType.Interface)] - object GetPropertyStoreForKeys( - IntPtr rgKeys, - uint cKeys, - GPS flags, - [In] ref Guid riid); - - [return: MarshalAs(UnmanagedType.Interface)] - object GetPropertyDescriptionList( - IntPtr keyType, - [In] ref Guid riid); - - // Ensures any cached information in this item is up to date, or returns __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) if the item does not exist. - void Update(IBindCtx pbc); - - PROPVARIANT GetProperty(IntPtr key); - - Guid GetCLSID(IntPtr key); - - FILETIME GetFileTime(IntPtr key); - - int GetInt32(IntPtr key); - - [return: MarshalAs(UnmanagedType.LPWStr)] - string GetString(IntPtr key); - - uint GetUInt32(IntPtr key); - - ulong GetUInt64(IntPtr key); - - [return: MarshalAs(UnmanagedType.Bool)] - void GetBool(IntPtr key); - } - - [ - ComImport, - InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.ShellLink), - ] - internal interface IShellLinkW - { - void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, [In, Out] WIN32_FIND_DATAW pfd, SLGP fFlags); - void GetIDList(out IntPtr ppidl); - void SetIDList(IntPtr pidl); - void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxName); - void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); - void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); - void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); - void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); - void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); - short GetHotKey(); - void SetHotKey(short wHotKey); - uint GetShowCmd(); - void SetShowCmd(uint iShowCmd); - void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon); - void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); - void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved); - void Resolve(IntPtr hwnd, uint fFlags); - void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.TaskbarList), - ] - internal interface ITaskbarList - { - /// - /// This function must be called first to validate use of other members. - /// - void HrInit(); - - /// - /// This function adds a tab for hwnd to the taskbar. - /// - /// The HWND for which to add the tab. - void AddTab(IntPtr hwnd); - - /// - /// This function deletes a tab for hwnd from the taskbar. - /// - /// The HWND for which the tab is to be deleted. - void DeleteTab(IntPtr hwnd); - - /// - /// This function activates the tab associated with hwnd on the taskbar. - /// - /// The HWND for which the tab is to be actuvated. - void ActivateTab(IntPtr hwnd); - - /// - /// This function marks hwnd in the taskbar as the active tab. - /// - /// The HWND to activate. - void SetActiveAlt(IntPtr hwnd); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.TaskbarList2), - ] - internal interface ITaskbarList2 : ITaskbarList - { - #region ITaskbarList redeclaration - new void HrInit(); - new void AddTab(IntPtr hwnd); - new void DeleteTab(IntPtr hwnd); - new void ActivateTab(IntPtr hwnd); - new void SetActiveAlt(IntPtr hwnd); - #endregion - - /// - /// Marks a window as full-screen. - /// - /// The handle of the window to be marked. - /// A Boolean value marking the desired full-screen status of the window. - /// - /// Setting the value of fFullscreen to true, the Shell treats this window as a full-screen window, and the taskbar - /// is moved to the bottom of the z-order when this window is active. Setting the value of fFullscreen to false - /// removes the full-screen marking, but does not cause the Shell to treat the window as though it were - /// definitely not full-screen. With a false fFullscreen value, the Shell depends on its automatic detection facility - /// to specify how the window should be treated, possibly still flagging the window as full-screen. - /// - void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); - } - - // Used to remove items from the automatic destination lists created when apps or the system call SHAddToRecentDocs to report usage of a document. - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.ApplicationDestinations) - ] - internal interface IApplicationDestinations - { - // Set the App User Model ID for the application removing destinations from its list. If an AppID is not provided - // via this method, the system will use a heuristically determined ID. This method must be called before - // RemoveDestination or RemoveAllDestinations. - void SetAppID([In, MarshalAs(UnmanagedType.LPWStr)] string pszAppID); - - // Remove an IShellItem or an IShellLink from the automatic destination list - void RemoveDestination([MarshalAs(UnmanagedType.IUnknown)] object punk); - - // Clear the frequent and recent destination lists for this application. - void RemoveAllDestinations(); - } - - /// - /// Allows an application to retrieve the most recent and frequent documents opened in that app, as reported via SHAddToRecentDocs - /// - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.ApplicationDocumentLists) - ] - internal interface IApplicationDocumentLists - { - /// - /// Set the App User Model ID for the application retrieving this list. If an AppID is not provided via this method, - /// the system will use a heuristically determined ID. This method must be called before GetList. - /// - /// App Id. - void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); - - /// - /// Retrieve an IEnumObjects or IObjectArray for IShellItems and/or IShellLinks. - /// Items may appear in both the frequent and recent lists. - /// - /// - /// - [return: MarshalAs(UnmanagedType.IUnknown)] - object GetList([In] APPDOCLISTTYPE listtype, [In] uint cItemsDesired, [In] ref Guid riid); - } - - // Custom Destination List - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.CustomDestinationList) - ] - internal interface ICustomDestinationList - { - void SetAppID([In, MarshalAs(UnmanagedType.LPWStr)] string pszAppID); - - // Retrieve IObjectArray of IShellItems or IShellLinks that represent removed destinations - [return: MarshalAs(UnmanagedType.Interface)] - object BeginList(out uint pcMaxSlots, [In] ref Guid riid); - - // PreserveSig because this will return custom errors when attempting to add unregistered ShellItems. - // Can't readily detect that case without just trying to append it. - [PreserveSig] - HRESULT AppendCategory([MarshalAs(UnmanagedType.LPWStr)] string pszCategory, IObjectArray poa); - void AppendKnownCategory(KDC category); - [PreserveSig] - HRESULT AddUserTasks(IObjectArray poa); - void CommitList(); - - // Retrieve IObjectCollection of IShellItems - [return: MarshalAs(UnmanagedType.Interface)] - object GetRemovedDestinations([In] ref Guid riid); - void DeleteList([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); - void AbortList(); - } - - /// - /// Provides access to the App User Model ID on objects supporting this value. - /// - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.ObjectWithAppUserModelId) - ] - internal interface IObjectWithAppUserModelId - { - void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); - [return: MarshalAs(UnmanagedType.LPWStr)] - string GetAppID(); - }; - - /// - /// Provides access to the ProgID associated with an object - /// - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.ObjectWithProgId) - ] - internal interface IObjectWithProgId - { - void SetProgID([MarshalAs(UnmanagedType.LPWStr)] string pszProgID); - [return: MarshalAs(UnmanagedType.LPWStr)] - string GetProgID(); - }; - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.TaskbarList3), - ] - internal interface ITaskbarList3 : ITaskbarList2 - { - #region ITaskbarList2 redeclaration - - #region ITaskbarList redeclaration - new void HrInit(); - new void AddTab(IntPtr hwnd); - new void DeleteTab(IntPtr hwnd); - new void ActivateTab(IntPtr hwnd); - new void SetActiveAlt(IntPtr hwnd); - #endregion - - new void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); - - #endregion - - [PreserveSig] - HRESULT SetProgressValue(IntPtr hwnd, ulong ullCompleted, ulong ullTotal); - - [PreserveSig] - HRESULT SetProgressState(IntPtr hwnd, TBPF tbpFlags); - - [PreserveSig] - HRESULT RegisterTab(IntPtr hwndTab, IntPtr hwndMDI); - - [PreserveSig] - HRESULT UnregisterTab(IntPtr hwndTab); - - [PreserveSig] - HRESULT SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore); - - [PreserveSig] - HRESULT SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, uint dwReserved); - - [PreserveSig] - HRESULT ThumbBarAddButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); - - [PreserveSig] - HRESULT ThumbBarUpdateButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); - - [PreserveSig] - HRESULT ThumbBarSetImageList(IntPtr hwnd, [MarshalAs(UnmanagedType.IUnknown)] object himl); - - [PreserveSig] - HRESULT SetOverlayIcon(IntPtr hwnd, IntPtr hIcon, [MarshalAs(UnmanagedType.LPWStr)] string pszDescription); - - [PreserveSig] - HRESULT SetThumbnailTooltip(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszTip); - - // Using RefRECT to making passing NULL possible. Removes clipping from the HWND. - [PreserveSig] - HRESULT SetThumbnailClip(IntPtr hwnd, RefRECT prcClip); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.TaskbarList3), - ] - internal interface ITaskbarList4 : ITaskbarList3 - { - #region ITaskbarList3 redeclaration - - #region ITaskbarList2 redeclaration - - #region ITaskbarList redeclaration - new void HrInit(); - new void AddTab(IntPtr hwnd); - new void DeleteTab(IntPtr hwnd); - new void ActivateTab(IntPtr hwnd); - new void SetActiveAlt(IntPtr hwnd); - #endregion - - new void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); - - #endregion - - [PreserveSig] new HRESULT SetProgressValue(IntPtr hwnd, ulong ullCompleted, ulong ullTotal); - [PreserveSig] new HRESULT SetProgressState(IntPtr hwnd, TBPF tbpFlags); - [PreserveSig] new HRESULT RegisterTab(IntPtr hwndTab, IntPtr hwndMDI); - [PreserveSig] new HRESULT UnregisterTab(IntPtr hwndTab); - [PreserveSig] new HRESULT SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore); - [PreserveSig] new HRESULT SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, uint dwReserved); - [PreserveSig] new HRESULT ThumbBarAddButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); - [PreserveSig] new HRESULT ThumbBarUpdateButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); - [PreserveSig] new HRESULT ThumbBarSetImageList(IntPtr hwnd, [MarshalAs(UnmanagedType.IUnknown)] object himl); - [PreserveSig] new HRESULT SetOverlayIcon(IntPtr hwnd, IntPtr hIcon, [MarshalAs(UnmanagedType.LPWStr)] string pszDescription); - [PreserveSig] new HRESULT SetThumbnailTooltip(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszTip); - // Using RefRECT to making passing NULL possible. Removes clipping from the HWND. - [PreserveSig] new HRESULT SetThumbnailClip(IntPtr hwnd, RefRECT prcClip); - - #endregion - - void SetTabProperties(IntPtr hwndTab, STPF stpFlags); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.FileDialogEvents), -] - internal interface IFileDialogEvents - { - [PreserveSig] - HRESULT OnFileOk(IFileDialog pfd); - - [PreserveSig] - HRESULT OnFolderChanging(IFileDialog pfd, IShellItem psiFolder); - - [PreserveSig] - HRESULT OnFolderChange(IFileDialog pfd); - - [PreserveSig] - HRESULT OnSelectionChange(IFileDialog pfd); - - [PreserveSig] - HRESULT OnShareViolation(IFileDialog pfd, IShellItem psi, out FDESVR pResponse); - - [PreserveSig] - HRESULT OnTypeChange(IFileDialog pfd); - - [PreserveSig] - HRESULT OnOverwrite(IFileDialog pfd, IShellItem psi, out FDEOR pResponse); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.ModalWindow), - ] - internal interface IModalWindow - { - [PreserveSig] - HRESULT Show(IntPtr parent); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.FileDialog), - ] - internal interface IFileDialog : IModalWindow - { - #region IModalWindow redeclarations - [PreserveSig] - new HRESULT Show(IntPtr parent); - #endregion - - void SetFileTypes(uint cFileTypes, [In] ref COMDLG_FILTERSPEC rgFilterSpec); - - void SetFileTypeIndex(uint iFileType); - - uint GetFileTypeIndex(); - - uint Advise(IFileDialogEvents pfde); - - void Unadvise(uint dwCookie); - - void SetOptions(FOS fos); - - FOS GetOptions(); - - void SetDefaultFolder(IShellItem psi); - - void SetFolder(IShellItem psi); - - IShellItem GetFolder(); - - IShellItem GetCurrentSelection(); - - void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName); - - [return: MarshalAs(UnmanagedType.LPWStr)] - string GetFileName(); - - void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle); - - void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText); - - void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel); - - IShellItem GetResult(); - - void AddPlace(IShellItem psi, FDAP alignment); - - void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); - - void Close([MarshalAs(UnmanagedType.Error)] int hr); - - void SetClientGuid([In] ref Guid guid); - - void ClearClientData(); - - void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.FileOpenDialog), - ] - internal interface IFileOpenDialog : IFileDialog - { - #region IFileDialog redeclarations - - #region IModalDialog redeclarations - [PreserveSig] - new HRESULT Show(IntPtr parent); - #endregion - - new void SetFileTypes(uint cFileTypes, [In] ref COMDLG_FILTERSPEC rgFilterSpec); - new void SetFileTypeIndex(uint iFileType); - new uint GetFileTypeIndex(); - new uint Advise(IFileDialogEvents pfde); - new void Unadvise(uint dwCookie); - new void SetOptions(FOS fos); - new FOS GetOptions(); - new void SetDefaultFolder(IShellItem psi); - new void SetFolder(IShellItem psi); - new IShellItem GetFolder(); - new IShellItem GetCurrentSelection(); - new void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName); - [return: MarshalAs(UnmanagedType.LPWStr)] - new string GetFileName(); - new void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle); - new void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText); - new void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel); - new IShellItem GetResult(); - new void AddPlace(IShellItem psi, FDAP fdcp); - new void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); - new void Close([MarshalAs(UnmanagedType.Error)] int hr); - new void SetClientGuid([In] ref Guid guid); - new void ClearClientData(); - new void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter); - - #endregion - - IShellItemArray GetResults(); - - IShellItemArray GetSelectedItems(); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.FileSaveDialog), - ] - internal interface IFileSaveDialog : IFileDialog - { - #region IFileDialog redeclarations - - #region IModalDialog redeclarations - [PreserveSig] - new HRESULT Show(IntPtr parent); - #endregion - - new void SetFileTypes(uint cFileTypes, [In] ref COMDLG_FILTERSPEC rgFilterSpec); - new void SetFileTypeIndex(uint iFileType); - new uint GetFileTypeIndex(); - new uint Advise(IFileDialogEvents pfde); - new void Unadvise(uint dwCookie); - new void SetOptions(FOS fos); - new FOS GetOptions(); - new void SetDefaultFolder(IShellItem psi); - new void SetFolder(IShellItem psi); - new IShellItem GetFolder(); - new IShellItem GetCurrentSelection(); - new void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName); - [return: MarshalAs(UnmanagedType.LPWStr)] - new string GetFileName(); - new void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle); - new void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText); - new void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel); - new IShellItem GetResult(); - new void AddPlace(IShellItem psi, FDAP fdcp); - new void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); - new void Close([MarshalAs(UnmanagedType.Error)] int hr); - new void SetClientGuid([In] ref Guid guid); - new void ClearClientData(); - new void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter); - - #endregion - - void SetSaveAsItem(IShellItem psi); - - void SetProperties([In, MarshalAs(UnmanagedType.Interface)] object pStore); - - void SetCollectedProperties([In, MarshalAs(UnmanagedType.Interface)] object pList, [In] int fAppendDefault); - - [return: MarshalAs(UnmanagedType.Interface)] - object GetProperties(); - - void ApplyProperties(IShellItem psi, [MarshalAs(UnmanagedType.Interface)] object pStore, [In] ref IntPtr hwnd, [MarshalAs(UnmanagedType.Interface)] object pSink); - } - - internal static class ShellUtil - { - public static string GetPathFromShellItem(IShellItem item) - { - return item.GetDisplayName(SIGDN.DESKTOPABSOLUTEPARSING); - } - - public static IShellItem2 GetShellItemForPath(string path) - { - if (string.IsNullOrEmpty(path)) - { - // Internal function. Should have verified this before calling if we cared. - return null; - } - - Guid iidShellItem2 = new Guid(IID.ShellItem2); - object unk; - HRESULT hr = NativeMethods.SHCreateItemFromParsingName(path, null, ref iidShellItem2, out unk); - - // Silently absorb errors such as ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND. - // Let others pass through - if (hr == (HRESULT)Win32Error.ERROR_FILE_NOT_FOUND || hr == (HRESULT)Win32Error.ERROR_PATH_NOT_FOUND) - { - hr = HRESULT.S_OK; - unk = null; - } - - hr.ThrowIfFailed(); - - return (IShellItem2)unk; - } - } - - #endregion -} diff --git a/Microsoft.Windows.Shell/Standard/SmallString.cs b/Microsoft.Windows.Shell/Standard/SmallString.cs deleted file mode 100644 index 7c2853e..0000000 --- a/Microsoft.Windows.Shell/Standard/SmallString.cs +++ /dev/null @@ -1,253 +0,0 @@ - -namespace Standard -{ - using System; - - [System.Diagnostics.DebuggerDisplay("SmallString: { GetString() }")] - internal struct SmallString : IEquatable, IComparable - { - [Flags] - private enum _SmallFlags : byte - { - None = 0, - IsInt64 = 1, - HasHashCode = 2, - Reserved = 4, - } - - private static readonly System.Text.UTF8Encoding s_Encoder = new System.Text.UTF8Encoding(false /* do not emit BOM */, true /* throw on error */); - private readonly byte[] _encodedBytes; - private _SmallFlags _flags; - private int _cachedHashCode; - - public SmallString(string value, bool precacheHashCode = false) - { - _flags = _SmallFlags.None; - _cachedHashCode = 0; - - if (!string.IsNullOrEmpty(value)) - { - if (precacheHashCode) - { - _flags |= _SmallFlags.HasHashCode; - _cachedHashCode = value.GetHashCode(); - } - - long numValue; - if (long.TryParse(value, System.Globalization.NumberStyles.None, null, out numValue)) - { - _flags |= _SmallFlags.IsInt64; - _encodedBytes = BitConverter.GetBytes(numValue); - - // It's possible that this doesn't round trip with full fidelity. - // If this assert ever gets hit, consider adding an overload that opts - // out of this optimization. - // (Note that the parameters are not evaluated on retail builds) - Assert.AreEqual(this.GetString(), value); - - return; - } - - _encodedBytes = s_Encoder.GetBytes(value); - Assert.IsNotNull(_encodedBytes); - } - else - { - _encodedBytes = null; - } - } - - private bool _IsInt64 - { - get { return (_flags & _SmallFlags.IsInt64) == _SmallFlags.IsInt64; } - } - - private bool _HasCachedHashCode - { - get { return (_flags & _SmallFlags.HasHashCode) == _SmallFlags.HasHashCode; } - } - - #region Object Overrides - - public override string ToString() - { - Assert.Fail(); - throw new NotSupportedException("This exception exists to prevent accidental performance penalties. Call GetString() instead."); - } - - public override int GetHashCode() - { - if (_encodedBytes == null) - { - return 0; - } - - if (!_HasCachedHashCode) - { - // Intentionally hashes similarly to the expanded strings. - _cachedHashCode = GetString().GetHashCode(); - _flags |= _SmallFlags.HasHashCode; - } - - return _cachedHashCode; - } - - public override bool Equals(object obj) - { - try - { - return Equals((SmallString)obj); - } - catch (InvalidCastException) - { - return false; - } - } - - #endregion - - #region IEquatable Members - - public bool Equals(SmallString other) - { - if (_encodedBytes == null) - { - return other._encodedBytes == null; - } - - if (other._encodedBytes == null) - { - return false; - } - - if (_encodedBytes.Length != other._encodedBytes.Length) - { - return false; - } - - // If only one is a number, then they're not equal. - if (((_flags ^ other._flags) & _SmallFlags.IsInt64) == _SmallFlags.IsInt64) - { - return false; - } - - if (_HasCachedHashCode && other._HasCachedHashCode) - { - if (_cachedHashCode != other._cachedHashCode) - { - return false; - } - } - - if (_IsInt64) - { - return BitConverter.ToInt64(_encodedBytes, 0) == BitConverter.ToInt64(other._encodedBytes, 0); - } - - // Note that this is doing a literal binary comparison of the two strings. - // It's possible for two real strings to compare equally even though they - // can be encoded in different ways with UTF8. - return Utility.MemCmp(_encodedBytes, other._encodedBytes, _encodedBytes.Length); - } - - #endregion - - public string GetString() - { - if (_encodedBytes == null) - { - return ""; - } - - if (_IsInt64) - { - return BitConverter.ToInt64(_encodedBytes, 0).ToString(); - } - - return s_Encoder.GetString(_encodedBytes); - } - - public static bool operator==(SmallString left, SmallString right) - { - return left.Equals(right); - } - - public static bool operator!=(SmallString left, SmallString right) - { - return !left.Equals(right); - } - - #region IComparable Members - - public int CompareTo(SmallString other) - { - // If either of the strings contains multibyte characters - // then we can't do a strictly bitwise comparison. - // We can look for a signaled high-bit in the byte to detect this. - // Opportunistically, we're going to assume that the strings are - // ASCII compatible until we find out they aren't. - - if (_encodedBytes == null) - { - if (other._encodedBytes == null) - { - return 0; - } - Assert.AreNotEqual(0, other._encodedBytes.Length); - return -1; - } - else if (other._encodedBytes == null) - { - Assert.AreNotEqual(0, _encodedBytes.Length); - return 1; - } - - bool? isThisStringShorter = null; - int cb = _encodedBytes.Length; - int cbDiffernce = other._encodedBytes.Length - cb; - - if (cbDiffernce < 0) - { - isThisStringShorter = false; - cb = other._encodedBytes.Length; - } - else if (cbDiffernce > 0) - { - isThisStringShorter = true; - } - - for (int i = 0; i < cb; ++i) - { - bool isEitherHighBitSet = ((_encodedBytes[i] | other._encodedBytes[i]) & 0x80) != 0; - // If the byte array contains multibyte characters - // we need to do a real string comparison. - if (isEitherHighBitSet) - { - string left = this.GetString(); - string right = other.GetString(); - - return left.CompareTo(right); - } - - if (_encodedBytes[i] != other._encodedBytes[i]) - { - return _encodedBytes[i] - other._encodedBytes[i]; - } - } - - if (isThisStringShorter == null) - { - return 0; - } - - if (isThisStringShorter == false) - { - return -1; - } - - return 1; - } - - #endregion - } -} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/Standard/SmallUri.cs b/Microsoft.Windows.Shell/Standard/SmallUri.cs deleted file mode 100644 index 4a3c350..0000000 --- a/Microsoft.Windows.Shell/Standard/SmallUri.cs +++ /dev/null @@ -1,151 +0,0 @@ - -namespace Standard -{ - using System; - using System.Diagnostics; - using System.Text; - - [DebuggerDisplay("SmallUri: { GetUri() }")] - internal struct SmallUri : IEquatable - { - private static readonly UTF8Encoding s_Encoder = new UTF8Encoding(false /* do not emit BOM */, true /* throw on error */); - private readonly byte[] _utf8String; - private readonly bool _isHttp; - - public SmallUri(Uri value) - { - _isHttp = false; - _utf8String = null; - - if (value == null) - { - return; - } - - if (!value.IsAbsoluteUri) - { - throw new ArgumentException("The parameter is not a valid absolute uri", "value"); - } - - string strValue = value.OriginalString; - if (strValue.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) - { - _isHttp = true; - strValue = strValue.Substring(7); - } - - _utf8String = s_Encoder.GetBytes(strValue); - Assert.IsNotNull(_utf8String); - } - - public SmallUri(string value) - { - _isHttp = false; - _utf8String = null; - - if (string.IsNullOrEmpty(value)) - { - return; - } - - if (!Uri.IsWellFormedUriString(value, UriKind.Absolute)) - { - throw new ArgumentException("The parameter is not a valid uri", "value"); - } - - if (value.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) - { - _isHttp = true; - value = value.Substring(7); - } - - _utf8String = s_Encoder.GetBytes(value); - Assert.IsNotNull(_utf8String); - } - - #region Object Overrides - - public override string ToString() - { - Assert.Fail(); - throw new NotSupportedException("This exception exists to prevent accidental performance penalties. Call GetString() instead."); - } - - public override int GetHashCode() - { - // Intentionally hashes similarly to the expanded strings. - return GetString().GetHashCode(); - } - - public override bool Equals(object obj) - { - try - { - return Equals((SmallUri)obj); - } - catch (InvalidCastException) - { - return false; - } - } - - #endregion - - #region IEquatable Members - - public bool Equals(SmallUri other) - { - if (_utf8String == null) - { - return other._utf8String == null; - } - - if (other._utf8String == null) - { - return false; - } - - if (_isHttp != other._isHttp) - { - return false; - } - - if (_utf8String.Length != other._utf8String.Length) - { - return false; - } - - return Utility.MemCmp(_utf8String, other._utf8String, _utf8String.Length); - } - - #endregion - - public string GetString() - { - if (_utf8String == null) - { - return ""; - } - return GetUri().ToString(); - } - - public Uri GetUri() - { - if (_utf8String == null) - { - return null; - } - return new Uri((_isHttp ? "http://" : "") + s_Encoder.GetString(_utf8String), UriKind.Absolute); - } - - public static bool operator ==(SmallUri left, SmallUri right) - { - return left.Equals(right); - } - - public static bool operator !=(SmallUri left, SmallUri right) - { - return !left.Equals(right); - } - } -} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/Standard/Standard.csproj b/Microsoft.Windows.Shell/Standard/Standard.csproj deleted file mode 100644 index fba179b..0000000 --- a/Microsoft.Windows.Shell/Standard/Standard.csproj +++ /dev/null @@ -1,162 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {A1326555-AD64-4A93-A95C-B68ABD5672D4} - Library - Properties - Standard - Standard - v4.0 - 512 - - - - - - - - - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - Client - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - AllRules.ruleset - - - true - bin\x86\Debug\ - DEBUG;TRACE - full - x86 - true - GlobalSuppressions.cs - prompt - true - AllRules.ruleset - - - bin\x86\Release\ - TRACE - true - pdbonly - x86 - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - - - - 3.0 - - - 3.0 - - - - 3.5 - - - - 3.5 - - - 3.5 - - - - - 3.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - - - \ No newline at end of file diff --git a/Microsoft.Windows.Shell/Standard/StreamHelper.cs b/Microsoft.Windows.Shell/Standard/StreamHelper.cs deleted file mode 100644 index 2885963..0000000 --- a/Microsoft.Windows.Shell/Standard/StreamHelper.cs +++ /dev/null @@ -1,713 +0,0 @@ -// The ComStream class is used for the contact property types. -// The types can have unexpected behavior if they're changed by callers, -// so this provides an immutable stream implementation. -// The volatile functions are implemented (not tested) -// in case a separate ReadonlyStream needs to be implemented. -//#define FEATURE_MUTABLE_COM_STREAMS - -namespace Standard -{ - using System; - using System.Diagnostics.CodeAnalysis; - using System.IO; - using System.Runtime.InteropServices; - using System.Runtime.InteropServices.ComTypes; - - // disambiguate with System.Runtime.InteropServices.STATSTG - using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG; - - // This is adapted from Microsoft KB article 321340 - /// - /// Wraps an IStream interface pointer from COM into a form consumable by .Net. - /// - /// - /// This implementation is immutable, though it's possible that the underlying - /// stream can be changed in another context. - /// - [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] - internal sealed class ComStream : Stream - { - private const int STATFLAG_NONAME = 1; - - private IStream _source; - - private void _Validate() - { - if (null == _source) - { - throw new ObjectDisposedException("this"); - } - } - - /// - /// Wraps a native IStream interface into a CLR Stream subclass. - /// - /// - /// The stream that this object wraps. - /// - /// - /// Note that the parameter is passed by ref. On successful creation it is - /// zeroed out to the caller. This object becomes responsible for the lifetime - /// management of the wrapped IStream. - /// - public ComStream(ref IStream stream) - { - Verify.IsNotNull(stream, "stream"); - _source = stream; - // Zero out caller's reference to this. The object now owns the memory. - stream = null; - } - - #region Overridden Stream Methods - - // Experimentally, the base class seems to deal with the IDisposable pattern. - // Overridden implementations aren't called, but Close is as part of the Dispose call. - public override void Close() - { - if (null != _source) - { -#if FEATURE_MUTABLE_COM_STREAMS - Flush(); -#endif - Utility.SafeRelease(ref _source); - } - } - - public override bool CanRead - { - get - { - // For the context of this class, this should be true... - return true; - } - } - - public override bool CanSeek - { - get - { - // This should be true... - return true; - } - } - - public override bool CanWrite - { - get - { -#if FEATURE_MUTABLE_COM_STREAMS - // Really don't know that this is true... - return true; -#endif - return false; - } - } - - public override void Flush() - { -#if FEATURE_MUTABLE_COM_STREAMS - _Validate(); - // Don't have enough context of the underlying object to reliably do anything here. - try - { - _source.Commit(STGC_DEFAULT); - } - catch { } -#endif - } - - public override long Length - { - get - { - _Validate(); - - STATSTG statstg; - _source.Stat(out statstg, STATFLAG_NONAME); - return statstg.cbSize; - } - } - - public override long Position - { - get { return Seek(0, SeekOrigin.Current); } - set { Seek(value, SeekOrigin.Begin); } - } - - public override int Read(byte[] buffer, int offset, int count) - { - _Validate(); - - IntPtr pcbRead = IntPtr.Zero; - - try - { - pcbRead = Marshal.AllocHGlobal(sizeof(Int32)); - - // PERFORMANCE NOTE: This buffer doesn't need to be allocated if offset == 0 - var tempBuffer = new byte[count]; - _source.Read(tempBuffer, count, pcbRead); - Array.Copy(tempBuffer, 0, buffer, offset, Marshal.ReadInt32(pcbRead)); - - return Marshal.ReadInt32(pcbRead); - } - finally - { - Utility.SafeFreeHGlobal(ref pcbRead); - } - } - - public override long Seek(long offset, SeekOrigin origin) - { - _Validate(); - - IntPtr plibNewPosition = IntPtr.Zero; - - try - { - plibNewPosition = Marshal.AllocHGlobal(sizeof(Int64)); - _source.Seek(offset, (int)origin, plibNewPosition); - - return Marshal.ReadInt64(plibNewPosition); - } - finally - { - Utility.SafeFreeHGlobal(ref plibNewPosition); - } - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); -#if FEATURE_MUTABLE_COM_STREAMS - _Validate(); - _source.SetSize(value); -#endif - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); -#if FEATURE_MUTABLE_COM_STREAMS - _Validate(); - - // PERFORMANCE NOTE: This buffer doesn't need to be allocated if offset == 0 - byte[] tempBuffer = new byte[buffer.Length - offset]; - Array.Copy(buffer, offset, tempBuffer, 0, tempBuffer.Length); - _source.Write(tempBuffer, tempBuffer.Length, IntPtr.Zero); -#endif - } - - #endregion - } - - // All these methods return void. Does the standard marshaller convert them to HRESULTs? - /// - /// Wraps a managed stream instance into an interface pointer consumable by COM. - /// - internal sealed class ManagedIStream : IStream, IDisposable - { - private const int STGTY_STREAM = 2; - private const int STGM_READWRITE = 2; - private const int LOCK_EXCLUSIVE = 2; - - private Stream _source; - - /// - /// Initializes a new instance of the ManagedIStream class with the specified managed Stream object. - /// - /// - /// The stream that this IStream reference is wrapping. - /// - public ManagedIStream(Stream source) - { - Verify.IsNotNull(source, "source"); - _source = source; - } - - private void _Validate() - { - if (null == _source) - { - throw new ObjectDisposedException("this"); - } - } - - // Comments are taken from MSDN IStream documentation. - #region IStream Members - - /// - /// Creates a new stream object with its own seek pointer that - /// references the same bytes as the original stream. - /// - /// - /// When this method returns, contains the new stream object. This parameter is passed uninitialized. - /// - /// - /// For more information, see the existing documentation for IStream::Clone in the MSDN library. - /// This class doesn't implement Clone. A COMException is thrown if it is used. - /// - [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)")] - [Obsolete("The method is not implemented", true)] - public void Clone(out IStream ppstm) - { - ppstm = null; - HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); - } - - /// - /// Ensures that any changes made to a stream object that is open in transacted - /// mode are reflected in the parent storage. - /// - /// - /// A value that controls how the changes for the stream object are committed. - /// - /// - /// For more information, see the existing documentation for IStream::Commit in the MSDN library. - /// - public void Commit(int grfCommitFlags) - { - _Validate(); - _source.Flush(); - } - - /// - /// Copies a specified number of bytes from the current seek pointer in the - /// stream to the current seek pointer in another stream. - /// - /// - /// A reference to the destination stream. - /// - /// - /// The number of bytes to copy from the source stream. - /// - /// - /// On successful return, contains the actual number of bytes read from the source. - /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written - /// to this parameter on success.) - /// - /// - /// On successful return, contains the actual number of bytes written to the destination. - /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written - /// to this parameter on success.) - /// - [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] - public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten) - { - Verify.IsNotNull(pstm, "pstm"); - - _Validate(); - - // Reasonbly sized buffer, don't try to copy large streams in bulk. - var buffer = new byte[4096]; - long cbWritten = 0; - - while (cbWritten < cb) - { - int cbRead = _source.Read(buffer, 0, buffer.Length); - if (0 == cbRead) - { - break; - } - - // COM documentation is a bit vague here whether NULL is valid for the third parameter. - // Going to assume it is, as most implementations I've seen treat it as optional. - // It's possible this will break on some IStream implementations. - pstm.Write(buffer, cbRead, IntPtr.Zero); - cbWritten += cbRead; - } - - if (IntPtr.Zero != pcbRead) - { - Marshal.WriteInt64(pcbRead, cbWritten); - } - - if (IntPtr.Zero != pcbWritten) - { - Marshal.WriteInt64(pcbWritten, cbWritten); - } - } - - /// - /// Restricts access to a specified range of bytes in the stream. - /// - /// - /// The byte offset for the beginning of the range. - /// - /// - /// The length of the range, in bytes, to restrict. - /// - /// - /// The requested restrictions on accessing the range. - /// - /// - /// For more information, see the existing documentation for IStream::LockRegion in the MSDN library. - /// This class doesn't implement LockRegion. A COMException is thrown if it is used. - /// - [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)"), Obsolete("The method is not implemented", true)] - public void LockRegion(long libOffset, long cb, int dwLockType) - { - HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); - } - - /// - /// Reads a specified number of bytes from the stream object into memory starting at the current seek pointer. - /// - /// - /// When this method returns, contains the data read from the stream. This parameter is passed uninitialized. - /// - /// - /// The number of bytes to read from the stream object. - /// - /// - /// A pointer to a ULONG variable that receives the actual number of bytes read from the stream object. - /// - /// - /// For more information, see the existing documentation for ISequentialStream::Read in the MSDN library. - /// - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] - public void Read(byte[] pv, int cb, IntPtr pcbRead) - { - _Validate(); - - int cbRead = _source.Read(pv, 0, cb); - - if (IntPtr.Zero != pcbRead) - { - Marshal.WriteInt32(pcbRead, cbRead); - } - } - - - /// - /// Discards all changes that have been made to a transacted stream since the last Commit call. - /// - /// - /// This class doesn't implement Revert. A COMException is thrown if it is used. - /// - [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)"), Obsolete("The method is not implemented", true)] - public void Revert() - { - HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); - } - - /// - /// Changes the seek pointer to a new location relative to the beginning of the - /// stream, to the end of the stream, or to the current seek pointer. - /// - /// - /// The displacement to add to dwOrigin. - /// - /// - /// The origin of the seek. The origin can be the beginning of the file, the current seek pointer, or the end of the file. - /// - /// - /// On successful return, contains the offset of the seek pointer from the beginning of the stream. - /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written - /// to this parameter on success.) - /// - /// - /// For more information, see the existing documentation for IStream::Seek in the MSDN library. - /// - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] - public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition) - { - _Validate(); - - long position = _source.Seek(dlibMove, (SeekOrigin)dwOrigin); - - if (IntPtr.Zero != plibNewPosition) - { - Marshal.WriteInt64(plibNewPosition, position); - } - } - - /// - /// Changes the size of the stream object. - /// - /// - /// The new size of the stream as a number of bytes. - /// - /// - /// For more information, see the existing documentation for IStream::SetSize in the MSDN library. - /// - public void SetSize(long libNewSize) - { - _Validate(); - _source.SetLength(libNewSize); - } - - /// - /// Retrieves the STATSTG structure for this stream. - /// - /// - /// When this method returns, contains a STATSTG structure that describes this stream object. - /// This parameter is passed uninitialized. - /// - /// - /// Members in the STATSTG structure that this method does not return, thus saving some memory allocation operations. - /// - public void Stat(out STATSTG pstatstg, int grfStatFlag) - { - pstatstg = default(STATSTG); - _Validate(); - - pstatstg.type = STGTY_STREAM; - pstatstg.cbSize = _source.Length; - pstatstg.grfMode = STGM_READWRITE; - pstatstg.grfLocksSupported = LOCK_EXCLUSIVE; - } - - /// - /// Removes the access restriction on a range of bytes previously restricted with the LockRegion method. - /// - /// The byte offset for the beginning of the range. - /// - /// - /// The length, in bytes, of the range to restrict. - /// - /// - /// The access restrictions previously placed on the range. - /// - /// - /// For more information, see the existing documentation for IStream::UnlockRegion in the MSDN library. - /// This class doesn't implement UnlockRegion. A COMException is thrown if it is used. - /// - [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)")] - [Obsolete("The method is not implemented", true)] - public void UnlockRegion(long libOffset, long cb, int dwLockType) - { - HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); - } - - /// - /// Writes a specified number of bytes into the stream object starting at the current seek pointer. - /// - /// - /// The buffer to write this stream to. - /// - /// - /// The number of bytes to write to the stream. - /// - /// - /// On successful return, contains the actual number of bytes written to the stream object. - /// If the caller sets this pointer to null, this method does not provide the actual number - /// of bytes written. - /// - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] - public void Write(byte[] pv, int cb, IntPtr pcbWritten) - { - _Validate(); - - _source.Write(pv, 0, cb); - - if (IntPtr.Zero != pcbWritten) - { - Marshal.WriteInt32(pcbWritten, cb); - } - } - - #endregion - - #region IDisposable Members - - /// - /// Releases resources controlled by this object. - /// - /// - /// Dispose can be called multiple times, but trying to use the object - /// after it has been disposed will generally throw ObjectDisposedExceptions. - /// - public void Dispose() - { - _source = null; - } - - #endregion - } - -#if CONSIDER_ADDING - /// - /// Wraps an existing stream in a read-only interface. The stream can still be modified externally. - /// - public class ReadonlyStream : Stream - { - private Stream _stream; - - public ReadonlyStream(Stream source) - { - Verify.IsNotNull(source, "source"); - _stream = source; - } - - public override bool CanRead - { - get - { - return _stream.CanRead; - } - } - - public override bool CanSeek - { - get - { - return _stream.CanSeek; - } - } - - public override bool CanWrite - { - get - { - return false; - } - } - - public override void Flush() { } - - public override long Length - { - get - { - return _stream.Length; - } - } - - public override long Position - { - get - { - return _stream.Position; - } - set - { - _stream.Position = value; - } - } - - public override int Read(byte[] buffer, int offset, int count) - { - return _stream.Read(buffer, offset, count); - } - - public override long Seek(long offset, SeekOrigin origin) - { - return _stream.Seek(offset, origin); - } - - public override void SetLength(long value) - { - throw new NotSupportedException("The stream doesn't support modifications."); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException("The stream doesn't support modifications."); - } - - public override void Close() - { - base.Close(); - } - } - - /// - /// Wraps a string to provide read-only Stream semantics. - /// - public class StringStream : Stream - { - private string _source; - private int _position; - - public StringStream(string source) - { - _source = source; - _position = 0; - } - - public override bool CanRead - { - get { return true; } - } - - public override bool CanSeek - { - get { return true; } - } - - public override bool CanWrite - { - get { return false; } - } - - public override void Flush() - { - throw new NotSupportedException(); - } - - public override long Length - { - get { return _source.Length * 2; } - } - - public override long Position - { - get - { - return _position; - } - set - { - Validate.BoundedInteger(0, (int)value, (int)Length + 1, "value"); - _position = (int)value; - } - } - - public override int Read(byte[] buffer, int offset, int count) - { - int cbRead = 0; - for (; cbRead < count; ++cbRead) - { - if (Length <= Position) - { - break; - } - buffer[offset + cbRead] = (byte)(0xFF & (_source[(int)Position / 2] >> ((0 == Position % 2) ? 0 : 8))); - ++Position; - } - return cbRead; - } - - public override long Seek(long offset, SeekOrigin origin) - { - switch (origin) - { - case SeekOrigin.Begin: - Position = offset; - break; - case SeekOrigin.Current: - Position += offset; - break; - case SeekOrigin.End: - Position = Length + offset; - break; - default: - throw new FormatException("Bad value for origin"); - } - return Position; - } - - public override void SetLength(long value) - { - throw new NotSupportedException(); - } - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - } -#endif -} diff --git a/Microsoft.Windows.Shell/Standard/Utilities.cs b/Microsoft.Windows.Shell/Standard/Utilities.cs deleted file mode 100644 index 6791f68..0000000 --- a/Microsoft.Windows.Shell/Standard/Utilities.cs +++ /dev/null @@ -1,921 +0,0 @@ -// This file contains general utilities to aid in development. -// Classes here generally shouldn't be exposed publicly since -// they're not particular to any library functionality. -// Because the classes here are internal, it's likely this file -// might be included in multiple assemblies. -namespace Standard -{ - using System; - using System.Collections.Generic; - using System.ComponentModel; - using System.Diagnostics.CodeAnalysis; - using System.Globalization; - using System.IO; - using System.Linq; - using System.Reflection; - using System.Runtime.InteropServices; - using System.Security.Cryptography; - using System.Text; - - internal enum SafeCopyFileOptions - { - PreserveOriginal, - Overwrite, - FindBetterName, - } - - internal static partial class Utility - { - private static readonly Version _osVersion = Environment.OSVersion.Version; - private static readonly Random _randomNumberGenerator = new Random(); - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - private static bool _MemCmp(IntPtr left, IntPtr right, long cb) - { - int offset = 0; - - for (; offset < (cb - sizeof(Int64)); offset += sizeof(Int64)) - { - Int64 left64 = Marshal.ReadInt64(left, offset); - Int64 right64 = Marshal.ReadInt64(right, offset); - - if (left64 != right64) - { - return false; - } - } - - for (; offset < cb; offset += sizeof(byte)) - { - byte left8 = Marshal.ReadByte(left, offset); - byte right8 = Marshal.ReadByte(right, offset); - - if (left8 != right8) - { - return false; - } - } - - return true; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static Exception FailableFunction(Func function, out T result) - { - return FailableFunction(5, function, out result); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static T FailableFunction(Func function) - { - T result; - Exception e = FailableFunction(function, out result); - if (e != null) - { - throw e; - } - return result; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static T FailableFunction(int maxRetries, Func function) - { - T result; - Exception e = FailableFunction(maxRetries, function, out result); - if (e != null) - { - throw e; - } - return result; - } - - [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static Exception FailableFunction(int maxRetries, Func function, out T result) - { - Assert.IsNotNull(function); - Assert.BoundedInteger(1, maxRetries, 100); - int i = 0; - while (true) - { - try - { - result = function(); - return null; - } - catch (Exception e) - { - if (i == maxRetries) - { - result = default(T); - return e; - } - } - ++i; - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static string GetHashString(string value) - { - using (MD5 md5 = MD5.Create()) - { - byte[] signatureHash = md5.ComputeHash(Encoding.UTF8.GetBytes(value)); - string signature = signatureHash.Aggregate( - new StringBuilder(), - (sb, b) => sb.Append(b.ToString("x2", CultureInfo.InvariantCulture))).ToString(); - return signature; - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static int GET_X_LPARAM(IntPtr lParam) - { - return LOWORD(lParam.ToInt32()); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static int GET_Y_LPARAM(IntPtr lParam) - { - return HIWORD(lParam.ToInt32()); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static int HIWORD(int i) - { - return (short)(i >> 16); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static int LOWORD(int i) - { - return (short)(i & 0xFFFF); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] - public static bool AreStreamsEqual(Stream left, Stream right) - { - if (null == left) - { - return right == null; - } - if (null == right) - { - return false; - } - - if (!left.CanRead || !right.CanRead) - { - throw new NotSupportedException("The streams can't be read for comparison"); - } - - if (left.Length != right.Length) - { - return false; - } - - var length = (int)left.Length; - - // seek to beginning - left.Position = 0; - right.Position = 0; - - // total bytes read - int totalReadLeft = 0; - int totalReadRight = 0; - - // bytes read on this iteration - int cbReadLeft = 0; - int cbReadRight = 0; - - // where to store the read data - var leftBuffer = new byte[512]; - var rightBuffer = new byte[512]; - - // pin the left buffer - GCHandle handleLeft = GCHandle.Alloc(leftBuffer, GCHandleType.Pinned); - IntPtr ptrLeft = handleLeft.AddrOfPinnedObject(); - - // pin the right buffer - GCHandle handleRight = GCHandle.Alloc(rightBuffer, GCHandleType.Pinned); - IntPtr ptrRight = handleRight.AddrOfPinnedObject(); - - try - { - while (totalReadLeft < length) - { - Assert.AreEqual(totalReadLeft, totalReadRight); - - cbReadLeft = left.Read(leftBuffer, 0, leftBuffer.Length); - cbReadRight = right.Read(rightBuffer, 0, rightBuffer.Length); - - // verify the contents are an exact match - if (cbReadLeft != cbReadRight) - { - return false; - } - - if (!_MemCmp(ptrLeft, ptrRight, cbReadLeft)) - { - return false; - } - - totalReadLeft += cbReadLeft; - totalReadRight += cbReadRight; - } - - Assert.AreEqual(cbReadLeft, cbReadRight); - Assert.AreEqual(totalReadLeft, totalReadRight); - Assert.AreEqual(length, totalReadLeft); - - return true; - } - finally - { - handleLeft.Free(); - handleRight.Free(); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool GuidTryParse(string guidString, out Guid guid) - { - Verify.IsNeitherNullNorEmpty(guidString, "guidString"); - - try - { - guid = new Guid(guidString); - return true; - } - catch (FormatException) - { - } - catch (OverflowException) - { - } - // Doesn't seem to be a valid guid. - guid = default(Guid); - return false; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool IsFlagSet(int value, int mask) - { - return 0 != (value & mask); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool IsFlagSet(uint value, uint mask) - { - return 0 != (value & mask); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool IsFlagSet(long value, long mask) - { - return 0 != (value & mask); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool IsFlagSet(ulong value, ulong mask) - { - return 0 != (value & mask); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool IsInterfaceImplemented(Type objectType, Type interfaceType) - { - Assert.IsNotNull(objectType); - Assert.IsNotNull(interfaceType); - Assert.IsTrue(interfaceType.IsInterface); - - return objectType.GetInterfaces().Any(type => type == interfaceType); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool IsOSVistaOrNewer - { - get { return _osVersion >= new Version(6, 0); } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool IsOSWindows7OrNewer - { - get { return _osVersion >= new Version(6, 1); } - } - - /// - /// Wrapper around File.Copy to provide feedback as to whether the file wasn't copied because it didn't exist. - /// - /// - /// - /// - /// - public static string SafeCopyFile(string sourceFileName, string destFileName, SafeCopyFileOptions options) - { - switch (options) - { - case SafeCopyFileOptions.PreserveOriginal: - if (!File.Exists(destFileName)) - { - File.Copy(sourceFileName, destFileName); - return destFileName; - } - return null; - case SafeCopyFileOptions.Overwrite: - File.Copy(sourceFileName, destFileName, true); - return destFileName; - case SafeCopyFileOptions.FindBetterName: - string directoryPart = Path.GetDirectoryName(destFileName); - string fileNamePart = Path.GetFileNameWithoutExtension(destFileName); - string extensionPart = Path.GetExtension(destFileName); - foreach (string path in GenerateFileNames(directoryPart, fileNamePart, extensionPart)) - { - if (!File.Exists(path)) - { - File.Copy(sourceFileName, path); - return path; - } - } - return null; - } - throw new ArgumentException("Invalid enumeration value", "options"); - } - - /// - /// Simple guard against the exceptions that File.Delete throws on null and empty strings. - /// - /// The path to delete. Unlike File.Delete, this can be null or empty. - /// - /// Note that File.Delete, and by extension SafeDeleteFile, does not throw an exception - /// if the file does not exist. - /// - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SafeDeleteFile(string path) - { - if (!string.IsNullOrEmpty(path)) - { - File.Delete(path); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SafeDestroyIcon(ref IntPtr hicon) - { - IntPtr p = hicon; - hicon = IntPtr.Zero; - if (IntPtr.Zero != p) - { - NativeMethods.DestroyIcon(p); - } - } - - /// GDI's DeleteObject - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SafeDeleteObject(ref IntPtr gdiObject) - { - IntPtr p = gdiObject; - gdiObject = IntPtr.Zero; - if (IntPtr.Zero != p) - { - NativeMethods.DeleteObject(p); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SafeDestroyWindow(ref IntPtr hwnd) - { - IntPtr p = hwnd; - hwnd = IntPtr.Zero; - if (NativeMethods.IsWindow(p)) - { - NativeMethods.DestroyWindow(p); - } - } - - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SafeDispose(ref T disposable) where T : IDisposable - { - // Dispose can safely be called on an object multiple times. - IDisposable t = disposable; - disposable = default(T); - if (null != t) - { - t.Dispose(); - } - } - - /// GDI+'s DisposeImage - /// - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SafeDisposeImage(ref IntPtr gdipImage) - { - IntPtr p = gdipImage; - gdipImage = IntPtr.Zero; - if (IntPtr.Zero != p) - { - NativeMethods.GdipDisposeImage(p); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] - public static void SafeCoTaskMemFree(ref IntPtr ptr) - { - IntPtr p = ptr; - ptr = IntPtr.Zero; - if (IntPtr.Zero != p) - { - Marshal.FreeCoTaskMem(p); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] - public static void SafeFreeHGlobal(ref IntPtr hglobal) - { - IntPtr p = hglobal; - hglobal = IntPtr.Zero; - if (IntPtr.Zero != p) - { - Marshal.FreeHGlobal(p); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] - public static void SafeRelease(ref T comObject) where T : class - { - T t = comObject; - comObject = default(T); - if (null != t) - { - Assert.IsTrue(Marshal.IsComObject(t)); - Marshal.ReleaseComObject(t); - } - } - - /// - /// Utility to help classes catenate their properties for implementing ToString(). - /// - /// The StringBuilder to catenate the results into. - /// The name of the property to be catenated. - /// The value of the property to be catenated. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void GeneratePropertyString(StringBuilder source, string propertyName, string value) - { - Assert.IsNotNull(source); - Assert.IsFalse(string.IsNullOrEmpty(propertyName)); - - if (0 != source.Length) - { - source.Append(' '); - } - - source.Append(propertyName); - source.Append(": "); - if (string.IsNullOrEmpty(value)) - { - source.Append(""); - } - else - { - source.Append('\"'); - source.Append(value); - source.Append('\"'); - } - } - - /// - /// Generates ToString functionality for a struct. This is an expensive way to do it, - /// it exists for the sake of debugging while classes are in flux. - /// Eventually this should just be removed and the classes should - /// do this without reflection. - /// - /// - /// - /// - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [Obsolete] - public static string GenerateToString(T @object) where T : struct - { - var sbRet = new StringBuilder(); - foreach (PropertyInfo property in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)) - { - if (0 != sbRet.Length) - { - sbRet.Append(", "); - } - Assert.AreEqual(0, property.GetIndexParameters().Length); - object value = property.GetValue(@object, null); - string format = null == value ? "{0}: " : "{0}: \"{1}\""; - sbRet.AppendFormat(format, property.Name, value); - } - return sbRet.ToString(); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void CopyStream(Stream destination, Stream source) - { - Assert.IsNotNull(source); - Assert.IsNotNull(destination); - - destination.Position = 0; - - // If we're copying from, say, a web stream, don't fail because of this. - if (source.CanSeek) - { - source.Position = 0; - - // Consider that this could throw because - // the source stream doesn't know it's size... - destination.SetLength(source.Length); - } - - var buffer = new byte[4096]; - int cbRead; - - do - { - cbRead = source.Read(buffer, 0, buffer.Length); - if (0 != cbRead) - { - destination.Write(buffer, 0, cbRead); - } - } - while (buffer.Length == cbRead); - - // Reset the Seek pointer before returning. - destination.Position = 0; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static string HashStreamMD5(Stream stm) - { - stm.Position = 0; - var hashBuilder = new StringBuilder(); - using (MD5 md5 = MD5.Create()) - { - foreach (byte b in md5.ComputeHash(stm)) - { - hashBuilder.Append(b.ToString("x2", CultureInfo.InvariantCulture)); - } - } - - return hashBuilder.ToString(); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void EnsureDirectory(string path) - { - if (!path.EndsWith(@"\")) - { - path += @"\"; - } - - path = Path.GetDirectoryName(path); - - if (!Directory.Exists(path)) - { - Directory.CreateDirectory(path); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool MemCmp(byte[] left, byte[] right, int cb) - { - Assert.IsNotNull(left); - Assert.IsNotNull(right); - - Assert.IsTrue(cb <= Math.Min(left.Length, right.Length)); - - // pin this buffer - GCHandle handleLeft = GCHandle.Alloc(left, GCHandleType.Pinned); - IntPtr ptrLeft = handleLeft.AddrOfPinnedObject(); - - // pin the other buffer - GCHandle handleRight = GCHandle.Alloc(right, GCHandleType.Pinned); - IntPtr ptrRight = handleRight.AddrOfPinnedObject(); - - bool fRet = _MemCmp(ptrLeft, ptrRight, cb); - - handleLeft.Free(); - handleRight.Free(); - - return fRet; - } - - private class _UrlDecoder - { - private readonly Encoding _encoding; - private readonly char[] _charBuffer; - private readonly byte[] _byteBuffer; - private int _byteCount; - private int _charCount; - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public _UrlDecoder(int size, Encoding encoding) - { - _encoding = encoding; - _charBuffer = new char[size]; - _byteBuffer = new byte[size]; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public void AddByte(byte b) - { - _byteBuffer[_byteCount++] = b; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public void AddChar(char ch) - { - _FlushBytes(); - _charBuffer[_charCount++] = ch; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - private void _FlushBytes() - { - if (_byteCount > 0) - { - _charCount += _encoding.GetChars(_byteBuffer, 0, _byteCount, _charBuffer, _charCount); - _byteCount = 0; - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public string GetString() - { - _FlushBytes(); - if (_charCount > 0) - { - return new string(_charBuffer, 0, _charCount); - } - return ""; - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static string UrlDecode(string url) - { - if (url == null) - { - return null; - } - - var decoder = new _UrlDecoder(url.Length, Encoding.UTF8); - int length = url.Length; - for (int i = 0; i < length; ++i) - { - char ch = url[i]; - - if (ch == '+') - { - decoder.AddByte((byte)' '); - continue; - } - - if (ch == '%' && i < length - 2) - { - // decode %uXXXX into a Unicode character. - if (url[i + 1] == 'u' && i < length - 5) - { - int a = _HexToInt(url[i + 2]); - int b = _HexToInt(url[i + 3]); - int c = _HexToInt(url[i + 4]); - int d = _HexToInt(url[i + 5]); - if (a >= 0 && b >= 0 && c >= 0 && d >= 0) - { - decoder.AddChar((char)((a << 12) | (b << 8) | (c << 4) | d)); - i += 5; - - continue; - } - } - else - { - // decode %XX into a Unicode character. - int a = _HexToInt(url[i + 1]); - int b = _HexToInt(url[i + 2]); - - if (a >= 0 && b >= 0) - { - decoder.AddByte((byte)((a << 4) | b)); - i += 2; - - continue; - } - } - } - - // Add any 7bit character as a byte. - if ((ch & 0xFF80) == 0) - { - decoder.AddByte((byte)ch); - } - else - { - decoder.AddChar(ch); - } - } - - return decoder.GetString(); - } - - /// - /// Encodes a URL string. Duplicated functionality from System.Web.HttpUtility.UrlEncode. - /// - /// - /// - /// - /// Duplicated from System.Web.HttpUtility because System.Web isn't part of the client profile. - /// URL Encoding replaces ' ' with '+' and unsafe ASCII characters with '%XX'. - /// Safe characters are defined in RFC2396 (http://www.ietf.org/rfc/rfc2396.txt). - /// They are the 7-bit ASCII alphanumerics and the mark characters "-_.!~*'()". - /// This implementation does not treat '~' as a safe character to be consistent with the System.Web version. - /// - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static string UrlEncode(string url) - { - if (url == null) - { - return null; - } - - byte[] bytes = Encoding.UTF8.GetBytes(url); - - bool needsEncoding = false; - int unsafeCharCount = 0; - foreach (byte b in bytes) - { - if (b == ' ') - { - needsEncoding = true; - } - else if (!_UrlEncodeIsSafe(b)) - { - ++unsafeCharCount; - needsEncoding = true; - } - } - - if (needsEncoding) - { - var buffer = new byte[bytes.Length + (unsafeCharCount * 2)]; - int writeIndex = 0; - foreach (byte b in bytes) - { - if (_UrlEncodeIsSafe(b)) - { - buffer[writeIndex++] = b; - } - else if (b == ' ') - { - buffer[writeIndex++] = (byte)'+'; - } - else - { - buffer[writeIndex++] = (byte)'%'; - buffer[writeIndex++] = _IntToHex((b >> 4) & 0xF); - buffer[writeIndex++] = _IntToHex(b & 0xF); - } - } - bytes = buffer; - Assert.AreEqual(buffer.Length, writeIndex); - } - - return Encoding.ASCII.GetString(bytes); - } - - // HttpUtility's UrlEncode is slightly different from the RFC. - // RFC2396 describes unreserved characters as alphanumeric or - // the list "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" - // The System.Web version unnecessarily escapes '~', which should be okay... - // Keeping that same pattern here just to be consistent. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - private static bool _UrlEncodeIsSafe(byte b) - { - if (_IsAsciiAlphaNumeric(b)) - { - return true; - } - - switch ((char)b) - { - case '-': - case '_': - case '.': - case '!': - //case '~': - case '*': - case '\'': - case '(': - case ')': - return true; - } - - return false; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - private static bool _IsAsciiAlphaNumeric(byte b) - { - return (b >= 'a' && b <= 'z') - || (b >= 'A' && b <= 'Z') - || (b >= '0' && b <= '9'); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - private static byte _IntToHex(int n) - { - Assert.BoundedInteger(0, n, 16); - if (n <= 9) - { - return (byte)(n + '0'); - } - return (byte)(n - 10 + 'A'); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - private static int _HexToInt(char h) - { - if (h >= '0' && h <= '9') - { - return h - '0'; - } - - if (h >= 'a' && h <= 'f') - { - return h - 'a' + 10; - } - - if (h >= 'A' && h <= 'F') - { - return h - 'A' + 10; - } - - Assert.Fail("Invalid hex character " + h); - return -1; - } - - public static string MakeValidFileName(string invalidPath) - { - return invalidPath - .Replace('\\', '_') - .Replace('/', '_') - .Replace(':', '_') - .Replace('*', '_') - .Replace('?', '_') - .Replace('\"', '_') - .Replace('<', '_') - .Replace('>', '_') - .Replace('|', '_'); - } - - public static IEnumerable GenerateFileNames(string directory, string primaryFileName, string extension) - { - Verify.IsNeitherNullNorEmpty(directory, "directory"); - Verify.IsNeitherNullNorEmpty(primaryFileName, "primaryFileName"); - - primaryFileName = MakeValidFileName(primaryFileName); - - for (int i = 0; i <= 50; ++i) - { - if (0 == i) - { - yield return Path.Combine(directory, primaryFileName) + extension; - } - else if (40 >= i) - { - yield return Path.Combine(directory, primaryFileName) + " (" + i.ToString((IFormatProvider)null) + ")" + extension; - } - else - { - // At this point we're hitting pathological cases. This should stir things up enough that it works. - // If this fails because of naming conflicts after an extra 10 tries, then I don't care. - yield return Path.Combine(directory, primaryFileName) + " (" + _randomNumberGenerator.Next(41, 9999) + ")" + extension; - } - } - } - - public static bool TryFileMove(string sourceFileName, string destFileName) - { - if (!File.Exists(destFileName)) - { - try - { - File.Move(sourceFileName, destFileName); - } - catch (IOException) - { - return false; - } - return true; - } - return false; - } - } -} diff --git a/Microsoft.Windows.Shell/Standard/Verify.cs b/Microsoft.Windows.Shell/Standard/Verify.cs deleted file mode 100644 index a6367ff..0000000 --- a/Microsoft.Windows.Shell/Standard/Verify.cs +++ /dev/null @@ -1,341 +0,0 @@ -// This file contains general utilities to aid in development. -// Classes here generally shouldn't be exposed publicly since -// they're not particular to any library functionality. -// Because the classes here are internal, it's likely this file -// might be included in multiple assemblies. -namespace Standard -{ - using System; - using System.Diagnostics; - using System.Diagnostics.CodeAnalysis; - using System.Globalization; - using System.IO; - using System.Threading; - - /// - /// A static class for retail validated assertions. - /// Instead of breaking into the debugger an exception is thrown. - /// - internal static class Verify - { - /// - /// Ensure that the current thread's apartment state is what's expected. - /// - /// - /// The required apartment state for the current thread. - /// - /// - /// The message string for the exception to be thrown if the state is invalid. - /// - /// - /// Thrown if the calling thread's apartment state is not the same as the requiredState. - /// - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void IsApartmentState(ApartmentState requiredState, string message) - { - if (Thread.CurrentThread.GetApartmentState() != requiredState) - { - Assert.Fail(); - throw new InvalidOperationException(message); - } - } - - /// - /// Ensure that an argument is neither null nor empty. - /// - /// The string to validate. - /// The name of the parameter that will be presented if an exception is thrown. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [SuppressMessage("Microsoft.Performance", "CA1820:TestForEmptyStringsUsingStringLength")] - [DebuggerStepThrough] - public static void IsNeitherNullNorEmpty(string value, string name) - { - // catch caller errors, mixing up the parameters. Name should never be empty. - Assert.IsNeitherNullNorEmpty(name); - - // Notice that ArgumentNullException and ArgumentException take the parameters in opposite order :P - const string errorMessage = "The parameter can not be either null or empty."; - if (null == value) - { - Assert.Fail(); - throw new ArgumentNullException(name, errorMessage); - } - if ("" == value) - { - Assert.Fail(); - throw new ArgumentException(errorMessage, name); - } - } - - /// - /// Ensure that an argument is neither null nor does it consist only of whitespace. - /// - /// The string to validate. - /// The name of the parameter that will be presented if an exception is thrown. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [SuppressMessage("Microsoft.Performance", "CA1820:TestForEmptyStringsUsingStringLength")] - [DebuggerStepThrough] - public static void IsNeitherNullNorWhitespace(string value, string name) - { - // catch caller errors, mixing up the parameters. Name should never be empty. - Assert.IsNeitherNullNorEmpty(name); - - // Notice that ArgumentNullException and ArgumentException take the parameters in opposite order :P - const string errorMessage = "The parameter can not be either null or empty or consist only of white space characters."; - if (null == value) - { - Assert.Fail(); - throw new ArgumentNullException(name, errorMessage); - } - if ("" == value.Trim()) - { - Assert.Fail(); - throw new ArgumentException(errorMessage, name); - } - } - - /// Verifies that an argument is not null. - /// Type of the object to validate. Must be a class. - /// The object to validate. - /// The name of the parameter that will be presented if an exception is thrown. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void IsNotDefault(T obj, string name) where T : struct - { - if (default(T).Equals(obj)) - { - Assert.Fail(); - throw new ArgumentException("The parameter must not be the default value.", name); - } - } - - /// Verifies that an argument is not null. - /// Type of the object to validate. Must be a class. - /// The object to validate. - /// The name of the parameter that will be presented if an exception is thrown. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void IsNotNull(T obj, string name) where T : class - { - if (null == obj) - { - Assert.Fail(); - throw new ArgumentNullException(name); - } - } - - /// Verifies that an argument is null. - /// Type of the object to validate. Must be a class. - /// The object to validate. - /// The name of the parameter that will be presented if an exception is thrown. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void IsNull(T obj, string name) where T : class - { - if (null != obj) - { - Assert.Fail(); - throw new ArgumentException("The parameter must be null.", name); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void PropertyIsNotNull(T obj, string name) where T : class - { - if (null == obj) - { - Assert.Fail(); - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The property {0} cannot be null at this time.", name)); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void PropertyIsNull(T obj, string name) where T : class - { - if (null != obj) - { - Assert.Fail(); - throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The property {0} must be null at this time.", name)); - } - } - - /// - /// Verifies the specified statement is true. Throws an ArgumentException if it's not. - /// - /// The statement to be verified as true. - /// Name of the parameter to include in the ArgumentException. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void IsTrue(bool statement, string name) - { - if (!statement) - { - Assert.Fail(); - throw new ArgumentException("", name); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void IsFalse(bool statement, string name) - { - if (statement) - { - Assert.Fail(); - throw new ArgumentException("", name); - } - } - - /// - /// Verifies the specified statement is true. Throws an ArgumentException if it's not. - /// - /// The statement to be verified as true. - /// Name of the parameter to include in the ArgumentException. - /// The message to include in the ArgumentException. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void IsTrue(bool statement, string name, string message) - { - if (!statement) - { - Assert.Fail(); - throw new ArgumentException(message, name); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void AreEqual(T expected, T actual, string parameterName, string message) - { - if (null == expected) - { - // Two nulls are considered equal, regardless of type semantics. - if (null != actual && !actual.Equals(expected)) - { - Assert.Fail(); - throw new ArgumentException(message, parameterName); - } - } - else if (!expected.Equals(actual)) - { - Assert.Fail(); - throw new ArgumentException(message, parameterName); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void AreNotEqual(T notExpected, T actual, string parameterName, string message) - { - if (null == notExpected) - { - // Two nulls are considered equal, regardless of type semantics. - if (null == actual || actual.Equals(notExpected)) - { - Assert.Fail(); - throw new ArgumentException(message, parameterName); - } - } - else if (notExpected.Equals(actual)) - { - Assert.Fail(); - throw new ArgumentException(message, parameterName); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void UriIsAbsolute(Uri uri, string parameterName) - { - Verify.IsNotNull(uri, parameterName); - if (!uri.IsAbsoluteUri) - { - Assert.Fail(); - throw new ArgumentException("The URI must be absolute.", parameterName); - } - } - - /// - /// Verifies that the specified value is within the expected range. The assertion fails if it isn't. - /// - /// The lower bound inclusive value. - /// The value to verify. - /// The upper bound exclusive value. - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void BoundedInteger(int lowerBoundInclusive, int value, int upperBoundExclusive, string parameterName) - { - if (value < lowerBoundInclusive || value >= upperBoundExclusive) - { - Assert.Fail(); - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The integer value must be bounded with [{0}, {1})", lowerBoundInclusive, upperBoundExclusive), parameterName); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void BoundedDoubleInc(double lowerBoundInclusive, double value, double upperBoundInclusive, string message, string parameter) - { - if (value < lowerBoundInclusive || value > upperBoundInclusive) - { - Assert.Fail(); - throw new ArgumentException(message, parameter); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void TypeSupportsInterface(Type type, Type interfaceType, string parameterName) - { - Assert.IsNeitherNullNorEmpty(parameterName); - Verify.IsNotNull(type, "type"); - Verify.IsNotNull(interfaceType, "interfaceType"); - - if (type.GetInterface(interfaceType.Name) == null) - { - Assert.Fail(); - throw new ArgumentException("The type of this parameter does not support a required interface", parameterName); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - public static void FileExists(string filePath, string parameterName) - { - Verify.IsNeitherNullNorEmpty(filePath, parameterName); - if (!File.Exists(filePath)) - { - Assert.Fail(); - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "No file exists at \"{0}\"", filePath), parameterName); - } - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - [DebuggerStepThrough] - internal static void ImplementsInterface(object parameter, Type interfaceType, string parameterName) - { - Assert.IsNotNull(parameter); - Assert.IsNotNull(interfaceType); - Assert.IsTrue(interfaceType.IsInterface); - - bool isImplemented = false; - foreach (var ifaceType in parameter.GetType().GetInterfaces()) - { - if (ifaceType == interfaceType) - { - isImplemented = true; - break; - } - } - - if (!isImplemented) - { - Assert.Fail(); - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The parameter must implement interface {0}.", interfaceType.ToString()), parameterName); - } - } - } -} diff --git a/Microsoft.Windows.Shell/Standard/WicProvider.cs b/Microsoft.Windows.Shell/Standard/WicProvider.cs deleted file mode 100644 index 94badb9..0000000 --- a/Microsoft.Windows.Shell/Standard/WicProvider.cs +++ /dev/null @@ -1,648 +0,0 @@ -// wincodec.idl -namespace Standard -{ - using System; - using System.Runtime.CompilerServices; - using System.Runtime.InteropServices; - using System.Runtime.InteropServices.ComTypes; - using System.Text; - - using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; - using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG; - - #region WIC Values - - internal static class WicValues - { - public const uint WINCODEC_SDK_VERSION = 0x0236; - public static readonly Guid GUID_VendorMicrosoft = new Guid(0xf0e749ca, 0xedef, 0x4589, 0xa7, 0x3a, 0xee, 0xe, 0x62, 0x6a, 0x2a, 0x2b); - } - - /// - /// GUID Identifiers for the image container formats - /// - internal static class WicGUID - { - /// GUID_ContainerFormatBmp - public const string ContainerFormatBmp = "0af1d87e-fcfe-4188-bdeb-a7906471cbe3"; - /// GUID_ContainerFormatPng - public const string ContainerFormatPng = "1b7cfaf4-713f-473c-bbcd-6137425faeaf"; - /// GUID_ContainerFormatIco - public const string ContainerFormatIco = "a3a860c4-338f-4c17-919a-fba4b5628f21"; - /// GUID_ContainerFormatJpeg - public const string ContainerFormatJpeg = "19e4a5aa-5662-4fc5-a0c0-1758028e1057"; - /// GUID_ContainerFormatTiff - public const string ContainerFormatTiff = "163bcc30-e2e9-4f0b-961d-a3e9fdb788a3"; - /// GUID_ContainerFormatGif - public const string ContainerFormatGif = "1f8a5601-7d4d-4cbd-9c82-1bc8d4eeb9a5"; - /// GUID_ContainerFormatWmp - public const string ContainerFormatWmp = "57a37caa-367a-4540-916b-f183c5093a4b"; - } - - /// - /// WIC Category Identifiers - /// - internal static class WicCATID - { - /// CATID_WICBitmapDecoders - public const string WICBitmapDecoders = "7ed96837-96f0-4812-b211-f13c24117ed3"; - /// CATID_WICBitmapEncoders - public const string WICBitmapEncoders = "ac757296-3522-4e11-9862-c17be5a1767e"; - /// CATID_WICPixelFormats - public const string WICPixelFormats = "2b46e70f-cda7-473e-89f6-dc9630a2390b"; - /// CATID_WICFormatConverters - public const string WICFormatConverters = "7835eae8-bf14-49d1-93ce-533a407b2248"; - /// CATID_WICMetadataReader - public const string WICMetadataReader = "05af94d8-7174-4cd2-be4a-4124b80ee4b8"; - /// CATID_WICMetadataWriter - public const string WICMetadataWriter = "abe3b9a4-257d-4b97-bd1a-294af496222e"; - } - - internal static class WicCLSID - { - #region (WIC) GUID identifiers for the codecs - - /// CLSID_WICBmpDecoder - public const string WICBmpDecoder = "6b462062-7cbf-400d-9fdb-813dd10f2778"; - /// CLSID_WICPngDecoder - public const string WICPngDecoder = "389ea17b-5078-4cde-b6ef-25c15175c751"; - /// CLSID_WICIcoDecoder - public const string WICIcoDecoder = "c61bfcdf-2e0f-4aad-a8d7-e06bafebcdfe"; - /// CLSID_WICJpegDecoder - public const string WICJpegDecoder = "9456a480-e88b-43ea-9e73-0b2d9b71b1ca"; - /// CLSID_WICGifDecoder - public const string WICGifDecoder = "381dda3c-9ce9-4834-a23e-1f98f8fc52be"; - /// CLSID_WICTiffDecoder - public const string WICTiffDecoder = "b54e85d9-fe23-499f-8b88-6acea713752b"; - /// CLSID_WICWmpDecoder - public const string WICWmpDecoder = "a26cec36-234c-4950-ae16-e34aace71d0d"; - - /// CLSID_WICBmpEncoder - public const string WICBmpEncoder = "69be8bb4-d66d-47c8-865a-ed1589433782"; - /// CLSID_WICPngEncoder - public const string WICPngEncoder = "27949969-876a-41d7-9447-568f6a35a4dc"; - /// CLSID_WICJpegEncoder - public const string WICJpegEncoder = "1a34f5c1-4a5a-46dc-b644-1f4567e7a676"; - /// CLSID_WICGifEncoder - public const string WICGifEncoder = "114f5598-0b22-40a0-86a1-c83ea495adbd"; - /// CLSID_WICTiffEncoder - public const string WICTiffEncoder = "0131be10-2001-4c5f-a9b0-cc88fab64ce8"; - /// CLSID_WICWmpEncoder - public const string WICWmpEncoder = "ac4ce3cb-e1c1-44cd-8215-5a1665509ec2"; - - #endregion - - #region Category Identifiers - - /// CLSID_WICImagingCategories - public const string WICImagingCategories = "fae3d380-fea4-4623-8c75-c6b61110b681"; - - #endregion - - #region Format converters - - /// CLSID_WICDefaultFormatConverter - public const string WICDefaultFormatConverter = "1a3f11dc-b514-4b17-8c5f-2154513852f1"; - /// CLSID_WICFormatConverterNChannel - public const string WICFormatConverterNChannel = "c17cabb2-d4a3-47d7-a557-339b2efbd4f1"; - /// CLSID_WICFormatConverterWMPhoto - public const string WICFormatConverterWMPhoto = "9cb5172b-d600-46ba-ab77-77bb7e3a00d9"; - - #endregion - } - - /// Pixel format GUIDs. - internal static class WICPixelFormat - { - /* Undefined formats */ - public static readonly Guid WICPixelFormatDontCare = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x00); - public static readonly Guid WICPixelFormatUndefined = WICPixelFormatDontCare; - - /* Indexed formats */ - public static readonly Guid WICPixelFormat1bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x01); - public static readonly Guid WICPixelFormat2bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x02); - public static readonly Guid WICPixelFormat4bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x03); - public static readonly Guid WICPixelFormat8bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x04); - - public static readonly Guid WICPixelFormatBlackWhite = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x05); - public static readonly Guid WICPixelFormat2bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x06); - public static readonly Guid WICPixelFormat4bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x07); - public static readonly Guid WICPixelFormat8bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x08); - - /* sRGB formats (gamma is approx. 2.2) */ - /* For a full definition, see the sRGB spec */ - - /* 16bpp formats */ - public static readonly Guid WICPixelFormat16bppBGR555 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x09); - public static readonly Guid WICPixelFormat16bppBGR565 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0a); - public static readonly Guid WICPixelFormat16bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0b); - - /* 24bpp formats */ - public static readonly Guid WICPixelFormat24bppBGR = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c); - public static readonly Guid WICPixelFormat24bppRGB = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d); - - /* 32bpp format */ - public static readonly Guid WICPixelFormat32bppBGR = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0e); - public static readonly Guid WICPixelFormat32bppBGRA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f); - public static readonly Guid WICPixelFormat32bppPBGRA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x10); - public static readonly Guid WICPixelFormat32bppGrayFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x11); - - /* 48bpp format */ - public static readonly Guid WICPixelFormat48bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x12); - - /* scRGB formats. Gamma is 1.0 */ - /* For a full definition, see the scRGB spec */ - - /* 16bpp format */ - public static readonly Guid WICPixelFormat16bppGrayFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x13); - - /* 32bpp format */ - public static readonly Guid WICPixelFormat32bppBGR101010 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x14); - - /* 48bpp format */ - public static readonly Guid WICPixelFormat48bppRGB = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x15); - - /* 64bpp format */ - public static readonly Guid WICPixelFormat64bppRGBA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x16); - public static readonly Guid WICPixelFormat64bppPRGBA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x17); - - /* 96bpp format */ - public static readonly Guid WICPixelFormat96bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x18); - - /* Floating point scRGB formats */ - public static readonly Guid WICPixelFormat128bppRGBAFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x19); - public static readonly Guid WICPixelFormat128bppPRGBAFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1a); - public static readonly Guid WICPixelFormat128bppRGBFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1b); - - /* CMYK formats. */ - public static readonly Guid WICPixelFormat32bppCMYK = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1c); - - /* Photon formats */ - public static readonly Guid WICPixelFormat64bppRGBAFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1d); - public static readonly Guid WICPixelFormat64bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x40); - public static readonly Guid WICPixelFormat128bppRGBAFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1e); - public static readonly Guid WICPixelFormat128bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x41); - - public static readonly Guid WICPixelFormat64bppRGBAHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3a); - public static readonly Guid WICPixelFormat64bppRGBHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x42); - public static readonly Guid WICPixelFormat48bppRGBHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3b); - - public static readonly Guid WICPixelFormat32bppRGBE = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3d); - - public static readonly Guid WICPixelFormat16bppGrayHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3e); - public static readonly Guid WICPixelFormat32bppGrayFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3f); - - /* More CMYK formats and n-Channel formats */ - public static readonly Guid WICPixelFormat64bppCMYK = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1f); - - public static readonly Guid WICPixelFormat24bpp3Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x20); - public static readonly Guid WICPixelFormat32bpp4Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x21); - public static readonly Guid WICPixelFormat40bpp5Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x22); - public static readonly Guid WICPixelFormat48bpp6Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x23); - public static readonly Guid WICPixelFormat56bpp7Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x24); - public static readonly Guid WICPixelFormat64bpp8Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x25); - - public static readonly Guid WICPixelFormat48bpp3Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x26); - public static readonly Guid WICPixelFormat64bpp4Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x27); - public static readonly Guid WICPixelFormat80bpp5Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x28); - public static readonly Guid WICPixelFormat96bpp6Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x29); - public static readonly Guid WICPixelFormat112bpp7Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2a); - public static readonly Guid WICPixelFormat128bpp8Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2b); - - public static readonly Guid WICPixelFormat40bppCMYKAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2c); - public static readonly Guid WICPixelFormat80bppCMYKAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2d); - - public static readonly Guid WICPixelFormat32bpp3ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2e); - public static readonly Guid WICPixelFormat40bpp4ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2f); - public static readonly Guid WICPixelFormat48bpp5ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x30); - public static readonly Guid WICPixelFormat56bpp6ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x31); - public static readonly Guid WICPixelFormat64bpp7ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x32); - public static readonly Guid WICPixelFormat72bpp8ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x33); - - public static readonly Guid WICPixelFormat64bpp3ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x34); - public static readonly Guid WICPixelFormat80bpp4ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x35); - public static readonly Guid WICPixelFormat96bpp5ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x36); - public static readonly Guid WICPixelFormat112bpp6ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x37); - public static readonly Guid WICPixelFormat128bpp7ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x38); - public static readonly Guid WICPixelFormat144bpp8ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x39); - } - - [Flags] - internal enum WICComponentType : int - { - WICDecoder = 0x00000001, - WICEncoder = 0x00000002, - WICPixelFormatConverter = 0x00000004, - WICMetadataReader = 0x00000008, - WICMetadataWriter = 0x00000010, - WICPixelFormat = 0x00000020, - WICAllComponents = 0x0000003F, - } - - internal enum WICBitmapDitherType : int - { - None = 0x00000000, - Solid = 0x00000000, - Ordered4x4 = 0x00000001, - Ordered8x8 = 0x00000002, - Ordered16x16 = 0x00000003, - Spiral4x4 = 0x00000004, - Spiral8x8 = 0x00000005, - DualSpiral4x4 = 0x00000006, - DualSpiral8x8 = 0x00000007, - ErrorDiffusion = 0x00000008, - } - - /// WICDecodeMetadata*, WICDecodeOptions - internal enum WICDecodeMetadata : int - { - CacheOnDemand = 0x00000000, - CacheOnLoad = 0x00000001, - } - - [Flags] - internal enum WICComponentSigning : uint - { - WICComponentSigned = 0x00000001, - WICComponentUnsigned = 0x00000002, - WICComponentSafe = 0x00000004, - WICComponentDisabled = 0x80000000, - } - - /// - /// WICBitmapPaletteType* - /// - internal enum WICBitmapPaletteType - { - /// Arbitrary custom palette provided by caller. - Custom = 0x00000000, - /// Optimal palette generated using a median-cut algorithm. - MedianCut = 0x00000001, - /// Black and white palette. - FixedBW = 0x00000002, - - // Symmetric halftone palettes. - // Each of these halftone palettes will be a superset of the system palette. - // E.g. Halftone8 will have it's 8-color on-off primaries and the 16 system - // colors added. With duplicates removed, that leaves 16 colors. - - FixedHalftone8 = 0x00000003, // 8-color, on-off primaries - FixedHalftone27 = 0x00000004, // 3 intensity levels of each color - FixedHalftone64 = 0x00000005, // 4 intensity levels of each color - FixedHalftone125 = 0x00000006, // 5 intensity levels of each color - FixedHalftone216 = 0x00000007, // 6 intensity levels of each color - - /// convenient web palette, same as WICBitmapPaletteTypeFixedHalftone216 - FixedWebPalette = FixedHalftone216, - - // Assymetric halftone palettes. - // These are somewhat less useful than the symmetric ones, but are - // included for completeness. These do not include all of the system - // colors. - - FixedHalftone252 = 0x00000008, // 6-red, 7-green, 6-blue intensities - FixedHalftone256 = 0x00000009, // 8-red, 8-green, 4-blue intensities - - FixedGray4 = 0x0000000A,// 4 shades of gray - FixedGray16 = 0x0000000B,// 16 shades of gray - FixedGray256 = 0x0000000C,// 256 shades of gray - } - - /// - /// WICBitmapTransform*, WICBitmapTransformOptions - /// - internal enum WICBitmapTransform : int - { - Rotate0 = 0x00000000, - Rotate90 = 0x00000001, - Rotate180 = 0x00000002, - Rotate270 = 0x00000003, - FlipHorizontal = 0x00000008, - FlipVertical = 0x00000010, - } - - /// - /// WICBitmap* - /// - internal enum WICBitmapCreateCacheOption : int - { - NoCache = 0x00000000, - CacheOnDemand = 0x00000001, - CacheOnLoad = 0x00000002, - } - - /// - /// WICBitmap* - /// - internal enum WICBitmapAlphaChannelOption : int - { - UseAlpha = 0x00000000, - UsePremultipliedAlpha = 0x00000001, - IgnoreAlpha = 0x00000002, - } - - #endregion - - #region WIC Structures - - [StructLayout(LayoutKind.Sequential)] - internal struct WICRect - { - public int X; - public int Y; - public int Width; - public int Height; - } - - #endregion - - #region WIC Interfaces - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.WICBitmapDecoder), - ] - internal interface IWICBitmapDecoder - { - uint QueryCapability([In] IStream pIStream); - - void Initialize([In] IStream pIStream, WICDecodeMetadata cacheOptions); - - Guid GetContainerFormat(); - - // returns IWICBitmapDecoderInfo - IntPtr GetDecoderInfo(); - - void CopyPalette([In] /*IWICPalette*/ IntPtr pIPalette); - - // returns IWICMetadataQueryReader - IntPtr GetMetadataQueryReader(); - - // returns IWICBitmapSource - IntPtr GetPreview(); - - void GetColorContexts(int cCount, [In, Out] /*IWICColorContext*/ ref IntPtr ppIColorContexts, out int pcActualCount); - - // returns IWICBitmapSource - IntPtr GetThumbnail(); - - int GetFrameCount(); - - IWICBitmapFrameDecode GetFrame(int index); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.WICBitmapSource) - ] - internal interface IWICBitmapSource - { - void GetSize(out int puiWidth, out int puiHeight); - - Guid GetPixelFormat(); - - void GetResolution(out double pDpiX, out double pDpiY); - - void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); - - void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.WICFormatConverter) - ] - interface IWICFormatConverter : IWICBitmapSource - { - #region IWICBitmapSource redeclaration - new void GetSize(out int puiWidth, out int puiHeight); - new Guid GetPixelFormat(); - new void GetResolution(out double pDpiX, out double pDpiY); - new void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); - new void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); - #endregion - - void Initialize( - IWICBitmapSource pISource, - [In] ref Guid dstFormat, - WICBitmapDitherType dither, - IntPtr pIPalette, - double alphaThresholdPercent, - WICBitmapPaletteType paletteTranslate); - - [return: MarshalAs(UnmanagedType.Bool)] - bool CanConvert( - [In] ref Guid srcPixelFormat, - [In] ref Guid dstPixelFormat); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.WICBitmap) - ] - internal interface IWICBitmap : IWICBitmapSource - { - #region IWICBitmapSource redeclaration - new void GetSize(out int puiWidth, out int puiHeight); - new Guid GetPixelFormat(); - new void GetResolution(out double pDpiX, out double pDpiY); - new void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); - new void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); - #endregion - - // IWICBitmapLock - IntPtr Lock([In] ref WICRect prcLock, int flags); - - void SetPalette(IntPtr pIPalette); - - void SetResolution(double dpiX, double dpiY); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.WICBitmapFrameDecode) - ] - internal interface IWICBitmapFrameDecode : IWICBitmapSource - { - #region IWICBitmapSource redeclaration - new void GetSize(out int puiWidth, out int puiHeight); - new Guid GetPixelFormat(); - new void GetResolution(out double pDpiX, out double pDpiY); - new void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); - new void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); - #endregion - - // IWICMetadataQueryReader - IntPtr GetMetadataQueryReader(); - - void GetColorContexts(int cCount, [In, Out] ref IntPtr /*IWICColorContext*/ ppIColorContexts, out int pcActualCount); - - IWICBitmapSource GetThumbnail(); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.WICBitmapFlipRotator) - ] - internal interface IWICBitmapFlipRotator : IWICBitmapSource - { - #region IWICBitmapSource redeclaration - new void GetSize(out int puiWidth, out int puiHeight); - new Guid GetPixelFormat(); - new void GetResolution(out double pDpiX, out double pDpiY); - new void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); - new void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); - #endregion - - void Initialize(IWICBitmapSource pISource, WICBitmapTransform options); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.WICImagingFactory) - ] - internal interface IWICImagingFactory - { - IWICBitmapDecoder CreateDecoderFromFilename( - [MarshalAs(UnmanagedType.LPWStr)] string wzFileName, - [In] ref Guid pguidVendor, - uint dwDesiredAccess, - WICDecodeMetadata metadataOptions); - - IWICBitmapDecoder CreateDecoderFromStream( - [In] IStream pIStream, - [In] ref Guid pguidVendor, - WICDecodeMetadata metadataOptions); - - IWICBitmapDecoder CreateDecoderFromFileHandle( - IntPtr hFile, - [In] ref Guid pguidVendor, - WICDecodeMetadata metadataOptions); - - // returns IWICComponentInfo - IntPtr CreateComponentInfo([In] ref Guid clsidComponent); - - IWICBitmapDecoder CreateDecoder( - [In] ref Guid guidContainerFormat, - [In] ref Guid pguidVendor); - - // IWICBitmapEncoder - IntPtr CreateEncoder( - [In] ref Guid guidContainerFormat, - [In] ref Guid pguidVendor); - - // IWICPalette - IntPtr CreatePalette(); - - IWICFormatConverter CreateFormatConverter(); - - // IWICBitmapScaler - IntPtr CreateBitmapScaler(); - - // IWICBitmapClipper - IntPtr CreateBitmapClipper(); - - IWICBitmapFlipRotator CreateBitmapFlipRotator(); - - IWICStream CreateStream(); - - // IWICColorContext - IntPtr CreateColorContext(); - - // IWICColorTransform - IntPtr CreateColorTransformer(); - - /* Bitmap creation */ - - IWICBitmap CreateBitmap( - int uiWidth, - int uiHeight, - [In] ref Guid pixelFormat, - WICBitmapCreateCacheOption option); - - IWICBitmap CreateBitmapFromSource( - IWICBitmapSource pIBitmapSource, - WICBitmapCreateCacheOption option); - - IWICBitmap CreateBitmapFromSourceRect( - IWICBitmapSource pIBitmapSource, - int x, - int y, - int width, - int height); - - IWICBitmap CreateBitmapFromMemory( - int uiWidth, - int uiHeight, - [In] ref Guid pixelFormat, - int cbStride, - int cbBufferSize, - IntPtr pbBuffer); - - IWICBitmap CreateBitmapFromHBITMAP( - IntPtr hBitmap, - IntPtr hPalette, - WICBitmapAlphaChannelOption options); - - IWICBitmap CreateBitmapFromHICON(IntPtr hIcon); - - // IEnumUnknown - IntPtr CreateComponentEnumerator( - int componentTypes, // WICComponentType - int options); // WICComponentEnumerateOptions - - // IWICFastMetadataEncoder - IntPtr CreateFastMetadataEncoderFromDecoder(IWICBitmapDecoder pIDecoder); - - // IWICFastMetadataEncoder - IntPtr CreateFastMetadataEncoderFromFrameDecode(IntPtr pIFrameDecoder); - - // IWICMetadataQueryWriter - IntPtr CreateQueryWriter( - [In] ref Guid guidMetadataFormat, - [In] ref Guid pguidVendor); - - // IWICMetadataQueryWriter - IntPtr CreateQueryWriterFromReader( - IntPtr pIQueryReader, - [In] ref Guid pguidVendor); - } - - [ - ComImport, - InterfaceType(ComInterfaceType.InterfaceIsIUnknown), - Guid(IID.WICStream) - ] - internal interface IWICStream : IStream - { - #region IStream redeclaration - - new void Clone(out IStream ppstm); - new void Commit(int grfCommitFlags); - new void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten); - new void LockRegion(long libOffset, long cb, int dwLockType); - new void Read(byte[] pv, int cb, IntPtr pcbRead); - new void Revert(); - new void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition); - new void SetSize(long libNewSize); - new void Stat(out STATSTG pstatstg, int grfStatFlag); - new void UnlockRegion(long libOffset, long cb, int dwLockType); - new void Write(byte[] pv, int cb, IntPtr pcbWritten); - - #endregion - - void InitializeFromIStream(IStream pIStream); - void InitializeFromFilename([In, MarshalAs(UnmanagedType.LPWStr)] string wzFileName, int dwDesiredAccess); - void InitializeFromMemory(IntPtr pbBuffer, uint cbBufferSize); - void InitializeFromIStreamRegion(IStream pIStream, ulong ulOffset, ulong ulMaxSize); - } - - #endregion -} diff --git a/Microsoft.Windows.Shell/Standard/WindowExtensions.cs b/Microsoft.Windows.Shell/Standard/WindowExtensions.cs deleted file mode 100644 index d0fb5b2..0000000 --- a/Microsoft.Windows.Shell/Standard/WindowExtensions.cs +++ /dev/null @@ -1,137 +0,0 @@ - -namespace Standard -{ - using System; - using System.ComponentModel; - using System.Windows; - using System.Windows.Interop; - using System.Windows.Media; - - /// - /// Attached properties for WPF Windows. - /// - internal sealed class WindowExtensions - { - private IntPtr _hwnd = IntPtr.Zero; - private Window _window = null; - - private event Action WindowSourceInitialized; - - private WindowExtensions(Window window) - { - Assert.IsNotNull(window); - _window = window; - _hwnd = new WindowInteropHelper(window).Handle; - - if (_hwnd == IntPtr.Zero) - { - _window.SourceInitialized += _OnWindowSourceInitialized; - } - } - - private void _OnWindowSourceInitialized(object sender, EventArgs e) - { - Assert.AreEqual(sender, _window); - - _window.SourceInitialized -= _OnWindowSourceInitialized; - - _hwnd = new WindowInteropHelper(_window).Handle; - Assert.IsNotDefault(_hwnd); - - Action handler = WindowSourceInitialized; - if (handler != null) - { - handler(); - } - } - - private static WindowExtensions _EnsureAttachedExtensions(Window window) - { - Assert.IsNotNull(window); - - var ext = (WindowExtensions)window.GetValue(WindowExtensionsProperty); - if (ext == null) - { - ext = new WindowExtensions(window); - window.SetValue(WindowExtensionsProperty, ext); - } - - return ext; - } - - private static readonly DependencyProperty WindowExtensionsProperty = DependencyProperty.RegisterAttached( - "WindowExtensions", - typeof(WindowExtensions), - typeof(WindowExtensions), - new PropertyMetadata(null)); - - // Not bothering with CLR attached property getter/setter since this is a private dependency property. - - - public static readonly DependencyProperty HwndBackgroundBrushProperty = DependencyProperty.RegisterAttached( - "HwndBackgroundBrush", - typeof(SolidColorBrush), - typeof(WindowExtensions), - new PropertyMetadata( - Brushes.Pink, - (d,e) => _OnHwndBackgroundBrushChanged(d))); - - public static SolidColorBrush GetHwndBackgroundBrush(FrameworkElement window) - { - Verify.IsNotNull(window, "window"); - return (SolidColorBrush)window.GetValue(HwndBackgroundBrushProperty); - } - - public static void SetHwndBackgroundBrush(FrameworkElement window, SolidColorBrush value) - { - if (!(window is Window)) - { - return; - } - Verify.IsNotNull(window, "window"); - window.SetValue(HwndBackgroundBrushProperty, value); - } - - private static void _OnHwndBackgroundBrushChanged(DependencyObject d) - { - if (DesignerProperties.GetIsInDesignMode(d)) - { - return; - } - - var window = d as Window; - Verify.IsNotNull(window, "window"); - - WindowExtensions ext = _EnsureAttachedExtensions(window); - - if (ext._hwnd == IntPtr.Zero) - { - ext.WindowSourceInitialized += () => _OnHwndBackgroundBrushChanged(window); - return; - } - - SolidColorBrush backgroundBrush = (SolidColorBrush)window.GetValue(HwndBackgroundBrushProperty); - //if (backgroundBrush == null) - //{ - // Nothing to change. - // return; - //} - - Color backgroundColor = backgroundBrush.Color; - - // Not really handling errors here, but they shouldn't matter... Might leak an HBRUSH. - - IntPtr hBrush = NativeMethods.CreateSolidBrush(Utility.RGB(backgroundColor)); - - // Note that setting this doesn't necessarily repaint the window right away. - // Since the WPF content should cover the HWND background this doesn't matter. - // The new background will get repainted when the window is resized. - IntPtr hBrushOld = NativeMethods.SetClassLongPtr(ext._hwnd, GCLP.HBRBACKGROUND, hBrush); - - if (IntPtr.Zero != hBrushOld) - { - NativeMethods.DeleteObject(hBrushOld); - } - } - } -} diff --git a/Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimation.cs b/Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimation.cs deleted file mode 100644 index 50368d1..0000000 --- a/Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimation.cs +++ /dev/null @@ -1,541 +0,0 @@ -namespace Standard -{ - using System; - using System.Diagnostics; - using System.Windows; - using System.Windows.Media.Animation; - - internal enum AnimationType - { - Automatic, - FromTo, - FromBy, - From, - To, - By, - } - - /// - /// Animates the value of a CornerRadius property using linear interpolation - /// between two values. The values are determined by the combination of - /// From, To, or By values that are set on the animation. - /// - internal partial class CornerRadiusAnimation : CornerRadiusAnimationBase - { - #region Data - - /// - /// This is used if the user has specified From, To, and/or By values. - /// - private CornerRadius[] _keyValues; - - private AnimationType _animationType; - private bool _isAnimationFunctionValid; - - #endregion - - #region Constructors - - /// - /// Static ctor for CornerRadiusAnimation establishes - /// dependency properties, using as much shared data as possible. - /// - static CornerRadiusAnimation() - { - Type typeofProp = typeof(CornerRadius?); - Type typeofThis = typeof(CornerRadiusAnimation); - PropertyChangedCallback propCallback = new PropertyChangedCallback(AnimationFunction_Changed); - ValidateValueCallback validateCallback = new ValidateValueCallback(ValidateFromToOrByValue); - - FromProperty = DependencyProperty.Register( - "From", - typeofProp, - typeofThis, - new PropertyMetadata((CornerRadius?)null, propCallback), - validateCallback); - - ToProperty = DependencyProperty.Register( - "To", - typeofProp, - typeofThis, - new PropertyMetadata((CornerRadius?)null, propCallback), - validateCallback); - - ByProperty = DependencyProperty.Register( - "By", - typeofProp, - typeofThis, - new PropertyMetadata((CornerRadius?)null, propCallback), - validateCallback); - - } - - - /// - /// Creates a new CornerRadiusAnimation with all properties set to - /// their default values. - /// - public CornerRadiusAnimation() - : base() - { - } - - /// - /// Creates a new CornerRadiusAnimation that will animate a - /// CornerRadius property from its base value to the value specified - /// by the "toValue" parameter of this constructor. - /// - public CornerRadiusAnimation(CornerRadius toValue, Duration duration) - : this() - { - To = toValue; - Duration = duration; - } - - /// - /// Creates a new CornerRadiusAnimation that will animate a - /// CornerRadius property from its base value to the value specified - /// by the "toValue" parameter of this constructor. - /// - public CornerRadiusAnimation(CornerRadius toValue, Duration duration, FillBehavior fillBehavior) - : this() - { - To = toValue; - Duration = duration; - FillBehavior = fillBehavior; - } - - /// - /// Creates a new CornerRadiusAnimation that will animate a - /// CornerRadius property from the "fromValue" parameter of this constructor - /// to the "toValue" parameter. - /// - public CornerRadiusAnimation(CornerRadius fromValue, CornerRadius toValue, Duration duration) - : this() - { - From = fromValue; - To = toValue; - Duration = duration; - } - - /// - /// Creates a new CornerRadiusAnimation that will animate a - /// CornerRadius property from the "fromValue" parameter of this constructor - /// to the "toValue" parameter. - /// - public CornerRadiusAnimation(CornerRadius fromValue, CornerRadius toValue, Duration duration, FillBehavior fillBehavior) - : this() - { - From = fromValue; - To = toValue; - Duration = duration; - FillBehavior = fillBehavior; - } - - #endregion - - #region Freezable - - /// - /// Creates a copy of this CornerRadiusAnimation - /// - /// The copy - public new CornerRadiusAnimation Clone() - { - return (CornerRadiusAnimation)base.Clone(); - } - - // - // Note that we don't override the Clone virtuals (CloneCore, CloneCurrentValueCore, - // GetAsFrozenCore, and GetCurrentValueAsFrozenCore) even though this class has state - // not stored in a DP. - // - // We don't need to clone _animationType and _keyValues because they are the the cached - // results of animation function validation, which can be recomputed. The other remaining - // field, isAnimationFunctionValid, defaults to false, which causes this recomputation to happen. - // - - /// - /// Implementation of Freezable.CreateInstanceCore. - /// - /// The new Freezable. - protected override Freezable CreateInstanceCore() - { - return new CornerRadiusAnimation(); - } - - #endregion - - #region Methods - - /// - /// Calculates the value this animation believes should be the current value for the property. - /// - /// - /// This value is the suggested origin value provided to the animation - /// to be used if the animation does not have its own concept of a - /// start value. If this animation is the first in a composition chain - /// this value will be the snapshot value if one is available or the - /// base property value if it is not; otherise this value will be the - /// value returned by the previous animation in the chain with an - /// animationClock that is not Stopped. - /// - /// - /// This value is the suggested destination value provided to the animation - /// to be used if the animation does not have its own concept of an - /// end value. This value will be the base value if the animation is - /// in the first composition layer of animations on a property; - /// otherwise this value will be the output value from the previous - /// composition layer of animations for the property. - /// - /// - /// This is the animationClock which can generate the CurrentTime or - /// CurrentProgress value to be used by the animation to generate its - /// output value. - /// - /// - /// The value this animation believes should be the current value for the property. - /// - protected override CornerRadius GetCurrentValueCore(CornerRadius defaultOriginValue, CornerRadius defaultDestinationValue, AnimationClock animationClock) - { - Debug.Assert(animationClock.CurrentState != ClockState.Stopped); - - if (!_isAnimationFunctionValid) - { - ValidateAnimationFunction(); - } - - double progress = animationClock.CurrentProgress.Value; - - CornerRadius from = new CornerRadius(); - CornerRadius to = new CornerRadius(); - CornerRadius accumulated = new CornerRadius(); - CornerRadius foundation = new CornerRadius(); - - // need to validate the default origin and destination values if - // the animation uses them as the from, to, or foundation values - bool validateOrigin = false; - bool validateDestination = false; - - switch(_animationType) - { - case AnimationType.Automatic: - - from = defaultOriginValue; - to = defaultDestinationValue; - - validateOrigin = true; - validateDestination = true; - - break; - - case AnimationType.From: - - from = _keyValues[0]; - to = defaultDestinationValue; - - validateDestination = true; - - break; - - case AnimationType.To: - - from = defaultOriginValue; - to = _keyValues[0]; - - validateOrigin = true; - - break; - - case AnimationType.By: - - // According to the SMIL specification, a By animation is - // always additive. But we don't force this so that a - // user can re-use a By animation and have it replace the - // animations that precede it in the list without having - // to manually set the From value to the base value. - - to = _keyValues[0]; - foundation = defaultOriginValue; - - validateOrigin = true; - - break; - - case AnimationType.FromTo: - - from = _keyValues[0]; - to = _keyValues[1]; - - if (IsAdditive) - { - foundation = defaultOriginValue; - validateOrigin = true; - } - - break; - - case AnimationType.FromBy: - - from = _keyValues[0]; - to = _AddCornerRadius(_keyValues[0], _keyValues[1]); - - if (IsAdditive) - { - foundation = defaultOriginValue; - validateOrigin = true; - } - - break; - - default: - - Debug.Fail("Unknown animation type."); - - break; - } - - if (validateOrigin - && !_IsValidAnimationValueCornerRadius(defaultOriginValue)) - { - throw new InvalidOperationException(); - } - - if (validateDestination - && !_IsValidAnimationValueCornerRadius(defaultDestinationValue)) - { - throw new InvalidOperationException(); - } - - - if (IsCumulative) - { - double currentRepeat = (double)(animationClock.CurrentIteration - 1); - - if (currentRepeat > 0.0) - { - CornerRadius accumulator = _SubtractCornerRadius(to, from); - - accumulated = _ScaleCornerRadius(accumulator, currentRepeat); - } - } - - // return foundation + accumulated + from + ((to - from) * progress) - - return _AddCornerRadius( - foundation, - _AddCornerRadius( - accumulated, - _InterpolateCornerRadius(from, to, progress))); - } - - private CornerRadius _InterpolateCornerRadius(CornerRadius from, CornerRadius to, double progress) - { - return this._ScaleCornerRadius(this._SubtractCornerRadius(to, from), progress); - } - - private CornerRadius _ScaleCornerRadius(CornerRadius first, double currentRepeat) - { - return new CornerRadius( - first.TopLeft * currentRepeat, - first.TopRight * currentRepeat, - first.BottomRight * currentRepeat, - first.BottomLeft * currentRepeat); - } - - private CornerRadius _SubtractCornerRadius(CornerRadius first, CornerRadius second) - { - return new CornerRadius( - first.TopLeft - second.TopLeft, - first.TopRight - second.TopRight, - first.BottomRight - second.BottomRight, - first.BottomLeft - second.BottomLeft); - } - - private static bool _IsValidAnimationValueCornerRadius(CornerRadius defaultOriginValue) - { - return true; - } - - private CornerRadius _AddCornerRadius(CornerRadius first, CornerRadius second) - { - return new CornerRadius( - first.TopLeft + second.TopLeft, - first.TopRight + second.TopRight, - first.BottomRight + second.BottomRight, - first.BottomLeft + second.BottomLeft); - } - - private void ValidateAnimationFunction() - { - _animationType = AnimationType.Automatic; - _keyValues = null; - - if (From.HasValue) - { - if (To.HasValue) - { - _animationType = AnimationType.FromTo; - _keyValues = new CornerRadius[2]; - _keyValues[0] = From.Value; - _keyValues[1] = To.Value; - } - else if (By.HasValue) - { - _animationType = AnimationType.FromBy; - _keyValues = new CornerRadius[2]; - _keyValues[0] = From.Value; - _keyValues[1] = By.Value; - } - else - { - _animationType = AnimationType.From; - _keyValues = new CornerRadius[1]; - _keyValues[0] = From.Value; - } - } - else if (To.HasValue) - { - _animationType = AnimationType.To; - _keyValues = new CornerRadius[1]; - _keyValues[0] = To.Value; - } - else if (By.HasValue) - { - _animationType = AnimationType.By; - _keyValues = new CornerRadius[1]; - _keyValues[0] = By.Value; - } - - _isAnimationFunctionValid = true; - } - - #endregion - - #region Properties - - private static void AnimationFunction_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - CornerRadiusAnimation a = (CornerRadiusAnimation)d; - - a._isAnimationFunctionValid = false; - //a.PropertyChanged(e.Property); - } - - private void PropertyChanged(DependencyProperty dependencyProperty) - { - //throw new NotImplementedException(); - } - - private static bool ValidateFromToOrByValue(object value) - { - CornerRadius? typedValue = (CornerRadius?)value; - - if (typedValue.HasValue) - { - return _IsValidAnimationValueCornerRadius(typedValue.Value); - } - else - { - return true; - } - } - - /// - /// FromProperty - /// - public static readonly DependencyProperty FromProperty; - - /// - /// From - /// - public CornerRadius? From - { - get - { - return (CornerRadius?)GetValue(FromProperty); - } - set - { - SetValue(FromProperty, value); - } - } - - /// - /// ToProperty - /// - public static readonly DependencyProperty ToProperty; - - /// - /// To - /// - public CornerRadius? To - { - get - { - return (CornerRadius?)GetValue(ToProperty); - } - set - { - SetValue(ToProperty, value); - } - } - - /// - /// ByProperty - /// - public static readonly DependencyProperty ByProperty; - - /// - /// By - /// - public CornerRadius? By - { - get - { - return (CornerRadius?)GetValue(ByProperty); - } - set - { - SetValue(ByProperty, value); - } - } - - - /// - /// If this property is set to true the animation will add its value to - /// the base value instead of replacing it entirely. - /// - public bool IsAdditive - { - get - { - return (bool)GetValue(IsAdditiveProperty); - } - set - { - SetValue(IsAdditiveProperty, value); - } - } - - /// - /// It this property is set to true, the animation will accumulate its - /// value over repeats. For instance if you have a From value of 0.0 and - /// a To value of 1.0, the animation return values from 1.0 to 2.0 over - /// the second reteat cycle, and 2.0 to 3.0 over the third, etc. - /// - public bool IsCumulative - { - get - { - return (bool)GetValue(IsCumulativeProperty); - } - set - { - SetValue(IsCumulativeProperty, value); - } - } - - #endregion - } -} diff --git a/Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimationBase.cs b/Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimationBase.cs deleted file mode 100644 index cd04245..0000000 --- a/Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimationBase.cs +++ /dev/null @@ -1,191 +0,0 @@ -namespace Standard -{ - using System; - using System.Windows; - using System.Windows.Media.Animation; - - internal abstract class CornerRadiusAnimationBase : AnimationTimeline - { - #region Constructors - - /// - /// Creates a new CornerRadiusAnimationBase. - /// - protected CornerRadiusAnimationBase() - : base() - { - } - - #endregion - - #region Freezable - - /// - /// Creates a copy of this CornerRadiusAnimationBase - /// - /// The copy - public new CornerRadiusAnimationBase Clone() - { - return (CornerRadiusAnimationBase)base.Clone(); - } - - #endregion - - #region IAnimation - - /// - /// Calculates the value this animation believes should be the current value for the property. - /// - /// - /// This value is the suggested origin value provided to the animation - /// to be used if the animation does not have its own concept of a - /// start value. If this animation is the first in a composition chain - /// this value will be the snapshot value if one is available or the - /// base property value if it is not; otherise this value will be the - /// value returned by the previous animation in the chain with an - /// animationClock that is not Stopped. - /// - /// - /// This value is the suggested destination value provided to the animation - /// to be used if the animation does not have its own concept of an - /// end value. This value will be the base value if the animation is - /// in the first composition layer of animations on a property; - /// otherwise this value will be the output value from the previous - /// composition layer of animations for the property. - /// - /// - /// This is the animationClock which can generate the CurrentTime or - /// CurrentProgress value to be used by the animation to generate its - /// output value. - /// - /// - /// The value this animation believes should be the current value for the property. - /// - public override sealed object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock) - { - // Verify that object arguments are non-null since we are a value type - if (defaultOriginValue == null) - { - throw new ArgumentNullException("defaultOriginValue"); - } - if (defaultDestinationValue == null) - { - throw new ArgumentNullException("defaultDestinationValue"); - } - return GetCurrentValue((CornerRadius)defaultOriginValue, (CornerRadius)defaultDestinationValue, animationClock); - } - - /// - /// Returns the type of the target property - /// - public override sealed Type TargetPropertyType - { - get - { - ReadPreamble(); - - return typeof(CornerRadius); - } - } - - #endregion - - #region Methods - - - /// - /// Calculates the value this animation believes should be the current value for the property. - /// - /// - /// This value is the suggested origin value provided to the animation - /// to be used if the animation does not have its own concept of a - /// start value. If this animation is the first in a composition chain - /// this value will be the snapshot value if one is available or the - /// base property value if it is not; otherise this value will be the - /// value returned by the previous animation in the chain with an - /// animationClock that is not Stopped. - /// - /// - /// This value is the suggested destination value provided to the animation - /// to be used if the animation does not have its own concept of an - /// end value. This value will be the base value if the animation is - /// in the first composition layer of animations on a property; - /// otherwise this value will be the output value from the previous - /// composition layer of animations for the property. - /// - /// - /// This is the animationClock which can generate the CurrentTime or - /// CurrentProgress value to be used by the animation to generate its - /// output value. - /// - /// - /// The value this animation believes should be the current value for the property. - /// - public CornerRadius GetCurrentValue(CornerRadius defaultOriginValue, CornerRadius defaultDestinationValue, AnimationClock animationClock) - { - ReadPreamble(); - - if (animationClock == null) - { - throw new ArgumentNullException("animationClock"); - } - - // We check for null above but presharp doesn't notice so we suppress the - // warning here. - - //#pragma warning suppress 6506 - if (animationClock.CurrentState == ClockState.Stopped) - { - return defaultDestinationValue; - } - - /* - if (!AnimatedTypeHelpers.IsValidAnimationValueCornerRadius(defaultDestinationValue)) - { - throw new ArgumentException( - SR.Get( - SRID.Animation_InvalidBaseValue, - defaultDestinationValue, - defaultDestinationValue.GetType(), - GetType()), - "defaultDestinationValue"); - } - */ - - return GetCurrentValueCore(defaultOriginValue, defaultDestinationValue, animationClock); - } - - - /// - /// Calculates the value this animation believes should be the current value for the property. - /// - /// - /// This value is the suggested origin value provided to the animation - /// to be used if the animation does not have its own concept of a - /// start value. If this animation is the first in a composition chain - /// this value will be the snapshot value if one is available or the - /// base property value if it is not; otherise this value will be the - /// value returned by the previous animation in the chain with an - /// animationClock that is not Stopped. - /// - /// - /// This value is the suggested destination value provided to the animation - /// to be used if the animation does not have its own concept of an - /// end value. This value will be the base value if the animation is - /// in the first composition layer of animations on a property; - /// otherwise this value will be the output value from the previous - /// composition layer of animations for the property. - /// - /// - /// This is the animationClock which can generate the CurrentTime or - /// CurrentProgress value to be used by the animation to generate its - /// output value. - /// - /// - /// The value this animation believes should be the current value for the property. - /// - protected abstract CornerRadius GetCurrentValueCore(CornerRadius defaultOriginValue, CornerRadius defaultDestinationValue, AnimationClock animationClock); - - #endregion - } -} diff --git a/Microsoft.Windows.Shell/Standard/Wpf/DpiHelper.cs b/Microsoft.Windows.Shell/Standard/Wpf/DpiHelper.cs deleted file mode 100644 index 42b4544..0000000 --- a/Microsoft.Windows.Shell/Standard/Wpf/DpiHelper.cs +++ /dev/null @@ -1,90 +0,0 @@ -namespace Standard -{ - using System; - using System.Diagnostics.CodeAnalysis; - using System.Windows; - using System.Windows.Media; - - internal static class DpiHelper - { - private static Matrix _transformToDevice; - private static Matrix _transformToDip; - - [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] - static DpiHelper() - { - using (SafeDC desktop = SafeDC.GetDesktop()) - { - // Can get these in the static constructor. They shouldn't vary window to window, - // and changing the system DPI requires a restart. - int pixelsPerInchX = NativeMethods.GetDeviceCaps(desktop, DeviceCap.LOGPIXELSX); - int pixelsPerInchY = NativeMethods.GetDeviceCaps(desktop, DeviceCap.LOGPIXELSY); - - _transformToDip = Matrix.Identity; - _transformToDip.Scale(96d / (double)pixelsPerInchX, 96d / (double)pixelsPerInchY); - _transformToDevice = Matrix.Identity; - _transformToDevice.Scale((double)pixelsPerInchX / 96d, (double)pixelsPerInchY / 96d); - } - } - - /// - /// Convert a point in device independent pixels (1/96") to a point in the system coordinates. - /// - /// A point in the logical coordinate system. - /// Returns the parameter converted to the system's coordinates. - public static Point LogicalPixelsToDevice(Point logicalPoint) - { - return _transformToDevice.Transform(logicalPoint); - } - - /// - /// Convert a point in system coordinates to a point in device independent pixels (1/96"). - /// - /// A point in the physical coordinate system. - /// Returns the parameter converted to the device independent coordinate system. - public static Point DevicePixelsToLogical(Point devicePoint) - { - return _transformToDip.Transform(devicePoint); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static Rect LogicalRectToDevice(Rect logicalRectangle) - { - Point topLeft = LogicalPixelsToDevice(new Point(logicalRectangle.Left, logicalRectangle.Top)); - Point bottomRight = LogicalPixelsToDevice(new Point(logicalRectangle.Right, logicalRectangle.Bottom)); - - return new Rect(topLeft, bottomRight); - } - - public static Rect DeviceRectToLogical(Rect deviceRectangle) - { - Point topLeft = DevicePixelsToLogical(new Point(deviceRectangle.Left, deviceRectangle.Top)); - Point bottomRight = DevicePixelsToLogical(new Point(deviceRectangle.Right, deviceRectangle.Bottom)); - - return new Rect(topLeft, bottomRight); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static Size LogicalSizeToDevice(Size logicalSize) - { - Point pt = LogicalPixelsToDevice(new Point(logicalSize.Width, logicalSize.Height)); - - return new Size { Width = pt.X, Height = pt.Y }; - } - - public static Size DeviceSizeToLogical(Size deviceSize) - { - Point pt = DevicePixelsToLogical(new Point(deviceSize.Width, deviceSize.Height)); - - return new Size(pt.X, pt.Y); - } - - public static Thickness LogicalThicknessToDevice(Thickness logicalThickness) - { - Point topLeft = LogicalPixelsToDevice(new Point(logicalThickness.Left, logicalThickness.Top)); - Point bottomRight = LogicalPixelsToDevice(new Point(logicalThickness.Right, logicalThickness.Bottom)); - - return new Thickness(topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y); - } - } -} diff --git a/Microsoft.Windows.Shell/Standard/Wpf/GlassHelper.cs b/Microsoft.Windows.Shell/Standard/Wpf/GlassHelper.cs deleted file mode 100644 index efc48e7..0000000 --- a/Microsoft.Windows.Shell/Standard/Wpf/GlassHelper.cs +++ /dev/null @@ -1,283 +0,0 @@ -namespace Standard -{ - using System; - using System.Collections.Generic; - using System.ComponentModel; - using System.Windows; - using System.Windows.Interop; - using System.Windows.Media; - - internal class GlassHelper - { - // Test Notes: - // Things to manually verify when making changes to this class. - // * Do modified windows look correct in non-composited themes? - // * Does changing the theme back and forth leave the window in a visually ugly state? - // * Does it matter which theme was used first? - // * Does glass extension work properly in high-dpi? - // * Which of SetWindowThemeAttribute and ExtendGlassFrame are set first shouldn't matter. - // The hooks injected by one should not block the hooks of the other. - // * Do captions and icons always show up when composition is disabled? - // - // There are not automated unit tests for this class ( Boo!!! :( ) - // Be careful not to break things... - - private static readonly Dictionary _extendedWindows = new Dictionary(); - - // TODO: - // Verify that this really is sufficient. There are DWMWINDOWATTRIBUTEs as well, so this may - // be able to be turned off on a per-HWND basis, but I never see comments about that online... - public static bool IsCompositionEnabled - { - get - { - if (!Utility.IsOSVistaOrNewer) - { - return false; - } - - return NativeMethods.DwmIsCompositionEnabled(); - } - } - - public static bool ExtendGlassFrameComplete(Window window) - { - return ExtendGlassFrame(window, new Thickness(-1)); - } - - /// - /// Extends the glass frame of a window. Only works on operating systems that support composition. - /// - /// The window to modify. - /// The margins of the new frame. - /// Whether the frame was successfully extended. - /// - /// This function adds hooks to the Window to respond to changes to whether composition is enabled. - /// - public static bool ExtendGlassFrame(Window window, Thickness margin) - { - Verify.IsNotNull(window, "window"); - - window.VerifyAccess(); - - IntPtr hwnd = new WindowInteropHelper(window).Handle; - - if (_extendedWindows.ContainsKey(hwnd)) - { - // The hook into the HWND's WndProc has the original margin cached. - // Don't want to support dynamically adjusting that unless there's a need. - throw new InvalidOperationException("Multiple calls to this function for the same Window are not supported."); - } - - return _ExtendGlassFrameInternal(window, margin); - } - - private static bool _ExtendGlassFrameInternal(Window window, Thickness margin) - { - Assert.IsNotNull(window); - Assert.IsTrue(window.CheckAccess()); - - // Expect that this might be called on OSes other than Vista. - if (!Utility.IsOSVistaOrNewer) - { - // Not an error. Just not on Vista so we're not going to get glass. - return false; - } - - IntPtr hwnd = new WindowInteropHelper(window).Handle; - if (IntPtr.Zero == hwnd) - { - throw new InvalidOperationException("Window must be shown before extending glass."); - } - - HwndSource hwndSource = HwndSource.FromHwnd(hwnd); - - bool isGlassEnabled = NativeMethods.DwmIsCompositionEnabled(); - - if (!isGlassEnabled) - { - window.Background = SystemColors.WindowBrush; - hwndSource.CompositionTarget.BackgroundColor = SystemColors.WindowColor; - } - else - { - // Apply the transparent background to both the Window and the HWND - window.Background = Brushes.Transparent; - hwndSource.CompositionTarget.BackgroundColor = Colors.Transparent; - - // Thickness is going to be DIPs, need to convert to system coordinates. - Point deviceTopLeft = DpiHelper.LogicalPixelsToDevice(new Point(margin.Left, margin.Top)); - Point deviceBottomRight = DpiHelper.LogicalPixelsToDevice(new Point(margin.Right, margin.Bottom)); - - var dwmMargin = new MARGINS - { - // err on the side of pushing in glass an extra pixel. - cxLeftWidth = (int)Math.Ceiling(deviceTopLeft.X), - cxRightWidth = (int)Math.Ceiling(deviceBottomRight.X), - cyTopHeight = (int)Math.Ceiling(deviceTopLeft.Y), - cyBottomHeight = (int)Math.Ceiling(deviceBottomRight.Y), - }; - - NativeMethods.DwmExtendFrameIntoClientArea(hwnd, ref dwmMargin); - } - - // Even if glass isn't currently enabled, add the hook so we can appropriately respond - // if that changes. - - bool addHook = !_extendedWindows.ContainsKey(hwnd); - - if (addHook) - { - HwndSourceHook hook = delegate(IntPtr innerHwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) - { - if (WM.DWMCOMPOSITIONCHANGED == (WM)msg) - { - _ExtendGlassFrameInternal(window, margin); - handled = false; - } - return IntPtr.Zero; - }; - - _extendedWindows.Add(hwnd, hook); - hwndSource.AddHook(hook); - window.Closing += _OnExtendedWindowClosing; - } - - return isGlassEnabled; - } - - /// - /// Handler for the Closing event on a Window with an extended glass frame. - /// - /// The source of the event. - /// The instance containing the event data. - /// - /// When a Window with an extended glass frame closes, removes any local references to it. - /// - // BUGBUG: Doesn't handle if the Closing gets canceled. - static void _OnExtendedWindowClosing(object sender, CancelEventArgs e) - { - var window = sender as Window; - Assert.IsNotNull(window); - - IntPtr hwnd = new WindowInteropHelper(window).Handle; - - // We use the Closing rather than the Closed event to ensure that we can get this value. - Assert.AreNotEqual(IntPtr.Zero, hwnd); - - HwndSource hwndSource = HwndSource.FromHwnd(hwnd); - - Assert.IsTrue(_extendedWindows.ContainsKey(hwnd)); - - hwndSource.RemoveHook(_extendedWindows[hwnd]); - _extendedWindows.Remove(hwnd); - - window.Closing -= _OnExtendedWindowClosing; - } - - private static readonly Dictionary _attributedWindows = new Dictionary(); - - public static bool SetWindowThemeAttribute(Window window, bool showCaption, bool showIcon) - { - Verify.IsNotNull(window, "window"); - - window.VerifyAccess(); - - IntPtr hwnd = new WindowInteropHelper(window).Handle; - - if (_attributedWindows.ContainsKey(hwnd)) - { - // The hook into the HWND's WndProc has the original settings cached. - // Don't want to support dynamically adjusting that unless there's a need. - throw new InvalidOperationException("Multiple calls to this function for the same Window are not supported."); - } - - return _SetWindowThemeAttribute(window, showCaption, showIcon); - } - - private static bool _SetWindowThemeAttribute(Window window, bool showCaption, bool showIcon) - { - bool isGlassEnabled; - - Assert.IsNotNull(window); - Assert.IsTrue(window.CheckAccess()); - - // This only is expected to work if Aero glass is enabled. - try - { - isGlassEnabled = NativeMethods.DwmIsCompositionEnabled(); - } - catch (DllNotFoundException) - { - // Not an error. Just not on Vista so we're not going to get glass. - return false; - } - - IntPtr hwnd = new WindowInteropHelper(window).Handle; - if (IntPtr.Zero == hwnd) - { - throw new InvalidOperationException("Window must be shown before we can modify attributes."); - } - - var options = new WTA_OPTIONS - { - dwMask = (WTNCA.NODRAWCAPTION | WTNCA.NODRAWICON) - }; - if (isGlassEnabled) - { - if (!showCaption) - { - options.dwFlags |= WTNCA.NODRAWCAPTION; - } - if (!showIcon) - { - options.dwFlags |= WTNCA.NODRAWICON; - } - } - - NativeMethods.SetWindowThemeAttribute(hwnd, WINDOWTHEMEATTRIBUTETYPE.WTA_NONCLIENT, ref options, WTA_OPTIONS.Size); - - bool addHook = !_attributedWindows.ContainsKey(hwnd); - - if (addHook) - { - HwndSourceHook hook = delegate(IntPtr unusedHwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) - { - if (WM.DWMCOMPOSITIONCHANGED == (WM)msg) - { - _SetWindowThemeAttribute(window, showCaption, showIcon); - handled = false; - } - return IntPtr.Zero; - }; - - _attributedWindows.Add(hwnd, hook); - HwndSource.FromHwnd(hwnd).AddHook(hook); - window.Closing += _OnAttributedWindowClosing; - } - - return isGlassEnabled; - } - - static void _OnAttributedWindowClosing(object sender, CancelEventArgs e) - { - var window = sender as Window; - Assert.IsNotNull(window); - - IntPtr hwnd = new WindowInteropHelper(window).Handle; - - // We use the Closing rather than the Closed event to ensure that we can get this value. - Assert.AreNotEqual(IntPtr.Zero, hwnd); - - HwndSource hwndSource = HwndSource.FromHwnd(hwnd); - - Assert.IsTrue(_attributedWindows.ContainsKey(hwnd)); - - hwndSource.RemoveHook(_attributedWindows[hwnd]); - _attributedWindows.Remove(hwnd); - - window.Closing -= _OnExtendedWindowClosing; - } - - } -} diff --git a/Microsoft.Windows.Shell/Standard/Wpf/MshtmlProvider.cs b/Microsoft.Windows.Shell/Standard/Wpf/MshtmlProvider.cs deleted file mode 100644 index 9ba9273..0000000 --- a/Microsoft.Windows.Shell/Standard/Wpf/MshtmlProvider.cs +++ /dev/null @@ -1,407 +0,0 @@ - -// Interface declarations for MSHTML objects. -namespace Standard -{ - using System; - using System.Collections.Generic; - using System.Globalization; - using System.Linq; - using System.Reflection; - using System.Runtime.InteropServices; - using System.Runtime.InteropServices.ComTypes; - using System.Windows.Controls; - - [ - ComImport, - Guid(IID.WebBrowserEvents2), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch), - TypeLibType(TypeLibTypeFlags.FHidden) - ] - internal interface DWebBrowserEvents2 - { - [DispId(102)] - void StatusTextChange([In] string text); - [DispId(104)] - void DownloadComplete(); - [DispId(105)] - void CommandStateChange([In] long command, [In] bool enable); - [DispId(106)] - void DownloadBegin(); - [DispId(108)] - void ProgressChange([In] int progress, [In] int progressMax); - [DispId(112)] - void PropertyChange([In] string szProperty); - [DispId(113)] - void TitleChange([In] string text); - [DispId(225)] - void PrintTemplateInstantiation([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp); - [DispId(226)] - void PrintTemplateTeardown([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp); - [DispId(227)] - void UpdatePageStatus([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, [In] ref object nPage, [In] ref object fDone); - [DispId(250)] - void BeforeNavigate2( - [In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, - [In] ref object URL, - [In] ref object flags, - [In] ref object targetFrameName, - [In] ref object postData, - [In] ref object headers, - [In, Out] ref bool cancel); - [DispId(251)] - void NewWindow2([In, Out, MarshalAs(UnmanagedType.IDispatch)] ref object pDisp, [In, Out] ref bool cancel); - [DispId(252)] - void NavigateComplete2([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, [In] ref object URL); - [DispId(253)] - void OnQuit(); - [DispId(254)] - void OnVisible([In] bool visible); - [DispId(255)] - void OnToolBar([In] bool toolBar); - [DispId(256)] - void OnMenuBar([In] bool menuBar); - [DispId(257)] - void OnStatusBar([In] bool statusBar); - [DispId(258)] - void OnFullScreen([In] bool fullScreen); - [DispId(259)] - void DocumentComplete([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, [In] ref object URL); - [DispId(260)] - void OnTheaterMode([In] bool theaterMode); - [DispId(262)] - void WindowSetResizable([In] bool resizable); - [DispId(263)] - void WindowClosing([In] bool isChildWindow, [In, Out] ref bool cancel); - [DispId(264)] - void WindowSetLeft([In] int left); - [DispId(265)] - void WindowSetTop([In] int top); - [DispId(266)] - void WindowSetWidth([In] int width); - [DispId(267)] - void WindowSetHeight([In] int height); - [DispId(268)] - void ClientToHostWindow([In, Out] ref long cx, [In, Out] ref long cy); - [DispId(269)] - void SetSecureLockIcon([In] int secureLockIcon); - [DispId(270)] - void FileDownload([In, Out] ref bool activeDocument, [In, Out] ref bool cancel); - [DispId(271)] - void NavigateError( - [In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, - [In] ref object URL, - [In] ref object frame, - [In] ref object statusCode, - [In, Out] ref bool cancel); - [DispId(272)] - void PrivacyImpactedStateChange([In] bool bImpacted); - [DispId(282)] // IE 7+ - void SetPhishingFilterStatus(uint phishingFilterStatus); - [DispId(283)] // IE 7+ - void WindowStateChanged(uint dwFlags, uint dwValidFlagsMask); - } - - [ - ComImport, - Guid(IID.HtmlDocument2), - InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual) - ] - internal interface IHtmlDocument2 - { - [return: MarshalAs(UnmanagedType.Interface)] - object GetScript(); - [return: MarshalAs(UnmanagedType.Interface)] - object GetAll(); - [return: MarshalAs(UnmanagedType.Interface)] - object GetBody(); - [return: MarshalAs(UnmanagedType.Interface)] - object GetActiveElement(); - [return: MarshalAs(UnmanagedType.Interface)] - object GetImages(); - [return: MarshalAs(UnmanagedType.Interface)] - object GetApplets(); - [return: MarshalAs(UnmanagedType.Interface)] - object GetLinks(); - [return: MarshalAs(UnmanagedType.Interface)] - object GetForms(); - [return: MarshalAs(UnmanagedType.Interface)] - object GetAnchors(); - void SetTitle([In, MarshalAs(UnmanagedType.BStr)] string p); - [return: MarshalAs(UnmanagedType.BStr)] - string GetTitle(); - [return: MarshalAs(UnmanagedType.Interface)] - object GetScripts(); - void SetDesignMode([In, MarshalAs(UnmanagedType.BStr)] string p); - [return: MarshalAs(UnmanagedType.BStr)] - string GetDesignMode(); - [return: MarshalAs(UnmanagedType.Interface)] - object GetSelection(); - [return: MarshalAs(UnmanagedType.BStr)] - string GetReadyState(); - [return: MarshalAs(UnmanagedType.Interface)] - object GetFrames(); - [return: MarshalAs(UnmanagedType.Interface)] - object GetEmbeds(); - [return: MarshalAs(UnmanagedType.Interface)] - object GetPlugins(); - void SetAlinkColor([In, MarshalAs(UnmanagedType.Struct)] object p); - [return: MarshalAs(UnmanagedType.Struct)] - object GetAlinkColor(); - void SetBackColor([In, MarshalAs(UnmanagedType.Struct)] object p); - [return: MarshalAs(UnmanagedType.Struct)] - object GetBackColor(); - void SetForeColor([In, MarshalAs(UnmanagedType.Struct)] object p); - [return: MarshalAs(UnmanagedType.Struct)] - object GetForeColor(); - void SetLinkColor([In, MarshalAs(UnmanagedType.Struct)] object p); - [return: MarshalAs(UnmanagedType.Struct)] - object GetLinkColor(); - void SetVlinkColor([In, MarshalAs(UnmanagedType.Struct)] object p); - [return: MarshalAs(UnmanagedType.Struct)] - object GetVlinkColor(); - [return: MarshalAs(UnmanagedType.BStr)] - string GetReferrer(); - [return: MarshalAs(UnmanagedType.Interface)] - object GetLocation(); - } - - [ - ComImport, - DefaultMember("Name"), - Guid(IID.WebBrowser2), - InterfaceType(ComInterfaceType.InterfaceIsIDispatch), - ] - interface IWebBrowser2 - { - [DispId(100)] - void GoBack(); - [DispId(0x65)] - void GoForward(); - [DispId(0x66)] - void GoHome(); - [DispId(0x67)] - void GoSearch(); - [DispId(0x68)] - void Navigate([MarshalAs(UnmanagedType.BStr)] string URL, [In] ref object Flags, [In] ref object TargetFrameName, [In] ref object PostData, [In] ref object Headers); - [DispId(-550)] - void Refresh(); - [DispId(0x69)] - void Refresh2([In] ref object Level); - [DispId(0x6a)] - void Stop(); - [DispId(300)] - void Quit(); - [DispId(0x12d)] - void ClientToWindow([In, Out] ref int pcx, [In, Out] ref int pcy); - [DispId(0x12e)] - void PutProperty([MarshalAs(UnmanagedType.BStr)] string Property, object vtValue); - [DispId(0x12f)] - object GetProperty([MarshalAs(UnmanagedType.BStr)] string Property); - [DispId(500)] - void Navigate2([In] ref object URL, [In] ref object Flags, [In] ref object TargetFrameName, [In] ref object PostData, [In] ref object Headers); - [DispId(0x1f5)] - OLECMDF QueryStatusWB(OLECMDID cmdID); - [DispId(0x1f6)] - void ExecWB(OLECMDID cmdID, OLECMDEXECOPT cmdexecopt, [In] ref object pvaIn, [In, Out] ref object pvaOut); - [DispId(0x1f7)] - void ShowBrowserBar([In] ref object pvaClsid, [In] ref object pvarShow, [In] ref object pvarSize); - bool AddressBar { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x22b)] get; [DispId(0x22b)] set; } - object Application { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(200)] get; } - bool Busy { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0xd4)] get; } - object Container { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xca)] get; } - object Document { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xcb)] get; } - string FullName { [return: MarshalAs(UnmanagedType.BStr)] [DispId(400)] get; } - bool FullScreen { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x197)] get; [DispId(0x197)] set; } - int Height { [DispId(0xd1)] get; [DispId(0xd1)] set; } - int HWND { [DispId(-515)] get; } - int Left { [DispId(0xce)] get; [DispId(0xce)] set; } - string LocationName { [return: MarshalAs(UnmanagedType.BStr)] [DispId(210)] get; } - string LocationURL { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0xd3)] get; } - bool MenuBar { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x196)] get; [DispId(0x196)] set; } - string Name { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0)] get; } - bool Offline { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(550)] get; [DispId(550)] set; } - object Parent { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xc9)] get; } - string Path { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x191)] get; } - READYSTATE ReadyState { [DispId(-525)] get; } - bool RegisterAsBrowser { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x228)] get; [DispId(0x228)] set; } - bool RegisterAsDropTarget { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x229)] get; [DispId(0x229)] set; } - bool Resizable { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x22c)] get; [DispId(0x22c)] set; } - bool Silent { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x227)] get; [DispId(0x227)] set; } - bool StatusBar { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x193)] get; [DispId(0x193)] set; } - string StatusText { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x194)] get; [DispId(0x194)] set; } - bool TheaterMode { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x22a)] get; [DispId(0x22a)] set; } - int ToolBar { [DispId(0x195)] get; [DispId(0x195)] set; } - int Top { [DispId(0xcf)] get; [DispId(0xcf)] set; } - bool TopLevelContainer { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0xcc)] get; } - string Type { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0xcd)] get; } - bool Visible { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x192)] get; [DispId(0x192)] set; } - int Width { [DispId(0xd0)] get; [DispId(0xd0)] set; } - } - - internal class WebBrowserEvents : IDisposable - { - private readonly _EventSink _sink; - private SafeConnectionPointCookie _cookie; - - public WebBrowserEvents(WebBrowser browser) - { - if (browser.Document == null) - { - throw new InvalidOperationException("Can't add an event sink until the browser's document is non-null"); - } - - var serviceProvider = (IServiceProvider)browser.Document; - var serviceGuid = new Guid(SID.SWebBrowserApp); - var iid = new Guid(IID.ConnectionPointContainer); - var cpc = (IConnectionPointContainer)serviceProvider.QueryService(ref serviceGuid, ref iid); - - _sink = new _EventSink(this); - _cookie = new SafeConnectionPointCookie(cpc, _sink, new Guid(IID.WebBrowserEvents2)); - } - - // Because the DWebBrowserEvents2 interface is internal, provide our own IDispatch front-end for interop. - private class _EventSink : DWebBrowserEvents2, IReflect - { - private readonly WebBrowserEvents _target; - private static readonly Dictionary _dispIdMethodMap = typeof(DWebBrowserEvents2).GetMethods() - .ToDictionary(mi => ((DispIdAttribute[])mi.GetCustomAttributes(typeof(DispIdAttribute), false))[0].Value); - - internal _EventSink(WebBrowserEvents target) - { - Assert.IsNotNull(target); - _target = target; - } - - #region DWebBrowserEvents2 Members - - public void StatusTextChange(string text) {} - public void DownloadComplete() {} - public void CommandStateChange(long command, bool enable) {} - public void DownloadBegin() {} - public void ProgressChange(int progress, int progressMax) {} - public void PropertyChange(string szProperty) {} - public void TitleChange(string text) {} - public void PrintTemplateInstantiation(object pDisp) {} - public void PrintTemplateTeardown(object pDisp) {} - public void UpdatePageStatus(object pDisp, ref object nPage, ref object fDone) {} - public void BeforeNavigate2(object pDisp, ref object URL, ref object flags, ref object targetFrameName, ref object postData, ref object headers, ref bool cancel) {} - public void NewWindow2(ref object pDisp, ref bool cancel) {} - public void NavigateComplete2(object pDisp, ref object URL) {} - public void OnQuit() {} - public void OnVisible(bool visible) {} - public void OnToolBar(bool toolBar) {} - public void OnMenuBar(bool menuBar) {} - public void OnStatusBar(bool statusBar) {} - public void OnFullScreen(bool fullScreen) {} - public void DocumentComplete(object pDisp, ref object URL) {} - public void OnTheaterMode(bool theaterMode) {} - public void WindowSetResizable(bool resizable) {} - public void WindowClosing(bool isChildWindow, ref bool cancel) - { - _target._NotifyWindowClosing(); - } - public void WindowSetLeft(int left) {} - public void WindowSetTop(int top) {} - public void WindowSetWidth(int width) {} - public void WindowSetHeight(int height) {} - public void ClientToHostWindow(ref long cx, ref long cy) {} - public void SetSecureLockIcon(int secureLockIcon) {} - public void FileDownload(ref bool activeDocument, ref bool cancel) {} - public void NavigateError(object pDisp, ref object URL, ref object frame, ref object statusCode, ref bool cancel) {} - public void PrivacyImpactedStateChange(bool bImpacted) {} - public void SetPhishingFilterStatus(uint phishingFilterStatus) {} - public void WindowStateChanged(uint dwFlags, uint dwValidFlagsMask) {} - - #endregion - - #region IReflect Members - - FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr) { throw new NotImplementedException(); } - FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) { return null; } - MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr) { throw new NotImplementedException(); } - MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr) { throw new NotImplementedException(); } - MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr) { throw new NotImplementedException(); } - MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) { throw new NotImplementedException(); } - MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr) { return null; } - PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr) { return null; } - PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) { throw new NotImplementedException(); } - PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr) { throw new NotImplementedException(); } - - object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) - { - if (name.StartsWith("[DISPID=", StringComparison.OrdinalIgnoreCase)) - { - int dispid = int.Parse(name.Substring(8, name.Length - 9), CultureInfo.InvariantCulture); - MethodInfo method; - if (_dispIdMethodMap.TryGetValue(dispid, out method)) - { - return method.Invoke(this, invokeAttr, binder, args, culture); - } - } - throw new MissingMethodException(GetType().Name, name); - } - - Type IReflect.UnderlyingSystemType { get { return typeof(DWebBrowserEvents2); } } - - #endregion - } - - public event EventHandler WindowClosing; - - private void _NotifyWindowClosing() - { - var handler = WindowClosing; - if (handler != null) - { - handler(this, EventArgs.Empty); - } - } - - #region IDisposable Pattern - - ~WebBrowserEvents() - { - Assert.Fail(); - _Dispose(false); - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "_cookie")] - public void Dispose() - { - _Dispose(true); - GC.SuppressFinalize(this); - } - - private void _Dispose(bool disposing) - { - Utility.SafeDispose(ref _cookie); - } - - #endregion - } - - internal static partial class Utility - { - public static string GetWebPageTitle(WebBrowser browser) - { - if (browser.Document == null) - { - return ""; - } - - return ((IHtmlDocument2)browser.Document).GetTitle(); - } - - public static void SuppressJavaScriptErrors(WebBrowser browser) - { - if (browser.Document != null) - { - var serviceProvider = (IServiceProvider)browser.Document; - var serviceGuid = new Guid(SID.SWebBrowserApp); - var iid = new Guid(IID.WebBrowser2); - var webBrowser2 = (IWebBrowser2)serviceProvider.QueryService(ref serviceGuid, ref iid); - webBrowser2.Silent = true; - } - } - } -} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/Standard/Wpf/SplashScreen.cs b/Microsoft.Windows.Shell/Standard/Wpf/SplashScreen.cs deleted file mode 100644 index 4abab04..0000000 --- a/Microsoft.Windows.Shell/Standard/Wpf/SplashScreen.cs +++ /dev/null @@ -1,344 +0,0 @@ - -namespace Standard -{ - using System; - using System.Globalization; - using System.IO; - using System.Reflection; - using System.Resources; - using System.Runtime.InteropServices; - using System.Windows; - using System.Windows.Threading; - - // Current issues with this implementation: - // * FadeOutDuration will pop the splashscreen in front of the main window. This can be partially managed - // by using IsTopMost, but that has other effects. I should be able to hook the WndProc to keep this - // window from going inactive. - // * FadeInDuration doesn't work because this is being created on the main UI thread. For multiple reasons we - // should probably create this window on a background thread. - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable")] - public class SplashScreen - { - private static readonly BLENDFUNCTION _BaseBlendFunction = new BLENDFUNCTION - { - BlendOp = AC.SRC_OVER, - BlendFlags = 0, - SourceConstantAlpha = 255, - AlphaFormat = AC.SRC_ALPHA, - }; - - private MessageWindow _hwndWrapper; - private SafeHBITMAP _hBitmap; - private DispatcherTimer _dt; - private DateTime _fadeOutEnd; - private DateTime _fadeInEnd; - private ResourceManager _resourceManager; - private string _resourceName; - private Dispatcher _dispatcher; - private Assembly _resourceAssembly; - private bool _isClosed = false; - - private void _VerifyMutability() - { - if (_hwndWrapper != null) - { - throw new InvalidOperationException("Splash screen has already been shown."); - } - } - - public SplashScreen() { } - - public Assembly ResourceAssembly - { - get { return _resourceAssembly; } - set - { - _VerifyMutability(); - - Verify.IsNotNull(value, "value"); - - _resourceAssembly = value; - AssemblyName name = new AssemblyName(_resourceAssembly.FullName); - _resourceManager = new ResourceManager(name.Name + ".g", _resourceAssembly); - } - } - - public string ResourceName - { - get { return _resourceName ?? ""; } - set - { - Verify.IsNeitherNullNorEmpty(value, "value"); - _resourceName = value.ToLowerInvariant(); - } - } - - public string ImageFileName { get; set; } - public bool IsTopMost { get; set; } - public bool CloseOnMainWindowCreation { get; set; } - public TimeSpan FadeOutDuration { get; set; } - public TimeSpan FadeInDuration { get; set; } - - public void Show() - { - _VerifyMutability(); - - Stream imageStream = null; - try - { - // Try to use the filepath first. If it's not provided or not available, use the embedded resource. - if (!string.IsNullOrEmpty(ImageFileName) && File.Exists(ImageFileName)) - { - try - { - imageStream = new FileStream(ImageFileName, FileMode.Open); - } - catch (IOException) { } - } - - if (imageStream == null) - { - imageStream = _resourceManager.GetStream(ResourceName, CultureInfo.CurrentUICulture); - if (imageStream == null) - { - throw new IOException("The resource could not be found."); - } - } - - Size bitmapSize; - _hBitmap = _CreateHBITMAPFromImageStream(imageStream, out bitmapSize); - - Point location = new Point( - (NativeMethods.GetSystemMetrics(SM.CXSCREEN) - bitmapSize.Width) / 2, - (NativeMethods.GetSystemMetrics(SM.CYSCREEN) - bitmapSize.Height) / 2); - - // Pass a null WndProc. Let the MessageWindow use DefWindowProc. - _hwndWrapper = new MessageWindow( - CS.HREDRAW | CS.VREDRAW, - WS.POPUP | WS.VISIBLE, - WS_EX.WINDOWEDGE | WS_EX.TOOLWINDOW | WS_EX.LAYERED | (IsTopMost ? WS_EX.TOPMOST : 0), - new Rect(location, bitmapSize), - "Splash Screen", - null); - - byte opacity = (byte)(FadeInDuration > TimeSpan.Zero ? 0 : 255); - - using (SafeDC hScreenDC = SafeDC.GetDesktop()) - { - using (SafeDC memDC = SafeDC.CreateCompatibleDC(hScreenDC)) - { - IntPtr hOldBitmap = NativeMethods.SelectObject(memDC, _hBitmap); - - RECT hwndRect = NativeMethods.GetWindowRect(_hwndWrapper.Handle); - - POINT hwndPos = hwndRect.Position; - SIZE hwndSize = hwndRect.Size; - POINT origin = new POINT(); - BLENDFUNCTION bf = _BaseBlendFunction; - bf.SourceConstantAlpha = opacity; - - NativeMethods.UpdateLayeredWindow(_hwndWrapper.Handle, hScreenDC, ref hwndPos, ref hwndSize, memDC, ref origin, 0, ref bf, ULW.ALPHA); - NativeMethods.SelectObject(memDC, hOldBitmap); - } - } - - - if (CloseOnMainWindowCreation) - { - Dispatcher.CurrentDispatcher.BeginInvoke( - DispatcherPriority.Loaded, - (DispatcherOperationCallback)delegate(object splashObj) - { - var splashScreen = (SplashScreen)splashObj; - if (!splashScreen._isClosed) - { - splashScreen.Close(); - } - return null; - }, - this); - } - - _dispatcher = Dispatcher.CurrentDispatcher; - if (FadeInDuration > TimeSpan.Zero) - { - _fadeInEnd = DateTime.UtcNow + FadeInDuration; - _dt = new DispatcherTimer(FadeInDuration, DispatcherPriority.Normal, _FadeInTick, _dispatcher); - _dt.Start(); - } - } - finally - { - Utility.SafeDispose(ref imageStream); - } - } - - public void Close() - { - if (!_dispatcher.CheckAccess()) - { - _dispatcher.Invoke(DispatcherPriority.Normal, (Action)Close); - return; - } - - if (_isClosed) - { - throw new InvalidOperationException("Splash screen was already closed"); - } - - _isClosed = true; - - if (FadeOutDuration <= TimeSpan.Zero) - { - _DestroyResources(); - return; - } - - try - { - NativeMethods.SetActiveWindow(_hwndWrapper.Handle); - } - catch - { - // SetActiveWindow fails if the application is not in the foreground. - // If this is the case, don't bother animating the fade out. - _DestroyResources(); - return; - } - - _fadeOutEnd = DateTime.UtcNow + FadeOutDuration; - if (_dt != null) - { - _dt.Stop(); - } - _dt = new DispatcherTimer(TimeSpan.FromMilliseconds(30), DispatcherPriority.Normal, _FadeOutTick, _dispatcher); - _dt.Start(); - - return; - } - - private void _FadeOutTick(object unused, EventArgs args) - { - DateTime dtNow = DateTime.UtcNow; - if (dtNow >= _fadeOutEnd) - { - _DestroyResources(); - } - else - { - double progress = (_fadeOutEnd - dtNow).TotalMilliseconds / FadeOutDuration.TotalMilliseconds; - BLENDFUNCTION bf = _BaseBlendFunction; - bf.SourceConstantAlpha = (byte)(255 * progress); - NativeMethods.UpdateLayeredWindow(_hwndWrapper.Handle, 0, ref bf, ULW.ALPHA); - } - } - - private void _FadeInTick(object unused, EventArgs args) - { - DateTime dtNow = DateTime.UtcNow; - if (dtNow >= _fadeInEnd) - { - _DestroyResources(); - } - else - { - double progress = 1 - (_fadeInEnd - dtNow).TotalMilliseconds / FadeInDuration.TotalMilliseconds; - progress = Math.Max(0, Math.Min(progress, 1)); - BLENDFUNCTION bf = _BaseBlendFunction; - bf.SourceConstantAlpha = (byte)(int)(255 * progress); - NativeMethods.UpdateLayeredWindow(_hwndWrapper.Handle, 0, ref bf, ULW.ALPHA); - } - } - - private void _DestroyResources() - { - if (_dt != null) - { - _dt.Stop(); - _dt = null; - } - Utility.SafeDispose(ref _hwndWrapper); - Utility.SafeDispose(ref _hBitmap); - if (_resourceManager != null) - { - _resourceManager.ReleaseAllResources(); - } - } - - private static SafeHBITMAP _CreateHBITMAPFromImageStream(Stream imgStream, out Size bitmapSize) - { - IWICImagingFactory pImagingFactory = null; - IWICBitmapDecoder pDecoder = null; - IWICStream pStream = null; - IWICBitmapFrameDecode pDecodedFrame = null; - IWICFormatConverter pBitmapSourceFormatConverter = null; - IWICBitmapFlipRotator pBitmapFlipRotator = null; - - SafeHBITMAP hbmp = null; - try - { - using (var istm = new ManagedIStream(imgStream)) - { - pImagingFactory = CLSID.CoCreateInstance(CLSID.WICImagingFactory); - pStream = pImagingFactory.CreateStream(); - pStream.InitializeFromIStream(istm); - - // Create an object that will decode the encoded image - Guid vendor = Guid.Empty; - pDecoder = pImagingFactory.CreateDecoderFromStream(pStream, ref vendor, WICDecodeMetadata.CacheOnDemand); - - pDecodedFrame = pDecoder.GetFrame(0); - pBitmapSourceFormatConverter = pImagingFactory.CreateFormatConverter(); - - // Convert the image from whatever format it is in to 32bpp premultiplied alpha BGRA - Guid pixelFormat = WICPixelFormat.WICPixelFormat32bppPBGRA; - pBitmapSourceFormatConverter.Initialize(pDecodedFrame, ref pixelFormat, WICBitmapDitherType.None, IntPtr.Zero, 0, WICBitmapPaletteType.Custom); - - pBitmapFlipRotator = pImagingFactory.CreateBitmapFlipRotator(); - pBitmapFlipRotator.Initialize(pBitmapSourceFormatConverter, WICBitmapTransform.FlipVertical); - - int width, height; - pBitmapFlipRotator.GetSize(out width, out height); - - bitmapSize = new Size { Width = width, Height = height }; - - var bmi = new BITMAPINFO - { - bmiHeader = new BITMAPINFOHEADER - { - biSize = Marshal.SizeOf(typeof(BITMAPINFOHEADER)), - biWidth = width, - biHeight = height, - biPlanes = 1, - biBitCount = 32, - biCompression = BI.RGB, - biSizeImage = (width * height * 4), - }, - }; - - // Create a 32bpp DIB. This DIB must have an alpha channel for UpdateLayeredWindow to succeed. - IntPtr pBitmapBits; - hbmp = NativeMethods.CreateDIBSection(null, ref bmi, out pBitmapBits, IntPtr.Zero, 0); - - // Copy the decoded image to the new buffer which backs the HBITMAP - var rect = new WICRect { X = 0, Y = 0, Width = width, Height = height }; - pBitmapFlipRotator.CopyPixels(ref rect, width * 4, bmi.bmiHeader.biSizeImage, pBitmapBits); - - var ret = hbmp; - hbmp = null; - return ret; - } - } - finally - { - Utility.SafeRelease(ref pImagingFactory); - Utility.SafeRelease(ref pDecoder); - Utility.SafeRelease(ref pStream); - Utility.SafeRelease(ref pDecodedFrame); - Utility.SafeRelease(ref pBitmapFlipRotator); - Utility.SafeRelease(ref pBitmapSourceFormatConverter); - Utility.SafeDispose(ref hbmp); - } - } - } -} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/Standard/Wpf/Utilities.Wpf.cs b/Microsoft.Windows.Shell/Standard/Wpf/Utilities.Wpf.cs deleted file mode 100644 index b520a35..0000000 --- a/Microsoft.Windows.Shell/Standard/Wpf/Utilities.Wpf.cs +++ /dev/null @@ -1,411 +0,0 @@ -// This file contains general utilities to aid in development. -// Classes here generally shouldn't be exposed publicly since -// they're not particular to any library functionality. -// Because the classes here are internal, it's likely this file -// might be included in multiple assemblies. -namespace Standard -{ - using System; - using System.Collections.Generic; - using System.ComponentModel; - using System.Diagnostics.CodeAnalysis; - using System.Globalization; - using System.IO; - using System.Linq; - using System.Reflection; - using System.Runtime.InteropServices; - using System.Security.Cryptography; - using System.Text; - using System.Windows; - using System.Windows.Media; - using System.Windows.Media.Imaging; - - internal static partial class Utility - { - private static readonly Version _presentationFrameworkVersion = Assembly.GetAssembly(typeof(Window)).GetName().Version; - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static byte[] GetBytesFromBitmapSource(BitmapSource bmp) - { - int width = bmp.PixelWidth; - int height = bmp.PixelHeight; - int stride = width * ((bmp.Format.BitsPerPixel + 7) / 8); - - var pixels = new byte[height * stride]; - - bmp.CopyPixels(pixels, stride, 0); - - return pixels; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static BitmapSource GenerateBitmapSource(ImageSource img) - { - return GenerateBitmapSource(img, img.Width, img.Height); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static BitmapSource GenerateBitmapSource(ImageSource img, double renderWidth, double renderHeight) - { - var dv = new DrawingVisual(); - using (DrawingContext dc = dv.RenderOpen()) - { - dc.DrawImage(img, new Rect(0, 0, renderWidth, renderHeight)); - } - var bmp = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32); - bmp.Render(dv); - return bmp; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static BitmapSource GenerateBitmapSource(UIElement element, double renderWidth, double renderHeight, bool performLayout) - { - if (performLayout) - { - element.Measure(new Size(renderWidth, renderHeight)); - element.Arrange(new Rect(new Size(renderWidth, renderHeight))); - } - - var bmp = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32); - var dv = new DrawingVisual(); - using (DrawingContext dc = dv.RenderOpen()) - { - dc.DrawRectangle(new VisualBrush(element), null, new Rect(0, 0, renderWidth, renderHeight)); - } - bmp.Render(dv); - return bmp; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static void SaveToPng(BitmapSource source, string fileName) - { - var encoder = new PngBitmapEncoder(); - encoder.Frames.Add(BitmapFrame.Create(source)); - - using (FileStream stream = File.Create(fileName)) - { - encoder.Save(stream); - } - } - - // This can be cached. It's not going to change under reasonable circumstances. - private static int s_bitDepth; // = 0; - private static int _GetBitDepth() - { - if (s_bitDepth == 0) - { - using (SafeDC dc = SafeDC.GetDesktop()) - { - s_bitDepth = NativeMethods.GetDeviceCaps(dc, DeviceCap.BITSPIXEL) * NativeMethods.GetDeviceCaps(dc, DeviceCap.PLANES); - } - } - return s_bitDepth; - } - - public static BitmapFrame GetBestMatch(IList frames, int width, int height) - { - return _GetBestMatch(frames, _GetBitDepth(), width, height); - } - - private static int _MatchImage(BitmapFrame frame, int bitDepth, int width, int height, int bpp) - { - int score = 2 * _WeightedAbs(bpp, bitDepth, false) + - _WeightedAbs(frame.PixelWidth, width, true) + - _WeightedAbs(frame.PixelHeight, height, true); - - return score; - } - - private static int _WeightedAbs(int valueHave, int valueWant, bool fPunish) - { - int diff = (valueHave - valueWant); - - if (diff < 0) - { - diff = (fPunish ? -2 : -1) * diff; - } - - return diff; - } - - /// From a list of BitmapFrames find the one that best matches the requested dimensions. - /// The methods used here are copied from Win32 sources. We want to be consistent with - /// system behaviors. - private static BitmapFrame _GetBestMatch(IList frames, int bitDepth, int width, int height) - { - int bestScore = int.MaxValue; - int bestBpp = 0; - int bestIndex = 0; - - bool isBitmapIconDecoder = frames[0].Decoder is IconBitmapDecoder; - - for (int i = 0; i < frames.Count && bestScore != 0; ++i) - { - int currentIconBitDepth = isBitmapIconDecoder ? frames[i].Thumbnail.Format.BitsPerPixel : frames[i].Format.BitsPerPixel; - - if (currentIconBitDepth == 0) - { - currentIconBitDepth = 8; - } - - int score = _MatchImage(frames[i], bitDepth, width, height, currentIconBitDepth); - if (score < bestScore) - { - bestIndex = i; - bestBpp = currentIconBitDepth; - bestScore = score; - } - else if (score == bestScore) - { - // Tie breaker: choose the higher color depth. If that fails, choose first one. - if (bestBpp < currentIconBitDepth) - { - bestIndex = i; - bestBpp = currentIconBitDepth; - } - } - } - - return frames[bestIndex]; - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static int RGB(Color c) - { - return c.R | (c.G << 8) | (c.B << 16); - } - - public static int AlphaRGB(Color c) - { - return c.R | (c.G << 8) | (c.B << 16) | (c.A << 24); - } - - /// Convert a native integer that represent a color with an alpha channel into a Color struct. - /// The integer that represents the color. Its bits are of the format 0xAARRGGBB. - /// A Color representation of the parameter. - public static Color ColorFromArgbDword(uint color) - { - return Color.FromArgb( - (byte)((color & 0xFF000000) >> 24), - (byte)((color & 0x00FF0000) >> 16), - (byte)((color & 0x0000FF00) >> 8), - (byte)((color & 0x000000FF) >> 0)); - } - - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static bool AreImageSourcesEqual(ImageSource left, ImageSource right) - { - if (null == left) - { - return right == null; - } - if (null == right) - { - return false; - } - - BitmapSource leftBmp = GenerateBitmapSource(left); - BitmapSource rightBmp = GenerateBitmapSource(right); - - byte[] leftPixels = GetBytesFromBitmapSource(leftBmp); - byte[] rightPixels = GetBytesFromBitmapSource(rightBmp); - - if (leftPixels.Length != rightPixels.Length) - { - return false; - } - - return MemCmp(leftPixels, rightPixels, leftPixels.Length); - } - - /// - /// Is this using WPF4? - /// - /// - /// There are a few specific bugs in Window in 3.5SP1 and below that require workarounds - /// when handling WM_NCCALCSIZE on the HWND. - /// - public static bool IsPresentationFrameworkVersionLessThan4 - { - get { return _presentationFrameworkVersion < new Version(4, 0); } - } - - // Caller is responsible for destroying the HICON - // Caller is responsible to ensure that GDI+ has been initialized. - [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")] - [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - public static IntPtr GenerateHICON(ImageSource image, Size dimensions) - { - if (image == null) - { - return IntPtr.Zero; - } - - // If we're getting this from a ".ico" resource, then it comes through as a BitmapFrame. - // We can use leverage this as a shortcut to get the right 16x16 representation - // because DrawImage doesn't do that for us. - var bf = image as BitmapFrame; - if (bf != null) - { - bf = GetBestMatch(bf.Decoder.Frames, (int)dimensions.Width, (int)dimensions.Height); - } - else - { - // Constrain the dimensions based on the aspect ratio. - var drawingDimensions = new Rect(0, 0, dimensions.Width, dimensions.Height); - - // There's no reason to assume that the requested image dimensions are square. - double renderRatio = dimensions.Width / dimensions.Height; - double aspectRatio = image.Width / image.Height; - - // If it's smaller than the requested size, then place it in the middle and pad the image. - if (image.Width <= dimensions.Width && image.Height <= dimensions.Height) - { - drawingDimensions = new Rect((dimensions.Width - image.Width) / 2, (dimensions.Height - image.Height) / 2, image.Width, image.Height); - } - else if (renderRatio > aspectRatio) - { - double scaledRenderWidth = (image.Width / image.Height) * dimensions.Width; - drawingDimensions = new Rect((dimensions.Width - scaledRenderWidth) / 2, 0, scaledRenderWidth, dimensions.Height); - } - else if (renderRatio < aspectRatio) - { - double scaledRenderHeight = (image.Height / image.Width) * dimensions.Height; - drawingDimensions = new Rect(0, (dimensions.Height - scaledRenderHeight) / 2, dimensions.Width, scaledRenderHeight); - } - - var dv = new DrawingVisual(); - DrawingContext dc = dv.RenderOpen(); - dc.DrawImage(image, drawingDimensions); - dc.Close(); - - var bmp = new RenderTargetBitmap((int)dimensions.Width, (int)dimensions.Height, 96, 96, PixelFormats.Pbgra32); - bmp.Render(dv); - bf = BitmapFrame.Create(bmp); - } - - // Using GDI+ to convert to an HICON. - // I'd rather not duplicate their code. - using (MemoryStream memstm = new MemoryStream()) - { - BitmapEncoder enc = new PngBitmapEncoder(); - enc.Frames.Add(bf); - enc.Save(memstm); - - using (var istm = new ManagedIStream(memstm)) - { - // We are not bubbling out GDI+ errors when creating the native image fails. - IntPtr bitmap = IntPtr.Zero; - try - { - Status gpStatus = NativeMethods.GdipCreateBitmapFromStream(istm, out bitmap); - if (Status.Ok != gpStatus) - { - return IntPtr.Zero; - } - - IntPtr hicon; - gpStatus = NativeMethods.GdipCreateHICONFromBitmap(bitmap, out hicon); - if (Status.Ok != gpStatus) - { - return IntPtr.Zero; - } - - // Caller is responsible for freeing this. - return hicon; - } - finally - { - Utility.SafeDisposeImage(ref bitmap); - } - } - } - } - - public static void AddDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener) - { - if (component == null) - { - return; - } - Assert.IsNotNull(property); - Assert.IsNotNull(listener); - - DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType()); - dpd.AddValueChanged(component, listener); - } - - public static void RemoveDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener) - { - if (component == null) - { - return; - } - Assert.IsNotNull(property); - Assert.IsNotNull(listener); - - DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType()); - dpd.RemoveValueChanged(component, listener); - } - - public static bool IsThicknessNonNegative(Thickness thickness) - { - if (!IsDoubleFiniteAndNonNegative(thickness.Top)) - { - return false; - } - - if (!IsDoubleFiniteAndNonNegative(thickness.Left)) - { - return false; - } - - if (!IsDoubleFiniteAndNonNegative(thickness.Bottom)) - { - return false; - } - - if (!IsDoubleFiniteAndNonNegative(thickness.Right)) - { - return false; - } - - return true; - } - - public static bool IsCornerRadiusValid(CornerRadius cornerRadius) - { - if (!IsDoubleFiniteAndNonNegative(cornerRadius.TopLeft)) - { - return false; - } - - if (!IsDoubleFiniteAndNonNegative(cornerRadius.TopRight)) - { - return false; - } - - if (!IsDoubleFiniteAndNonNegative(cornerRadius.BottomLeft)) - { - return false; - } - - if (!IsDoubleFiniteAndNonNegative(cornerRadius.BottomRight)) - { - return false; - } - - return true; - } - - private static bool IsDoubleFiniteAndNonNegative(double d) - { - if (double.IsNaN(d) || double.IsInfinity(d) || d < 0) - { - return false; - } - - return true; - } - } -} diff --git a/Microsoft.Windows.Shell/standard.net b/Microsoft.Windows.Shell/standard.net new file mode 160000 index 0000000..95f0048 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net @@ -0,0 +1 @@ +Subproject commit 95f0048696700db4f6bd09347c1218dc57f59879 From 1927292fff3235fa6f53646355496e624fc93daf Mon Sep 17 00:00:00 2001 From: Joe Castro Date: Wed, 29 May 2013 15:57:30 -0700 Subject: [PATCH 05/21] Manual cleanup of msbuild files Removing cruft related to deployments and old version control systems as well as deliberately only targeting AnyCPU. --- Microsoft.Windows.Shell.sln | 16 ---- .../Microsoft.Windows.Shell.csproj | 96 +------------------ Microsoft.Windows.Shell/app.config | 3 - TaskbarSample/TaskbarSample.csproj | 53 ---------- WindowChromeSample/WindowChromeSample.csproj | 86 ----------------- 5 files changed, 3 insertions(+), 251 deletions(-) delete mode 100644 Microsoft.Windows.Shell/app.config diff --git a/Microsoft.Windows.Shell.sln b/Microsoft.Windows.Shell.sln index 04b6074..4e9a2ee 100644 --- a/Microsoft.Windows.Shell.sln +++ b/Microsoft.Windows.Shell.sln @@ -10,31 +10,15 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU - Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Debug|Any CPU.Build.0 = Debug|Any CPU - {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Debug|x86.ActiveCfg = Debug|x86 - {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Debug|x86.Build.0 = Debug|x86 {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Release|Any CPU.ActiveCfg = Release|Any CPU - {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Release|Any CPU.Build.0 = Release|Any CPU - {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Release|x86.ActiveCfg = Release|x86 - {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Release|x86.Build.0 = Release|x86 {F7D0B052-2123-4DFD-B844-C545A1082514}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {F7D0B052-2123-4DFD-B844-C545A1082514}.Debug|Any CPU.Build.0 = Debug|Any CPU - {F7D0B052-2123-4DFD-B844-C545A1082514}.Debug|x86.ActiveCfg = Debug|Any CPU {F7D0B052-2123-4DFD-B844-C545A1082514}.Release|Any CPU.ActiveCfg = Release|Any CPU - {F7D0B052-2123-4DFD-B844-C545A1082514}.Release|Any CPU.Build.0 = Release|Any CPU - {F7D0B052-2123-4DFD-B844-C545A1082514}.Release|x86.ActiveCfg = Release|Any CPU {7E654166-1387-43D9-956C-6B473C514545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7E654166-1387-43D9-956C-6B473C514545}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7E654166-1387-43D9-956C-6B473C514545}.Debug|x86.ActiveCfg = Debug|Any CPU {7E654166-1387-43D9-956C-6B473C514545}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7E654166-1387-43D9-956C-6B473C514545}.Release|Any CPU.Build.0 = Release|Any CPU - {7E654166-1387-43D9-956C-6B473C514545}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj b/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj index 8079209..fb28426 100644 --- a/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj +++ b/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj @@ -12,37 +12,10 @@ Microsoft.Windows.Shell v4.0 512 - - - - - - - - false - - - true - - - 3.5 - - publish\ true Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false false - true Client @@ -54,10 +27,7 @@ prompt 4 true - - AllRules.ruleset - false pdbonly @@ -66,48 +36,15 @@ TRACE prompt 4 - - true AllRules.ruleset - false - - - true - bin\x86\Debug\ - DEBUG;TRACE - full - x86 - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - false - - - bin\x86\Release\ - TRACE - true - pdbonly - x86 - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - false - - 3.0 - - - 3.0 - + + - - 3.0 - + @@ -136,32 +73,5 @@ - - - - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - diff --git a/Microsoft.Windows.Shell/app.config b/Microsoft.Windows.Shell/app.config deleted file mode 100644 index 6ff5afb..0000000 --- a/Microsoft.Windows.Shell/app.config +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/TaskbarSample/TaskbarSample.csproj b/TaskbarSample/TaskbarSample.csproj index 9bb9a97..e8269dd 100644 --- a/TaskbarSample/TaskbarSample.csproj +++ b/TaskbarSample/TaskbarSample.csproj @@ -15,19 +15,7 @@ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 app.ico - false - - - - - - - - - - 3.5 - publish\ true Disk @@ -53,7 +41,6 @@ prompt 4 AllRules.ruleset - false pdbonly @@ -64,7 +51,6 @@ 4 false AllRules.ruleset - false @@ -119,44 +105,5 @@ - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 2.0 %28x86%29 - false - - - False - .NET Framework 3.0 %28x86%29 - false - - - False - .NET Framework 3.5 - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - \ No newline at end of file diff --git a/WindowChromeSample/WindowChromeSample.csproj b/WindowChromeSample/WindowChromeSample.csproj index 0a96f21..16e1527 100644 --- a/WindowChromeSample/WindowChromeSample.csproj +++ b/WindowChromeSample/WindowChromeSample.csproj @@ -14,34 +14,9 @@ 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 - - - - - - - - - - 3.5 - false Client - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true true @@ -53,7 +28,6 @@ 4 AllRules.ruleset false - false pdbonly @@ -63,42 +37,6 @@ prompt 4 AllRules.ruleset - false - - - true - bin\x86\Debug\ - DEBUG;TRACE - full - x86 - bin\Debug\WindowChromeSample.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - false - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - true - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - true - false - - - bin\x86\Release\ - TRACE - true - pdbonly - x86 - bin\Release\WindowChromeSample.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - AllRules.ruleset - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - true - ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - true - false app.ico @@ -145,32 +83,8 @@ Microsoft.Windows.Shell - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - true - - - False - Windows Installer 3.1 - true - - - \ No newline at end of file From 59d25c0fc6c9a1b825cc0466a6dd6eafbb0d9baf Mon Sep 17 00:00:00 2001 From: Joe Castro Date: Wed, 29 May 2013 17:39:42 -0600 Subject: [PATCH 06/21] Update README.md --- README.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 2413fca..5126575 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,13 @@ -wpf-shell -========= +WPF Shell Integration Library (Ex)tended Edition +=== -Further extensions of the WPF Shell Integration Library \ No newline at end of file +This is a .Net library for providing custom chrome for WPF windows and some other deeper integration with +the Windows Shell. It's a concrete implementation of techniques described here: + +http://blogs.msdn.com/b/wpfsdk/archive/2008/09/08/custom-window-chrome-in-wpf.aspx + +It's a fork of the original [WPF Shell Integration Library](http://archive.msdn.microsoft.com/WPFShell), +which hasn't been updated in a while, and the download links for that are for older frameworks and the +source has some bugs that I've addressed since. Some of this code has since been incorporated into the +current .Net framework, but this library gives the ability to use these features in older versions of the +framework, or more deeply extend the interop code to enable more features. From f6dbe4dca6b7c02f81faba9f077dc36de1d0a018 Mon Sep 17 00:00:00 2001 From: Joe Castro Date: Fri, 31 May 2013 15:37:30 -0700 Subject: [PATCH 07/21] Splitting wpf-shell into 2 projects, targeting 3.5 and 4.0+ The Win7 Superbar integration was included in .Net4, so don't need it for projects targeting that runtime. Including it here makes it ambiguous. --- Microsoft.Windows.Shell.sln | 16 +++- Microsoft.Windows.Shell/JumpPath.cs | 3 + .../Microsoft.Windows.Shell.csproj | 77 ------------------- TaskbarSample/TaskbarSample.csproj | 15 ++-- TaskbarSample/app.config | 2 +- WindowChromeSample/WindowChromeSample.csproj | 10 +-- 6 files changed, 28 insertions(+), 95 deletions(-) delete mode 100644 Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj diff --git a/Microsoft.Windows.Shell.sln b/Microsoft.Windows.Shell.sln index 4e9a2ee..6fdfe53 100644 --- a/Microsoft.Windows.Shell.sln +++ b/Microsoft.Windows.Shell.sln @@ -1,24 +1,32 @@  Microsoft Visual Studio Solution File, Format Version 11.00 # Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Windows.Shell", "Microsoft.Windows.Shell\Microsoft.Windows.Shell.csproj", "{55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TaskbarSample", "TaskbarSample\TaskbarSample.csproj", "{F7D0B052-2123-4DFD-B844-C545A1082514}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowChromeSample", "WindowChromeSample\WindowChromeSample.csproj", "{7E654166-1387-43D9-956C-6B473C514545}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Windows.Shell.v4", "Microsoft.Windows.Shell\Microsoft.Windows.Shell.v4.csproj", "{55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Windows.Shell.v35", "Microsoft.Windows.Shell\Microsoft.Windows.Shell.v35.csproj", "{8F016757-F022-4338-9989-9CEE39BFC087}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Release|Any CPU.ActiveCfg = Release|Any CPU {F7D0B052-2123-4DFD-B844-C545A1082514}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {F7D0B052-2123-4DFD-B844-C545A1082514}.Release|Any CPU.ActiveCfg = Release|Any CPU {7E654166-1387-43D9-956C-6B473C514545}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7E654166-1387-43D9-956C-6B473C514545}.Release|Any CPU.ActiveCfg = Release|Any CPU + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB}.Release|Any CPU.Build.0 = Release|Any CPU + {8F016757-F022-4338-9989-9CEE39BFC087}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F016757-F022-4338-9989-9CEE39BFC087}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F016757-F022-4338-9989-9CEE39BFC087}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F016757-F022-4338-9989-9CEE39BFC087}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Microsoft.Windows.Shell/JumpPath.cs b/Microsoft.Windows.Shell/JumpPath.cs index 2a49461..296a3de 100644 --- a/Microsoft.Windows.Shell/JumpPath.cs +++ b/Microsoft.Windows.Shell/JumpPath.cs @@ -1,6 +1,7 @@ /**************************************************************************\ Copyright Microsoft Corporation. All Rights Reserved. \**************************************************************************/ +#if !DOT_NET_4 namespace Microsoft.Windows.Shell { @@ -12,3 +13,5 @@ public JumpPath() public string Path { get; set; } } } + +#endif \ No newline at end of file diff --git a/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj b/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj deleted file mode 100644 index fb28426..0000000 --- a/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj +++ /dev/null @@ -1,77 +0,0 @@ - - - - Debug - AnyCPU - 9.0.30729 - 2.0 - {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB} - Library - Properties - Microsoft.Windows.Shell - Microsoft.Windows.Shell - v4.0 - 512 - false - true - Disk - false - Client - - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - true - AllRules.ruleset - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - true - AllRules.ruleset - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/TaskbarSample/TaskbarSample.csproj b/TaskbarSample/TaskbarSample.csproj index e8269dd..112c3c1 100644 --- a/TaskbarSample/TaskbarSample.csproj +++ b/TaskbarSample/TaskbarSample.csproj @@ -10,7 +10,7 @@ Properties TaskbarSample TaskbarSample - v4.0 + v3.5 512 {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 4 @@ -55,7 +55,6 @@ - @@ -90,12 +89,6 @@ - - - {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB} - Microsoft.Windows.Shell - - @@ -105,5 +98,11 @@ + + + {8F016757-F022-4338-9989-9CEE39BFC087} + Microsoft.Windows.Shell.v35 + + \ No newline at end of file diff --git a/TaskbarSample/app.config b/TaskbarSample/app.config index 6ff5afb..a89b9c6 100644 --- a/TaskbarSample/app.config +++ b/TaskbarSample/app.config @@ -1,3 +1,3 @@ - + diff --git a/WindowChromeSample/WindowChromeSample.csproj b/WindowChromeSample/WindowChromeSample.csproj index 16e1527..07c5084 100644 --- a/WindowChromeSample/WindowChromeSample.csproj +++ b/WindowChromeSample/WindowChromeSample.csproj @@ -78,13 +78,13 @@ - - {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB} - Microsoft.Windows.Shell - + - + + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB} + Microsoft.Windows.Shell.v4 + \ No newline at end of file From e857dea5a683b645fd391548cf94ac42788b703e Mon Sep 17 00:00:00 2001 From: Joe Castro Date: Fri, 31 May 2013 15:42:22 -0700 Subject: [PATCH 08/21] Adding project files missed in last commit --- .../Microsoft.Windows.Shell.v35.csproj | 76 +++++++++++++++++++ .../Microsoft.Windows.Shell.v4.csproj | 70 +++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 Microsoft.Windows.Shell/Microsoft.Windows.Shell.v35.csproj create mode 100644 Microsoft.Windows.Shell/Microsoft.Windows.Shell.v4.csproj diff --git a/Microsoft.Windows.Shell/Microsoft.Windows.Shell.v35.csproj b/Microsoft.Windows.Shell/Microsoft.Windows.Shell.v35.csproj new file mode 100644 index 0000000..0aa82dc --- /dev/null +++ b/Microsoft.Windows.Shell/Microsoft.Windows.Shell.v35.csproj @@ -0,0 +1,76 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {8F016757-F022-4338-9989-9CEE39BFC087} + Library + Properties + Microsoft.Windows.Shell + Microsoft.Windows.Shell + v3.5 + 512 + false + true + Disk + false + Client + + + true + full + false + bin35\Debug\ + TRACE;DEBUG;CODE_ANALYSIS + prompt + 4 + true + AllRules.ruleset + + + pdbonly + true + bin35\Release\ + TRACE + prompt + 4 + true + AllRules.ruleset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Microsoft.Windows.Shell/Microsoft.Windows.Shell.v4.csproj b/Microsoft.Windows.Shell/Microsoft.Windows.Shell.v4.csproj new file mode 100644 index 0000000..523ba32 --- /dev/null +++ b/Microsoft.Windows.Shell/Microsoft.Windows.Shell.v4.csproj @@ -0,0 +1,70 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB} + Library + Properties + Microsoft.Windows.Shell + Microsoft.Windows.Shell + v4.0 + 512 + false + true + Disk + false + Client + + + true + full + false + bin\Debug\ + TRACE;DEBUG;CODE_ANALYSIS + prompt + 4 + true + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + true + AllRules.ruleset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 161f7cdadecc1dd8d1d33c7d0b606e6b206079b5 Mon Sep 17 00:00:00 2001 From: Joe Castro Date: Fri, 31 May 2013 15:51:09 -0700 Subject: [PATCH 09/21] Fixing errant #if in JumpPath --- Microsoft.Windows.Shell/JumpPath.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/Microsoft.Windows.Shell/JumpPath.cs b/Microsoft.Windows.Shell/JumpPath.cs index 296a3de..2a49461 100644 --- a/Microsoft.Windows.Shell/JumpPath.cs +++ b/Microsoft.Windows.Shell/JumpPath.cs @@ -1,7 +1,6 @@ /**************************************************************************\ Copyright Microsoft Corporation. All Rights Reserved. \**************************************************************************/ -#if !DOT_NET_4 namespace Microsoft.Windows.Shell { @@ -13,5 +12,3 @@ public JumpPath() public string Path { get; set; } } } - -#endif \ No newline at end of file From eec024ed2e2686a2c4557ffa438329320038cb55 Mon Sep 17 00:00:00 2001 From: Joe Castro Date: Mon, 3 Jun 2013 17:49:18 -0700 Subject: [PATCH 10/21] Adding ability to create HT_CAPTION styled WPF elements This makes it so you can create WPF visuals that allow you to drag the window around, in the same way as a resize grip. --- Microsoft.Windows.Shell/WindowChrome.cs | 1 + Microsoft.Windows.Shell/WindowChromeWorker.cs | 2 ++ WindowChromeSample/SelectableChromeWindow.xaml | 14 ++++++++++++-- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Microsoft.Windows.Shell/WindowChrome.cs b/Microsoft.Windows.Shell/WindowChrome.cs index f35a515..db3a5dc 100644 --- a/Microsoft.Windows.Shell/WindowChrome.cs +++ b/Microsoft.Windows.Shell/WindowChrome.cs @@ -22,6 +22,7 @@ public enum ResizeGripDirection Bottom, BottomLeft, Left, + Caption, } [Flags] diff --git a/Microsoft.Windows.Shell/WindowChromeWorker.cs b/Microsoft.Windows.Shell/WindowChromeWorker.cs index b8fe06f..883fd5d 100644 --- a/Microsoft.Windows.Shell/WindowChromeWorker.cs +++ b/Microsoft.Windows.Shell/WindowChromeWorker.cs @@ -524,6 +524,8 @@ private HT _GetHTFromResizeGripDirection(ResizeGripDirection direction) return compliment ? HT.TOPRIGHT : HT.TOPLEFT; case ResizeGripDirection.TopRight: return compliment ? HT.TOPLEFT : HT.TOPRIGHT; + case ResizeGripDirection.Caption: + return HT.CAPTION; default: return HT.NOWHERE; } diff --git a/WindowChromeSample/SelectableChromeWindow.xaml b/WindowChromeSample/SelectableChromeWindow.xaml index 7b3fac1..e3b9655 100644 --- a/WindowChromeSample/SelectableChromeWindow.xaml +++ b/WindowChromeSample/SelectableChromeWindow.xaml @@ -47,8 +47,9 @@ + CornerRadius="0" + GlassFrameThickness="1" + UseAeroCaptionButtons="False"/> @@ -82,6 +83,15 @@ CommandParameter="{Binding ElementName=ThisWindow}"> XXX + + From 2e3de482c68a30cdb8d7eecb62a228bd7571b7d8 Mon Sep 17 00:00:00 2001 From: Joe Castro Date: Fri, 7 Jun 2013 11:10:37 -0700 Subject: [PATCH 11/21] Updating standard.net reference and fixing up breaking changes. --- Microsoft.Windows.Shell/WindowChrome.cs | 6 +-- Microsoft.Windows.Shell/WindowChromeWorker.cs | 44 +++++++++++-------- Microsoft.Windows.Shell/standard.net | 2 +- 3 files changed, 30 insertions(+), 22 deletions(-) diff --git a/Microsoft.Windows.Shell/WindowChrome.cs b/Microsoft.Windows.Shell/WindowChrome.cs index db3a5dc..11da800 100644 --- a/Microsoft.Windows.Shell/WindowChrome.cs +++ b/Microsoft.Windows.Shell/WindowChrome.cs @@ -195,7 +195,7 @@ public double CaptionHeight typeof(Thickness), typeof(WindowChrome), new PropertyMetadata(default(Thickness)), - (value) => Utility.IsThicknessNonNegative((Thickness)value)); + (value) => ((Thickness)value).IsNonNegative()); public Thickness ResizeBorderThickness { @@ -216,7 +216,7 @@ private static object _CoerceGlassFrameThickness(Thickness thickness) { // If it's explicitly set, but set to a thickness with at least one negative side then // coerce the value to the stock GlassFrameCompleteThickness. - if (!Utility.IsThicknessNonNegative(thickness)) + if (!thickness.IsNonNegative()) { return GlassFrameCompleteThickness; } @@ -249,7 +249,7 @@ public bool UseAeroCaptionButtons new PropertyMetadata( default(CornerRadius), (d, e) => ((WindowChrome)d)._OnPropertyChangedThatRequiresRepaint()), - (value) => Utility.IsCornerRadiusValid((CornerRadius)value)); + (value) => ((CornerRadius)value).IsValid()); public CornerRadius CornerRadius { diff --git a/Microsoft.Windows.Shell/WindowChromeWorker.cs b/Microsoft.Windows.Shell/WindowChromeWorker.cs index 883fd5d..7b310f8 100644 --- a/Microsoft.Windows.Shell/WindowChromeWorker.cs +++ b/Microsoft.Windows.Shell/WindowChromeWorker.cs @@ -16,9 +16,24 @@ namespace Microsoft.Windows.Shell using Standard; using HANDLE_MESSAGE = System.Collections.Generic.KeyValuePair; + using System.Reflection; internal class WindowChromeWorker : DependencyObject { + private static readonly Version _presentationFrameworkVersion = Assembly.GetAssembly(typeof(Window)).GetName().Version; + + /// + /// Is this using WPF4? + /// + /// + /// There are a few specific bugs in Window in 3.5SP1 and below that require workarounds + /// when handling WM_NCCALCSIZE on the HWND. + /// + private static bool _IsPresentationFrameworkVersionLessThan4 + { + get { return _presentationFrameworkVersion < new Version(4, 0); } + } + // Delegate signature used for Dispatcher.BeginInvoke. private delegate void _Action(); @@ -67,7 +82,7 @@ public WindowChromeWorker() new HANDLE_MESSAGE(WM.DWMCOMPOSITIONCHANGED, _HandleDwmCompositionChanged), }; - if (Utility.IsPresentationFrameworkVersionLessThan4) + if (_IsPresentationFrameworkVersionLessThan4) { _messageTable.AddRange(new[] { @@ -141,9 +156,6 @@ private void _SetWindow(Window window) // If the window hasn't yet been shown, then we need to make sure to remove hooks after it's closed. _hwnd = new WindowInteropHelper(_window).Handle; - // if (Utility.IsPresentationFrameworkVersionLessThan4) - // { - // On older versions of the framework the client size of the window is incorrectly calculated. // We need to modify the template to fix this on behalf of the user. @@ -151,8 +163,6 @@ private void _SetWindow(Window window) // the SacrificialEdge property which requires this kind of fixup to be a bit more ubiquitous. Utility.AddDependencyPropertyChangeListener(_window, Window.TemplateProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); Utility.AddDependencyPropertyChangeListener(_window, Window.FlowDirectionProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); - - // } _window.Closed += _UnsetWindow; @@ -189,7 +199,6 @@ private void _SetWindow(Window window) private void _UnsetWindow(object sender, EventArgs e) { - // if (Utility.IsPresentationFrameworkVersionLessThan4) Utility.RemoveDependencyPropertyChangeListener(_window, Window.TemplateProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); Utility.RemoveDependencyPropertyChangeListener(_window, Window.FlowDirectionProperty, _OnWindowPropertyChangedThatRequiresTemplateFixup); @@ -280,7 +289,7 @@ private void _FixupTemplateIssues() Thickness templateFixupMargin = default(Thickness); Transform templateFixupTransform = null; - if (Utility.IsPresentationFrameworkVersionLessThan4) + if (_IsPresentationFrameworkVersionLessThan4) { RECT rcWindow = NativeMethods.GetWindowRect(_hwnd); RECT rcAdjustedClient = _GetAdjustedWindowRect(rcWindow); @@ -340,7 +349,7 @@ private void _FixupTemplateIssues() rootElement.Margin = templateFixupMargin; rootElement.RenderTransform = templateFixupTransform; - if (Utility.IsPresentationFrameworkVersionLessThan4) + if (_IsPresentationFrameworkVersionLessThan4) { if (!_isFixedUp) { @@ -355,7 +364,7 @@ private void _FixupTemplateIssues() private void _FixupRestoreBounds(object sender, EventArgs e) { - Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + Assert.IsTrue(_IsPresentationFrameworkVersionLessThan4); if (_window.WindowState == WindowState.Maximized || _window.WindowState == WindowState.Minimized) { // Old versions of WPF sometimes force their incorrect idea of the Window's location @@ -381,7 +390,7 @@ private void _FixupRestoreBounds(object sender, EventArgs e) private RECT _GetAdjustedWindowRect(RECT rcWindow) { // This should only be used to work around issues in the Framework that were fixed in 4.0 - Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + Assert.IsTrue(_IsPresentationFrameworkVersionLessThan4); var style = (WS)NativeMethods.GetWindowLongPtr(_hwnd, GWL.STYLE); var exstyle = (WS_EX)NativeMethods.GetWindowLongPtr(_hwnd, GWL.EXSTYLE); @@ -400,7 +409,7 @@ private bool _IsWindowDocked { // We're only detecting this state to work around .Net 3.5 issues. // This logic won't work correctly when those issues are fixed. - Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + Assert.IsTrue(_IsPresentationFrameworkVersionLessThan4); if (_window.WindowState != WindowState.Normal) { @@ -653,7 +662,7 @@ private IntPtr _HandleSettingChange(WM uMsg, IntPtr wParam, IntPtr lParam, out b { // There are several settings that can cause fixups for the template to become invalid when changed. // These shouldn't be required on the v4 framework. - Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + Assert.IsTrue(_IsPresentationFrameworkVersionLessThan4); _FixupTemplateIssues(); @@ -664,7 +673,7 @@ private IntPtr _HandleSettingChange(WM uMsg, IntPtr wParam, IntPtr lParam, out b private IntPtr _HandleEnterSizeMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) { // This is only intercepted to deal with bugs in Window in .Net 3.5 and below. - Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + Assert.IsTrue(_IsPresentationFrameworkVersionLessThan4); _isUserResizing = true; @@ -691,7 +700,7 @@ private IntPtr _HandleEnterSizeMove(WM uMsg, IntPtr wParam, IntPtr lParam, out b private IntPtr _HandleExitSizeMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) { // This is only intercepted to deal with bugs in Window in .Net 3.5 and below. - Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + Assert.IsTrue(_IsPresentationFrameworkVersionLessThan4); _isUserResizing = false; @@ -711,7 +720,7 @@ private IntPtr _HandleExitSizeMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bo private IntPtr _HandleMove(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled) { // This is only intercepted to deal with bugs in Window in .Net 3.5 and below. - Assert.IsTrue(Utility.IsPresentationFrameworkVersionLessThan4); + Assert.IsTrue(_IsPresentationFrameworkVersionLessThan4); if (_isUserResizing) { @@ -1210,11 +1219,10 @@ private void _RestoreTemplateFixups() // This margin is only necessary if the client rect is going to be calculated incorrectly by WPF. // This bug was fixed in V4 of the framework. // But it still needs to happen if there was a SacrificialEdge. - //if (Utility.IsPresentationFrameworkVersionLessThan4) //Assert.IsTrue(_isFixedUp); - Assert.Implies(Utility.IsPresentationFrameworkVersionLessThan4, () => _isFixedUp); + Assert.Implies(_IsPresentationFrameworkVersionLessThan4, () => _isFixedUp); var rootElement = (FrameworkElement)VisualTreeHelper.GetChild(_window, 0); // Undo anything that was done before. diff --git a/Microsoft.Windows.Shell/standard.net b/Microsoft.Windows.Shell/standard.net index 95f0048..9df6c45 160000 --- a/Microsoft.Windows.Shell/standard.net +++ b/Microsoft.Windows.Shell/standard.net @@ -1 +1 @@ -Subproject commit 95f0048696700db4f6bd09347c1218dc57f59879 +Subproject commit 9df6c45c99dea623168c893ed8be8714475756bb From 38b19dcd9926ddd06dd832c31e845c497bdc93c3 Mon Sep 17 00:00:00 2001 From: Jan Karger Date: Mon, 17 Mar 2014 20:24:11 +0100 Subject: [PATCH 12/21] the glass is not gone after setting 0->x->0 with this change it is possible to get a maximized window with hidden taskbar. so we can set initial ```GlassFrameThickness = new Thickness(0)``` with ```WindowStyle=None``` to get a custom window. now if user maximize the window we can set ```GlassFrameThickness = new Thickness(1)``` to get a window that fills the complete monitor and hides the taskbar. with ```GlassFrameThickness = new Thickness(0)``` we can set back to a custom styled window without showing the glass frame. this all works only with ```WindowStyle=None```! --- Microsoft.Windows.Shell/WindowChromeWorker.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Microsoft.Windows.Shell/WindowChromeWorker.cs b/Microsoft.Windows.Shell/WindowChromeWorker.cs index 7b310f8..4534dcf 100644 --- a/Microsoft.Windows.Shell/WindowChromeWorker.cs +++ b/Microsoft.Windows.Shell/WindowChromeWorker.cs @@ -856,6 +856,7 @@ private void _UpdateFrameState(bool force) if (!_isGlassEnabled) { _SetRoundingRegion(null); + _ExtendGlassFrame(); } else { From d3bf8a57c6e2cb08f4b69c2d92c6b53b5b98249f Mon Sep 17 00:00:00 2001 From: Jan Karger Date: Tue, 18 Mar 2014 10:45:15 +0100 Subject: [PATCH 13/21] move ExtendGlassFrame call outside if/else --- Microsoft.Windows.Shell/WindowChromeWorker.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Microsoft.Windows.Shell/WindowChromeWorker.cs b/Microsoft.Windows.Shell/WindowChromeWorker.cs index 4534dcf..efb50f7 100644 --- a/Microsoft.Windows.Shell/WindowChromeWorker.cs +++ b/Microsoft.Windows.Shell/WindowChromeWorker.cs @@ -856,14 +856,15 @@ private void _UpdateFrameState(bool force) if (!_isGlassEnabled) { _SetRoundingRegion(null); - _ExtendGlassFrame(); } else { _ClearRoundingRegion(); - _ExtendGlassFrame(); } + // update the glass frame too, if the user sets the glass frame thickness to 0 at run time + _ExtendGlassFrame(); + NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, _SwpFlags); } } From f7727eb90842e30dc7d68f236ed2610c2b855378 Mon Sep 17 00:00:00 2001 From: Jan Karger Date: Wed, 19 Mar 2014 19:38:00 +0100 Subject: [PATCH 14/21] i think this is a better solution introduce IgnoreTaskbarOnMaximize and use it at _SetRoundingRegion --- Microsoft.Windows.Shell/WindowChrome.cs | 12 ++++++++++++ Microsoft.Windows.Shell/WindowChromeWorker.cs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/Microsoft.Windows.Shell/WindowChrome.cs b/Microsoft.Windows.Shell/WindowChrome.cs index 11da800..c5faa04 100644 --- a/Microsoft.Windows.Shell/WindowChrome.cs +++ b/Microsoft.Windows.Shell/WindowChrome.cs @@ -242,6 +242,18 @@ public bool UseAeroCaptionButtons set { SetValue(UseAeroCaptionButtonsProperty, value); } } + public static readonly DependencyProperty IgnoreTaskbarOnMaximizeProperty = DependencyProperty.Register( + "IgnoreTaskbarOnMaximize", + typeof(bool), + typeof(WindowChrome), + new FrameworkPropertyMetadata(false)); + + public bool IgnoreTaskbarOnMaximize + { + get { return (bool)GetValue(IgnoreTaskbarOnMaximizeProperty); } + set { SetValue(IgnoreTaskbarOnMaximizeProperty, value); } + } + public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register( "CornerRadius", typeof(CornerRadius), diff --git a/Microsoft.Windows.Shell/WindowChromeWorker.cs b/Microsoft.Windows.Shell/WindowChromeWorker.cs index efb50f7..05ecf0a 100644 --- a/Microsoft.Windows.Shell/WindowChromeWorker.cs +++ b/Microsoft.Windows.Shell/WindowChromeWorker.cs @@ -902,7 +902,7 @@ private void _SetRoundingRegion(WINDOWPOS? wp) IntPtr hMon = NativeMethods.MonitorFromWindow(_hwnd, MONITOR_DEFAULTTONEAREST); MONITORINFO mi = NativeMethods.GetMonitorInfo(hMon); - RECT rcMax = mi.rcWork; + RECT rcMax = _chromeInfo.IgnoreTaskbarOnMaximize ? mi.rcMonitor : mi.rcWork; // The location of maximized window takes into account the border that Windows was // going to remove, so we also need to consider it. rcMax.Offset(-left, -top); From 6244c66245955ce08a6d9c9e6d1aa7442979534e Mon Sep 17 00:00:00 2001 From: Joe Castro Date: Mon, 24 Mar 2014 16:54:24 -0700 Subject: [PATCH 15/21] Removing unnecessary change around extending glass frame unconditionally --- Microsoft.Windows.Shell/WindowChrome.cs | 5 +++++ Microsoft.Windows.Shell/WindowChromeWorker.cs | 14 ++++++++++---- Microsoft.Windows.Shell/standard.net | 2 +- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Microsoft.Windows.Shell/WindowChrome.cs b/Microsoft.Windows.Shell/WindowChrome.cs index c5faa04..8c3ab76 100644 --- a/Microsoft.Windows.Shell/WindowChrome.cs +++ b/Microsoft.Windows.Shell/WindowChrome.cs @@ -242,12 +242,17 @@ public bool UseAeroCaptionButtons set { SetValue(UseAeroCaptionButtonsProperty, value); } } + /// Dependency property for IgnoreTaskbarOnMaximize public static readonly DependencyProperty IgnoreTaskbarOnMaximizeProperty = DependencyProperty.Register( "IgnoreTaskbarOnMaximize", typeof(bool), typeof(WindowChrome), new FrameworkPropertyMetadata(false)); + /// + /// If this property is true and the attached window's WindowStyle=None then when the window is maximized it will cover the entire + /// monitor, including the taskbar. + /// public bool IgnoreTaskbarOnMaximize { get { return (bool)GetValue(IgnoreTaskbarOnMaximizeProperty); } diff --git a/Microsoft.Windows.Shell/WindowChromeWorker.cs b/Microsoft.Windows.Shell/WindowChromeWorker.cs index 05ecf0a..6319bda 100644 --- a/Microsoft.Windows.Shell/WindowChromeWorker.cs +++ b/Microsoft.Windows.Shell/WindowChromeWorker.cs @@ -856,15 +856,13 @@ private void _UpdateFrameState(bool force) if (!_isGlassEnabled) { _SetRoundingRegion(null); + _ExtendGlassFrame(); } else { _ClearRoundingRegion(); } - // update the glass frame too, if the user sets the glass frame thickness to 0 at run time - _ExtendGlassFrame(); - NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, _SwpFlags); } } @@ -874,6 +872,14 @@ private void _ClearRoundingRegion() NativeMethods.SetWindowRgn(_hwnd, IntPtr.Zero, NativeMethods.IsWindowVisible(_hwnd)); } + private bool _ShouldRespectTaskbar + { + get + { + return _window.WindowStyle != WindowStyle.None || !_chromeInfo.IgnoreTaskbarOnMaximize; + } + } + private void _SetRoundingRegion(WINDOWPOS? wp) { const int MONITOR_DEFAULTTONEAREST = 0x00000002; @@ -902,7 +908,7 @@ private void _SetRoundingRegion(WINDOWPOS? wp) IntPtr hMon = NativeMethods.MonitorFromWindow(_hwnd, MONITOR_DEFAULTTONEAREST); MONITORINFO mi = NativeMethods.GetMonitorInfo(hMon); - RECT rcMax = _chromeInfo.IgnoreTaskbarOnMaximize ? mi.rcMonitor : mi.rcWork; + RECT rcMax = _ShouldRespectTaskbar ? mi.rcWork : mi.rcMonitor; // The location of maximized window takes into account the border that Windows was // going to remove, so we also need to consider it. rcMax.Offset(-left, -top); diff --git a/Microsoft.Windows.Shell/standard.net b/Microsoft.Windows.Shell/standard.net index 9df6c45..e6616ff 160000 --- a/Microsoft.Windows.Shell/standard.net +++ b/Microsoft.Windows.Shell/standard.net @@ -1 +1 @@ -Subproject commit 9df6c45c99dea623168c893ed8be8714475756bb +Subproject commit e6616ff46316377b51abeedabfd2250c87cef0a7 From 831df3aca71bdd778cf93edfa3a664f26f4a7b7e Mon Sep 17 00:00:00 2001 From: cplotts Date: Wed, 3 Sep 2014 15:30:26 -0500 Subject: [PATCH 16/21] ExtendGlassFrame should be called when glass is enabled. --- Microsoft.Windows.Shell/WindowChromeWorker.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Microsoft.Windows.Shell/WindowChromeWorker.cs b/Microsoft.Windows.Shell/WindowChromeWorker.cs index 6319bda..d33a1a4 100644 --- a/Microsoft.Windows.Shell/WindowChromeWorker.cs +++ b/Microsoft.Windows.Shell/WindowChromeWorker.cs @@ -856,12 +856,12 @@ private void _UpdateFrameState(bool force) if (!_isGlassEnabled) { _SetRoundingRegion(null); - _ExtendGlassFrame(); } else { - _ClearRoundingRegion(); - } + _ClearRoundingRegion(); + _ExtendGlassFrame(); + } NativeMethods.SetWindowPos(_hwnd, IntPtr.Zero, 0, 0, 0, 0, _SwpFlags); } From cb42e5995b2d8c4b77306b07c13f6768d94c81e7 Mon Sep 17 00:00:00 2001 From: cplotts Date: Thu, 4 Sep 2014 10:24:11 -0500 Subject: [PATCH 17/21] Hooking the buttons up to show the system menu. --- WindowChromeSample/SelectableChromeWindow.xaml | 10 ++++++++-- WindowChromeSample/SelectableChromeWindow.xaml.cs | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/WindowChromeSample/SelectableChromeWindow.xaml b/WindowChromeSample/SelectableChromeWindow.xaml index e3b9655..143218c 100644 --- a/WindowChromeSample/SelectableChromeWindow.xaml +++ b/WindowChromeSample/SelectableChromeWindow.xaml @@ -11,6 +11,8 @@ + @@ -32,7 +34,9 @@ VerticalAlignment="Top" HorizontalAlignment="Left" Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(shell:WindowChrome.WindowChrome).ResizeBorderThickness}" - Padding="8"> + Padding="8" + Command="{x:Static shell:SystemCommands.ShowSystemMenuCommand}" + CommandParameter="{Binding ElementName=ThisWindow}"> @@ -69,7 +73,9 @@ VerticalAlignment="Top" HorizontalAlignment="Left" Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(shell:WindowChrome.WindowChrome).ResizeBorderThickness}" - Padding="10"> + Padding="10" + Command="{x:Static shell:SystemCommands.ShowSystemMenuCommand}" + CommandParameter="{Binding ElementName=ThisWindow}"> diff --git a/WindowChromeSample/SelectableChromeWindow.xaml.cs b/WindowChromeSample/SelectableChromeWindow.xaml.cs index 60c6167..e9150d5 100644 --- a/WindowChromeSample/SelectableChromeWindow.xaml.cs +++ b/WindowChromeSample/SelectableChromeWindow.xaml.cs @@ -36,5 +36,10 @@ private void _OnSystemCommandCloseWindow(object sender, ExecutedRoutedEventArgs { SystemCommands.CloseWindow((Window)e.Parameter); } + + private void OnSystemCommandShowSystemMenu(object sender, ExecutedRoutedEventArgs e) + { + SystemCommands.ShowSystemMenu((Window)e.Parameter, this.PointToScreen(Mouse.GetPosition(this))); + } } } From 0add21ef65276afe316c681f12f074a5dd4d68b0 Mon Sep 17 00:00:00 2001 From: Joe Castro Date: Wed, 25 Mar 2015 11:39:48 -0700 Subject: [PATCH 18/21] Adding license information --- license.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 license.md diff --git a/license.md b/license.md new file mode 100644 index 0000000..5511d67 --- /dev/null +++ b/license.md @@ -0,0 +1,33 @@ +#Microsoft Public License (Ms-PL) + +Copyright (c) 2015 Joe Castro + +This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. + +##1. Definitions + +The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. + +A "contribution" is the original software, or any additions or changes to the software. + +A "contributor" is any person that distributes its contribution under this license. + +"Licensed patents" are a contributor's patent claims that read directly on its contribution. + +##2. Grant of Rights + +* (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. + +* (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + +##3. Conditions and Limitations + +* (A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. + +* (B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. + +* (C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. + +* (D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. + +* (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. From 104c44556f50a3b77ae10d43c6a0cac6b2dd2fac Mon Sep 17 00:00:00 2001 From: Joe Castro Date: Mon, 10 Aug 2015 16:00:00 -0700 Subject: [PATCH 19/21] Inlining standard as a subproject --- Microsoft.Windows.Shell/standard.net | 1 - Microsoft.Windows.Shell/standard.net/Csv.cs | 168 + Microsoft.Windows.Shell/standard.net/Debug.cs | 398 ++ .../standard.net/DoubleUtil.cs | 150 + .../standard.net/Enumerable2.cs | 278 ++ .../standard.net/MergeableCollection.cs | 628 +++ .../standard.net/NotifyingList.cs | 189 + .../standard.net/Properties/AssemblyInfo.cs | 21 + .../standard.net/README.md | 4 + .../standard.net/SmallString.cs | 257 ++ .../standard.net/SmallUri.cs | 155 + .../standard.net/Standard.Native.csproj | 66 + .../standard.net/Standard.Wpf.csproj | 82 + .../standard.net/Standard.csproj | 81 + .../standard.net/Standard.sln | 42 + .../standard.net/Utilities.cs | 827 ++++ .../standard.net/Verify.cs | 341 ++ .../standard.net/Windows/ComGuids.cs | 159 + .../standard.net/Windows/ErrorCodes.cs | 631 +++ .../standard.net/Windows/FileWalker.cs | 116 + .../standard.net/Windows/NativeMethods.cs | 3687 +++++++++++++++++ .../standard.net/Windows/ShellProvider.cs | 1311 ++++++ .../standard.net/Windows/StreamHelper.cs | 715 ++++ .../standard.net/Windows/Utilities.Windows.cs | 108 + .../standard.net/Windows/WicProvider.cs | 717 ++++ .../standard.net/Wpf/CornerRadiusAnimation.cs | 547 +++ .../Wpf/CornerRadiusAnimationBase.cs | 191 + .../standard.net/Wpf/DpiHelper.cs | 95 + .../standard.net/Wpf/GlassHelper.cs | 290 ++ .../standard.net/Wpf/MessageWindow.cs | 166 + .../standard.net/Wpf/MshtmlProvider.cs | 412 ++ .../standard.net/Wpf/SingleInstance.cs | 138 + .../standard.net/Wpf/SplashScreen.cs | 350 ++ .../standard.net/Wpf/Utilities.Wpf.cs | 400 ++ .../standard.net/Wpf/WindowExtensions.cs | 137 + 35 files changed, 13857 insertions(+), 1 deletion(-) delete mode 160000 Microsoft.Windows.Shell/standard.net create mode 100644 Microsoft.Windows.Shell/standard.net/Csv.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Debug.cs create mode 100644 Microsoft.Windows.Shell/standard.net/DoubleUtil.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Enumerable2.cs create mode 100644 Microsoft.Windows.Shell/standard.net/MergeableCollection.cs create mode 100644 Microsoft.Windows.Shell/standard.net/NotifyingList.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Properties/AssemblyInfo.cs create mode 100644 Microsoft.Windows.Shell/standard.net/README.md create mode 100644 Microsoft.Windows.Shell/standard.net/SmallString.cs create mode 100644 Microsoft.Windows.Shell/standard.net/SmallUri.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Standard.Native.csproj create mode 100644 Microsoft.Windows.Shell/standard.net/Standard.Wpf.csproj create mode 100644 Microsoft.Windows.Shell/standard.net/Standard.csproj create mode 100644 Microsoft.Windows.Shell/standard.net/Standard.sln create mode 100644 Microsoft.Windows.Shell/standard.net/Utilities.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Verify.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Windows/ComGuids.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Windows/ErrorCodes.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Windows/FileWalker.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Windows/NativeMethods.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Windows/ShellProvider.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Windows/StreamHelper.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Windows/Utilities.Windows.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Windows/WicProvider.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Wpf/CornerRadiusAnimation.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Wpf/CornerRadiusAnimationBase.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Wpf/DpiHelper.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Wpf/GlassHelper.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Wpf/MessageWindow.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Wpf/MshtmlProvider.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Wpf/SingleInstance.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Wpf/SplashScreen.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Wpf/Utilities.Wpf.cs create mode 100644 Microsoft.Windows.Shell/standard.net/Wpf/WindowExtensions.cs diff --git a/Microsoft.Windows.Shell/standard.net b/Microsoft.Windows.Shell/standard.net deleted file mode 160000 index e6616ff..0000000 --- a/Microsoft.Windows.Shell/standard.net +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e6616ff46316377b51abeedabfd2250c87cef0a7 diff --git a/Microsoft.Windows.Shell/standard.net/Csv.cs b/Microsoft.Windows.Shell/standard.net/Csv.cs new file mode 100644 index 0000000..ff1899b --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Csv.cs @@ -0,0 +1,168 @@ +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Linq; + using System.Text; + + internal static class Csv + { + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string Escape(string str) + { + if (string.IsNullOrEmpty(str)) + { + return ""; + } + + if (str.Contains("\"")) + { + str = str.Replace("\"", "\"\""); + } + + if (str.IndexOfAny(new char[] { ',', '"', '\n' }) > -1) + { + str = '\"' + str + '\"'; + } + + return str; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string MakeLine(string[] data) + { + var sb = new StringBuilder(); + foreach (var cell in data) + { + sb.Append(Escape(cell)); + sb.Append(','); + } + + return sb.ToString(0, sb.Length - 1); + } + + // Read a logical line from the stream. It may contain embedded newlines if it was CSV-style escaped. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static string _ReadLine(StreamReader reader) + { + int i = 0; + bool inEscape = false; + bool lastChance = false; + + var sb = new StringBuilder(reader.ReadLine()); + + while (true) + { + for (; i < sb.Length; ++i) + { + if (sb[i] == '\"') + { + inEscape = !inEscape; + } + } + if (!inEscape) + { + return sb.ToString(); + } + sb.Append("\n"); + if (lastChance) + { + throw new ArgumentException("Invalid CSV data."); + } + sb.Append(reader.ReadLine()); + lastChance = reader.EndOfStream; + } + } + + private static readonly string bellString = Encoding.ASCII.GetString(new byte[] { 7 }); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static List _ParseLine(string row) + { + if (!row.Contains('\"')) + { + return new List(row.Split(',')); + } + + // Make it simpler to not have to look for escaped quotes. + row = row.Replace("\"\"", bellString); + + var ret = new List(); + int startIndex = 0; + for (int i = 0; i < row.Length; ++i) + { + if (row[i] == '\"') + { + // Skip the opening quote + startIndex = i + 1; + while (row[++i] != '\"') + { } + + // Remove the trailing quote, and replace back any embedded quotes. + ret.Add(row.Substring(startIndex, i - startIndex).Replace((char)7, '\"')); + + ++i; + if (i < row.Length && row[i] != ',') + { + throw new ArgumentException("Malformed data."); + } + startIndex = i + 1; + } + else + { + if (i >= row.Length - 1 || row[i] == ',') + { + ret.Add(""); + startIndex = i + 1; + continue; + } + + while (i < row.Length-1 && row[++i] != ',') + { } + + ret.Add(row.Substring(startIndex, i - startIndex)); + + if (i < row.Length-1 && row[i] != ',') + { + throw new ArgumentException("Malformed data."); + } + startIndex = i + 1; + } + } + + if (row.EndsWith(",", StringComparison.Ordinal)) + { + ret.Add(""); + } + + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static List> ReadDocument(StreamReader reader) + { + List headers = _ParseLine(_ReadLine(reader)); + var ret = new List>(); + + while (!reader.EndOfStream) + { + var rowData = new Dictionary(); + List cells = _ParseLine(_ReadLine(reader)); + if (cells.Count != headers.Count) + { + throw new ArgumentException("Bad CSV file."); + } + + for (int i = 0; i < headers.Count; ++i) + { + rowData.Add(headers[i], cells[i]); + } + ret.Add(rowData); + } + + return ret; + } + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Debug.cs b/Microsoft.Windows.Shell/standard.net/Debug.cs new file mode 100644 index 0000000..88ac5b1 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Debug.cs @@ -0,0 +1,398 @@ +// Conditional to use more aggressive fail-fast behaviors when debugging. +#define DEV_DEBUG + +// This file contains general utilities to aid in development. +// It is distinct from unit test Assert classes. +// Classes here generally shouldn't be exposed publicly since +// they're not particular to any library functionality. +// Because the classes here are internal, it's likely this file +// might be included in multiple assemblies. +namespace Standard +{ + using System; + using System.Diagnostics; + using System.Threading; + + /// A static class for verifying assumptions. + internal static class Assert + { + // Blend and VS don't like Debugger.Break being called on their design surfaces. Badness will happen. + //private static readonly bool _isNotAtRuntime = (bool)System.ComponentModel.DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(System.Windows.DependencyObject)).DefaultValue; + + private static void _Break() + { + //if (!_isNotAtRuntime) + { +#if DEV_DEBUG + Debugger.Break(); +#else + Debug.Assert(false); +#endif + } + } + + /// A function signature for Assert.Evaluate. + public delegate void EvaluateFunction(); + + /// A function signature for Assert.Implies. + /// Returns the truth of a predicate. + public delegate bool ImplicationFunction(); + + /// + /// Executes the specified argument. + /// + /// The function to execute. + [Conditional("DEBUG")] + public static void Evaluate(EvaluateFunction argument) + { + IsNotNull(argument); + argument(); + } + + /// Obsolete: Use Standard.Assert.AreEqual instead of Assert.Equals + /// The generic type to compare for equality. + /// The first generic type data to compare. This is is the expected value. + /// The second generic type data to compare. This is the actual value. + [ + Obsolete("Use Assert.AreEqual instead of Assert.Equals", false), + Conditional("DEBUG") + ] + public static void Equals(T expected, T actual) + { + AreEqual(expected, actual); + } + + /// + /// Verifies that two generic type data are equal. The assertion fails if they are not. + /// + /// The generic type to compare for equality. + /// The first generic type data to compare. This is is the expected value. + /// The second generic type data to compare. This is the actual value. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void AreEqual(T expected, T actual) + { + if (null == expected) + { + // Two nulls are considered equal, regardless of type semantics. + if (null != actual && !actual.Equals(expected)) + { + _Break(); + } + } + else if (!expected.Equals(actual)) + { + _Break(); + } + } + + [Conditional("DEBUG")] + public static void LazyAreEqual(Func expectedResult, Func actualResult) + { + Assert.IsNotNull(expectedResult); + Assert.IsNotNull(actualResult); + + T actual = actualResult(); + T expected = expectedResult(); + + if (null == expected) + { + // Two nulls are considered equal, regardless of type semantics. + if (null != actual && !actual.Equals(expected)) + { + _Break(); + } + } + else if (!expected.Equals(actual)) + { + _Break(); + } + } + + /// + /// Verifies that two generic type data are not equal. The assertion fails if they are. + /// + /// The generic type to compare for inequality. + /// The first generic type data to compare. This is is the value that's not expected. + /// The second generic type data to compare. This is the actual value. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void AreNotEqual(T notExpected, T actual) + { + if (null == notExpected) + { + // Two nulls are considered equal, regardless of type semantics. + if (null == actual || actual.Equals(notExpected)) + { + _Break(); + } + } + else if (notExpected.Equals(actual)) + { + _Break(); + } + } + + /// + /// Verifies that if the specified condition is true, then so is the result. + /// The assertion fails if the condition is true but the result is false. + /// + /// if set to true [condition]. + /// + /// A second Boolean statement. If the first was true then so must this be. + /// If the first statement was false then the value of this is ignored. + /// + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void Implies(bool condition, bool result) + { + if (condition && !result) + { + _Break(); + } + } + + /// + /// Lazy evaluation overload. Verifies that if a condition is true, then so is a secondary value. + /// + /// The conditional value. + /// A function to be evaluated for truth if the condition argument is true. + /// + /// This overload only evaluates the result if the first condition is true. + /// + [Conditional("DEBUG")] + public static void Implies(bool condition, ImplicationFunction result) + { + if (condition && !result()) + { + _Break(); + } + } + + /// + /// Verifies that a string has content. I.e. it is not null and it is not empty. + /// + /// The string to verify. + [Conditional("DEBUG")] + public static void IsNeitherNullNorEmpty(string value) + { + IsFalse(string.IsNullOrEmpty(value)); + } + + /// + /// Verifies that a string has content. I.e. it is not null and it is not purely whitespace. + /// + /// The string to verify. + [Conditional("DEBUG")] + public static void IsNeitherNullNorWhitespace(string value) + { + if (string.IsNullOrEmpty(value)) + { + _Break(); + } + + if (value.Trim().Length == 0) + { + _Break(); + } + } + + /// + /// Verifies the specified value is not null. The assertion fails if it is. + /// + /// The generic reference type. + /// The value to check for nullness. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsNotNull(T value) where T : class + { + if (null == value) + { + _Break(); + } + } + + [Conditional("DEBUG")] + public static void IsDefault(T value) where T : struct + { + if (!value.Equals(default(T))) + { + Assert.Fail(); + } + } + + [Conditional("DEBUG")] + public static void IsNotDefault(T value) where T : struct + { + if (value.Equals(default(T))) + { + Assert.Fail(); + } + } + + /// + /// Verifies that the specified condition is false. The assertion fails if it is true. + /// + /// The expression that should be false. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsFalse(bool condition) + { + if (condition) + { + _Break(); + } + } + + /// + /// Verifies that the specified condition is false. The assertion fails if it is true. + /// + /// The expression that should be false. + /// The message to display if the condition is true. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsFalse(bool condition, string message) + { + if (condition) + { + _Break(); + } + } + + /// + /// Verifies that the specified condition is true. The assertion fails if it is not. + /// + /// A condition that is expected to be true. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsTrue(bool condition) + { + if (!condition) + { + _Break(); + } + } + + [Conditional("DEBUG")] + public static void IsTrue(Predicate predicate, T arg) + { + if (!predicate(arg)) + { + _Break(); + } + } + + /// + /// Verifies that the specified condition is true. The assertion fails if it is not. + /// + /// A condition that is expected to be true. + /// The message to write in case the condition is false. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsTrue(bool condition, string message) + { + if (!condition) + { + _Break(); + } + } + + /// + /// This line should never be executed. The assertion always fails. + /// + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void Fail() + { + _Break(); + } + + /// + /// This line should never be executed. The assertion always fails. + /// + /// The message to display if this function is executed. + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void Fail(string message) + { + _Break(); + } + + /// + /// Verifies that the specified object is null. The assertion fails if it is not. + /// + /// The item to verify is null. + [Conditional("DEBUG")] + public static void IsNull(T item) where T : class + { + if (null != item) + { + _Break(); + } + } + + /// + /// Verifies that the specified value is within the expected range. The assertion fails if it isn't. + /// + /// The lower bound inclusive value. + /// The value to verify. + /// The upper bound inclusive value. + [Conditional("DEBUG")] + public static void BoundedDoubleInc(double lowerBoundInclusive, double value, double upperBoundInclusive) + { + if (value < lowerBoundInclusive || value > upperBoundInclusive) + { + _Break(); + } + } + + /// + /// Verifies that the specified value is within the expected range. The assertion fails if it isn't. + /// + /// The lower bound inclusive value. + /// The value to verify. + /// The upper bound exclusive value. + [Conditional("DEBUG")] + public static void BoundedInteger(int lowerBoundInclusive, int value, int upperBoundExclusive) + { + if (value < lowerBoundInclusive || value >= upperBoundExclusive) + { + _Break(); + } + } + + /// + /// Verify the current thread's apartment state is what's expected. The assertion fails if it isn't + /// + /// + /// The expected apartment state for the current thread. + /// + /// This breaks into the debugger in the case of a failed assertion. + [Conditional("DEBUG")] + public static void IsApartmentState(ApartmentState expectedState) + { + if (Thread.CurrentThread.GetApartmentState() != expectedState) + { + _Break(); + } + } + + [Conditional("DEBUG")] + public static void NullableIsNotNull(T? value) where T : struct + { + if (null == value) + { + _Break(); + } + } + + [Conditional("DEBUG")] + public static void NullableIsNull(T? value) where T : struct + { + if (null != value) + { + _Break(); + } + } + } +} diff --git a/Microsoft.Windows.Shell/standard.net/DoubleUtil.cs b/Microsoft.Windows.Shell/standard.net/DoubleUtil.cs new file mode 100644 index 0000000..48d0124 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/DoubleUtil.cs @@ -0,0 +1,150 @@ + +namespace Standard +{ + using System; + using System.Diagnostics.CodeAnalysis; + + /// + /// DoubleUtil uses fixed eps to provide fuzzy comparison functionality for doubles. + /// Note that FP noise is a big problem and using any of these compare + /// methods is not a complete solution, but rather the way to reduce + /// the probability of repeating unnecessary work. + /// + internal static class DoubleUtilities + { + /// + /// Epsilon - more or less random, more or less small number. + /// + private const double Epsilon = 0.00000153; + + /// + /// AreClose returns whether or not two doubles are "close". That is, whether or + /// not they are within epsilon of each other. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the AreClose comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool AreClose(double value1, double value2) + { + if (value1 == value2) + { + return true; + } + + double delta = value1 - value2; + return (delta < Epsilon) && (delta > -Epsilon); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsCloseTo(this double value1, double value2) + { + return AreClose(value1, value2); + } + + /// + /// LessThan returns whether or not the first double is less than the second double. + /// That is, whether or not the first is strictly less than *and* not within epsilon of + /// the other number. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the LessThan comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsStrictlyLessThan(this double value1, double value2) + { + return (value1 < value2) && !AreClose(value1, value2); + } + + /// + /// GreaterThan returns whether or not the first double is greater than the second double. + /// That is, whether or not the first is strictly greater than *and* not within epsilon of + /// the other number. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the GreaterThan comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsStrictlyGreaterThan(this double value1, double value2) + { + return (value1 > value2) && !AreClose(value1, value2); + } + + /// + /// LessThanOrClose returns whether or not the first double is less than or close to + /// the second double. That is, whether or not the first is strictly less than or within + /// epsilon of the other number. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the LessThanOrClose comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsLessThanOrCloseTo(this double value1, double value2) + { + return (value1 < value2) || AreClose(value1, value2); + } + + /// + /// GreaterThanOrClose returns whether or not the first double is greater than or close to + /// the second double. That is, whether or not the first is strictly greater than or within + /// epsilon of the other number. + /// There are plenty of ways for this to return false even for numbers which + /// are theoretically identical, so no code calling this should fail to work if this + /// returns false. + /// + /// The first double to compare. + /// The second double to compare. + /// The result of the GreaterThanOrClose comparision. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsGreaterThanOrCloseTo(this double value1, double value2) + { + return (value1 > value2) || AreClose(value1, value2); + } + + /// + /// Test to see if a double is a finite number (is not NaN or Infinity). + /// + /// The value to test. + /// Whether or not the value is a finite number. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFinite(this double value) + { + return !double.IsNaN(value) && !double.IsInfinity(value); + } + + /// + /// Test to see if a double a valid size value (is finite and > 0). + /// + /// The value to test. + /// Whether or not the value is a valid size value. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsValidSize(this double value) + { + return IsFinite(value) && value.IsGreaterThanOrCloseTo(0); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFiniteAndNonNegative(this double d) + { + if (double.IsNaN(d) || double.IsInfinity(d) || d < 0) + { + return false; + } + + return true; + } + + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Enumerable2.cs b/Microsoft.Windows.Shell/standard.net/Enumerable2.cs new file mode 100644 index 0000000..152ef7a --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Enumerable2.cs @@ -0,0 +1,278 @@ + +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + + /// + /// Further LINQ extensions + /// + internal static class Enumerable2 + { + // Unnecessary in .Net 4. + //public static IEnumerable Zip(this IEnumerable first, IEnumerable second, Func func) + //{ + // Verify.IsNotNull(first, "first"); + // Verify.IsNotNull(second, "second"); + + // return _Zip(first, second, func); + //} + + //private static IEnumerable _Zip(this IEnumerable first, IEnumerable second, Func func) + //{ + // IEnumerator ie1 = first.GetEnumerator(); + // IEnumerator ie2 = second.GetEnumerator(); + // while (ie1.MoveNext() && ie2.MoveNext()) + // { + // yield return func(ie1.Current, ie2.Current); + // } + //} + + /// Partition a collection into two, based on whether the items match a predicate. + /// The type of the enumeration. + /// The original collection to split. + /// The condition to use for the split. + /// A collection of all items in the original collection that do not satisfy the condition. + /// A collection of all items in the original collection that satisfy the condition. + /// Unlike most extension methods of this nature, this does not perform the operation lazily. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IEnumerable SplitWhere(this IEnumerable collection, Predicate condition, out IEnumerable rest) + { + Verify.IsNotNull(collection, "collection"); + Verify.IsNotNull(condition, "condition"); + + var passList = new List(); + var failList = new List(); + + foreach (T t in collection) + { + if (condition(t)) + { + passList.Add(t); + } + else + { + failList.Add(t); + } + } + + rest = failList; + return passList; + } + + /// + /// Limit an enumeration to be constrained to a subset after a given index. + /// + /// The type of items being enumerated. + /// The collection to be enumerated. + /// The index (inclusive) of the first item to be returned. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IEnumerable Sublist(this IEnumerable enumerable, int startIndex) + { + return Sublist(enumerable, startIndex, null); + } + + /// + /// Limit an enumeration to be within a set of indices. + /// + /// The type of items being enumerated. + /// The collection to be enumerated. + /// The index (inclusive) of the first item to be returned. + /// + /// The index (exclusive) of the last item to be returned. + /// If this is null then the full collection after startIndex is returned. + /// If this is greater than the count of the collection after startIndex, then the full collection after startIndex is returned. + /// + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IEnumerable Sublist(this IEnumerable enumerable, int startIndex, int? endIndex) + { + Verify.IsNotNull(enumerable, "enumerable"); + Verify.BoundedInteger(0, startIndex, int.MaxValue, "startIndex"); + if (endIndex != null) + { + Verify.BoundedInteger(startIndex, endIndex.Value, int.MaxValue, "endIndex"); + } + + // If this supports indexing then just use that. + var list = enumerable as IList; + if (list != null) + { + return _SublistList(list, startIndex, endIndex); + } + + return _SublistEnum(enumerable, startIndex, endIndex); + } + + private static IEnumerable _SublistEnum(this IEnumerable enumerable, int startIndex, int? endIndex) + { + int currentIndex = 0; + IEnumerator enumerator = enumerable.GetEnumerator(); + while (currentIndex < startIndex && enumerator.MoveNext()) + { + ++currentIndex; + } + + int trueEndIndex = endIndex ?? int.MaxValue; + + while (currentIndex < trueEndIndex && enumerator.MoveNext()) + { + yield return enumerator.Current; + ++currentIndex; + } + } + + private static IEnumerable _SublistList(this IList list, int startIndex, int? endIndex) + { + int trueEndIndex = Math.Min(list.Count, endIndex ?? int.MaxValue); + for (int i = startIndex; i < trueEndIndex; ++i) + { + yield return list[i]; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool AreSorted(this IEnumerable enumerable) + { + return _AreSorted(enumerable, null); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool AreSorted(this IEnumerable enumerable, Comparison comparison) + { + Verify.IsNotNull(enumerable, "enumerable"); + if (comparison == null) + { + if (typeof(T).GetInterface(typeof(IComparable).Name) == null) + { + // Not comparable for a sort. + return true; + } + + comparison = delegate(T left, T right) + { + if (left == null) + { + if (right == null) + { + return 0; + } + return -((IComparable)right).CompareTo(left); + } + return ((IComparable)left).CompareTo(right); + }; + } + + return _AreSorted(enumerable, comparison); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static bool _AreSorted(IEnumerable enumerable, Comparison comparison) + { + var enumerator = enumerable.GetEnumerator(); + if (!enumerator.MoveNext()) + { + return true; + } + + T last = enumerator.Current; + while (enumerator.MoveNext()) + { + if (comparison(last, enumerator.Current) > 0) + { + return false; + } + last = enumerator.Current; + } + + return true; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void AddRange(this ICollection collection, params T[] items) + { + Verify.IsNotNull(collection, "collection"); + _AddRange(collection, items); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void AddRange(this ICollection collection, IEnumerable items) + { + Verify.IsNotNull(collection, "collection"); + _AddRange(collection, items); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static void _AddRange(ICollection collection, IEnumerable items) + { + if (items == null) + { + return; + } + + foreach (var item in items) + { + collection.Add(item); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IEnumerable Reverse(this IList list) + { + Verify.IsNotNull(list, "list"); + return _Reverse(list); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static IEnumerable _Reverse(IList list) + { + for (int i = list.Count - 1; i >= 0; --i) + { + yield return list[i]; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IList Shuffle(this IList list) + { + var r = new Random(); + return Shuffle(list, () => r.Next(list.Count)); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IList Shuffle(this IList list, Func numberGenerator) + { + Verify.IsNotNull(list, "list"); + Verify.IsNotNull(numberGenerator, "numberGenerator"); + + var swapIndices = new int[list.Count]; + for (int i = 0; i < list.Count; ++i) + { + int j = numberGenerator(); + if (j < 0 || j >= list.Count) + { + throw new ArgumentException("The number generator function generated a number outside the valid range."); + } + swapIndices[i] = j; + } + return _Shuffle(list, swapIndices); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static IList _Shuffle(IList list, int[] swapIndices) + { + Assert.AreEqual(list.Count, swapIndices.Length); + for (int i = swapIndices.Length; i > 1; --i) + { + int k = swapIndices[i-1]; + T temp = list[k]; + list[k] = list[i-1]; + list[i-1] = temp; + } + + return list; + } + } +} diff --git a/Microsoft.Windows.Shell/standard.net/MergeableCollection.cs b/Microsoft.Windows.Shell/standard.net/MergeableCollection.cs new file mode 100644 index 0000000..79b5433 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/MergeableCollection.cs @@ -0,0 +1,628 @@ +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Collections.Specialized; + using System.ComponentModel; + using System.Linq; + + internal interface IMergeable : IEquatable where TKey : IEquatable + { + /// Immutable foreign key for the object + TKey FKID { get; } + + /// Merge the properties of another object of like type with this one. + /// The object to merge + void Merge(TItem other); + } + + internal class MergeableCollection : IList, INotifyCollectionChanged where TItem : class where TKey : IEquatable + { + private class _Comparer : IComparer + { + private bool _dontCompare = false; + private Comparison _defaultComparison; + private Comparison _customComparison; + private Comparison _trueComparison; + + public _Comparer() + { + if (Utility.IsInterfaceImplemented(typeof(TItem), typeof(IComparable))) + { + _defaultComparison = (left, right) => + { + if (object.ReferenceEquals(left, right)) + { + return 0; + } + + var comparableLeft = (IComparable)left; + if (comparableLeft == null) + { + return -1; + } + + return comparableLeft.CompareTo(right); + }; + } + + _trueComparison = _defaultComparison; + } + + public Comparison Comparison + { + get { return _trueComparison; } + set + { + Assert.IsFalse(_dontCompare); + if (!_dontCompare) + { + _customComparison = value; + _trueComparison = _customComparison ?? _defaultComparison; + } + } + } + + public bool CanCompare + { + get { return _trueComparison != null; } + } + + public void StopComparisons() + { + _trueComparison = null; + _dontCompare = true; + } + + public int Compare(TItem x, TItem y) + { + Assert.IsTrue(CanCompare); + return _trueComparison(x, y); + } + + public IEnumerable OrderedList(IEnumerable original) + { + Assert.IsNotNull(original); + + if (!CanCompare) + { + return original; + } + + return original.OrderBy(x => x, this); + } + } + + private readonly bool _areItemsMergable; + private readonly bool _areItemsNotifiable; + private readonly ObservableCollection _items; + private readonly Dictionary _fkidLookup; + private _Comparer _itemComparer = new _Comparer(); + + // Block reentrancy that would cause the collection to be reordered. + // If while we're doing a merge we get change notifications that the item has changed, ignore it. + private IMergeable _suspendNotificationsForMergeableObject; + + public object SyncRoot { get; private set; } + + public MergeableCollection() + : this(null, true) + {} + + public MergeableCollection(bool sort) + : this(null, sort) + {} + + public MergeableCollection(IEnumerable dataObjects) + : this(dataObjects, true) + {} + + public MergeableCollection(IEnumerable dataObjects, bool sort) + { + SyncRoot = new object(); + + if (!sort) + { + _itemComparer.StopComparisons(); + } + + // We don't really want to constrain based on the type being IMergeable or comparable + // This is a very specific check. We want to ensure that this type supports IMergeable, not IMergeable + _areItemsMergable = Utility.IsInterfaceImplemented(typeof(TItem), typeof(IMergeable)); + _areItemsNotifiable = Utility.IsInterfaceImplemented(typeof(TItem), typeof(INotifyPropertyChanged)); + + if (dataObjects == null) + { + _items = new ObservableCollection(); + } + else + { + _items = new ObservableCollection(_itemComparer.OrderedList(dataObjects)); + if (_areItemsNotifiable) + { + lock (SyncRoot) + { + foreach (INotifyPropertyChanged item in _items) + { + item.PropertyChanged += _OnItemChanged; + } + } + } + } + + if (_areItemsMergable) + { + _fkidLookup = new Dictionary(); + foreach (IMergeable item in _items) + { + //Assert.IsNotNull(item.FKID); + _fkidLookup.Add(item.FKID, (TItem)item); + } + } + } + + public Comparison CustomComparison + { + get { return _itemComparer.Comparison; } + set + { + if (_itemComparer.Comparison != value) + { + _itemComparer.Comparison = value; + RefreshSort(); + } + } + } + + public void RefreshSort() + { + if (_itemComparer.CanCompare) + { + lock (SyncRoot) + { + if (!_AreItemsSortedUpToIndex(_items.Count)) + { + var copyList = new List(_items); + // Clear the list first so we don't bubble-sort just to reorder. + _Merge(null, false, null); + _Merge(copyList, false, null); + } + } + } + } + + /// + /// Merges data from another collection. + /// + /// The data object collection that contains new data. + /// + /// If true, combine the new collection with existing content, otherwise replace the list. + /// + public void Merge(IEnumerable newCollection, bool add) + { + _Merge(newCollection, add, null); + } + + public void Merge(IEnumerable newCollection, bool add, int? maxCount) + { + _Merge(newCollection, add, maxCount); + } + + private void _Merge(IEnumerable newCollection, bool add, int? maxCount) + { + // These should never get out of sync. + Assert.Implies(_areItemsMergable, () => _items.Count == _fkidLookup.Count); + + lock (SyncRoot) + { + // Go-go partial template specialization! + if (_areItemsMergable) + { + _RichMerge(newCollection, add, maxCount); + } + else + { + _SimpleMerge(newCollection, add, maxCount); + } + } + } + + public TItem FindFKID(TKey id) + { + lock (SyncRoot) + { + if (!_areItemsMergable) + { + throw new InvalidOperationException("This can only be used on collections with mergable items."); + } + + TItem ret; + if (_fkidLookup.TryGetValue(id, out ret)) + { + return ret; + } + return null; + } + } + + private int _FindIndex(int startIndex, Predicate> match) + { + int count = Count - startIndex; + for (int i = startIndex; i < startIndex + count; ++i) + { + if (match((IMergeable)this[i])) + { + return i; + } + } + + return -1; + } + + private bool _VerifyInsertionPoint(int index) + { + lock (SyncRoot) + { + if (_itemComparer.Comparison == null) + { + // We don't have any way of determining a correct order. Whatever we have is fine. + return true; + } + + // Make sure that the item at index is not less than the one before it + // and not greater than the one after it. + // If this fails, we need to update the list. + + if (index != 0) + { + if (_itemComparer.Compare(_items[index - 1], _items[index]) > 0) + { + return false; + } + } + + if (index < _items.Count - 1) + { + if (_itemComparer.Compare(_items[index], _items[index+1]) > 0) + { + return false; + } + } + + return true; + } + } + + private int _FindInsertionPoint(TItem item) + { + Assert.IsNotNull(item); + + if (_itemComparer.Comparison != null) + { + for (int i = 0; i < _items.Count; ++i) + { + if (_itemComparer.Compare(item, _items[i]) <= 0) + { + return i; + } + } + } + + return -1; + } + + /// + /// Safe version of Clear that removes references to this from the items being removed. + /// + private void _MergeClear() + { + if (_areItemsNotifiable) + { + foreach (var item in _items) + { + _SafeRemoveNotifyAndLookup(item); + } + } + _items.Clear(); + + if (_fkidLookup != null) + { + _fkidLookup.Clear(); + } + } + + private void _RichMerge(IEnumerable newCollection, bool additive, int? maxCount) + { + lock (SyncRoot) + { + if (newCollection == null) + { + _MergeClear(); + return; + } + + if (!additive) + { + int index = -1; + foreach (TItem newItem in _itemComparer.OrderedList(newCollection).Sublist(0, maxCount)) + { + var mergeableItem = newItem as IMergeable; + + ++index; + //Assert.IsNotNull(mergeableItem.FKID); + int oldIndex = _FindIndex(index, p => mergeableItem.FKID.Equals(p.FKID)); + if (oldIndex == -1) + { + _items.Insert(index, newItem); + _SafeAddNotifyAndLookup(newItem); + continue; + } + else if (oldIndex != index) + { + _items.Move(oldIndex, index); + } + + _suspendNotificationsForMergeableObject = (IMergeable)this[index]; + _suspendNotificationsForMergeableObject.Merge(newItem); + _suspendNotificationsForMergeableObject = null; + + Assert.IsTrue(unused => _AreItemsSortedUpToIndex(index), null); + } + + if (index != -1) + { + ++index; + _RemoveRange(index); + } + else + { + _MergeClear(); + } + } + else + { + foreach (var item in newCollection) + { + var mergableItem = (IMergeable)item; + + int index = _FindIndex(0, p => p.FKID.Equals(mergableItem.FKID)); + if (index == -1) + { + index = _FindInsertionPoint(item); + + if (-1 == index) + { + _items.Add(item); + } + else + { + _items.Insert(index, item); + } + _SafeAddNotifyAndLookup(item); + } + else + { + _suspendNotificationsForMergeableObject = (IMergeable)this[index]; + _suspendNotificationsForMergeableObject.Merge(item); + _suspendNotificationsForMergeableObject = null; + } + } + } + + if (maxCount != null && _items.Count > maxCount.Value) + { + _RemoveRange(maxCount.Value); + } + + //Assert.Implies(_areItemsComparable || _customComparison != null, () => _items.AreSorted(_customComparison)); + } + } + + private bool _AreItemsSortedUpToIndex(int index) + { + if (_itemComparer.CanCompare) + { + for (int i = 1; i < index; ++i) + { + if (_itemComparer.Comparison(_items[i - 1], _items[i]) > 0) + { + return false; + } + } + } + return true; + } + + private void _RemoveRange(int index) + { + while (index < _items.Count) + { + _SafeRemoveNotifyAndLookup(_items[index]); + _items.RemoveAt(index); + } + } + + private void _SimpleMerge(IEnumerable newCollection, bool add, int? maxCount) + { + lock (SyncRoot) + { + if (!add) + { + // This just replaces the entire collection. + _MergeClear(); + + if (newCollection == null) + { + return; + } + + foreach (TItem item in _itemComparer.OrderedList(newCollection).Sublist(0, maxCount)) + { + _items.Add(item); + _SafeAddNotifyAndLookup(item); + } + } + else + { + foreach (var item in newCollection) + { + if (!_items.Contains(item)) + { + int index = _FindInsertionPoint(item); + + if (-1 == index) + { + _items.Add(item); + } + else + { + _items.Insert(index, item); + } + _SafeAddNotifyAndLookup(item); + } + } + + if (maxCount != null && _items.Count > maxCount.Value) + { + _RemoveRange(maxCount.Value); + } + } + //Assert.Implies(_areItemsComparable || _customComparison != null, () => _items.AreSorted(_customComparison)); + } + } + + private void _SafeAddNotifyAndLookup(TItem item) + { + Assert.IsNotNull(item); + if (_areItemsNotifiable) + { + ((INotifyPropertyChanged)item).PropertyChanged += _OnItemChanged; + } + + if (_areItemsMergable) + { + //Assert.IsNotNull(((IMergeable)item).FKID); + _fkidLookup.Add(((IMergeable)item).FKID, item); + } + } + + private void _SafeRemoveNotifyAndLookup(TItem item) + { + Assert.IsNotNull(item); + if (_areItemsNotifiable) + { + ((INotifyPropertyChanged)item).PropertyChanged -= _OnItemChanged; + } + + if (_areItemsMergable) + { + //Assert.IsNotNull(((IMergeable)item).FKID); + _fkidLookup.Remove(((IMergeable)item).FKID); + } + } + + private void _OnItemChanged(object sender, PropertyChangedEventArgs e) + { + var item = sender as TItem; + // If we're doing a merge of this item then we expect that properties may change. + // Don't reorder because of this. We expect the merge is putting the item in the right place. + if (item != null && item != _suspendNotificationsForMergeableObject) + { + lock (SyncRoot) + { + int currentIndex = _items.IndexOf(item); + if (-1 != currentIndex) + { + if (!_VerifyInsertionPoint(currentIndex)) + { + _items.RemoveAt(currentIndex); + int newIndex = _FindInsertionPoint(item); + if (newIndex == -1 || newIndex == _items.Count) + { + _items.Add(item); + } + else + { + _items.Insert(newIndex, item); + } + } + } + + //Assert.IsTrue(_items.AreSorted(_customComparison)); + } + } + } + + #region IList Members + + public int IndexOf(TItem item) { return _items.IndexOf(item); } + + public TItem this[int index] + { + get { return _items[index]; } + set { throw new NotSupportedException(); } + } + + #region Unsupported Mutable IList Members + void IList.Insert(int index, TItem item) { throw new NotSupportedException(); } + void IList.RemoveAt(int index) { throw new NotSupportedException(); } + #endregion + + #endregion + + #region ICollection Members + + public bool Contains(TItem item) { return _items.Contains(item); } + public void CopyTo(TItem[] array, int arrayIndex) { _items.CopyTo(array, arrayIndex); } + public int Count { get { return _items.Count; } } + public bool IsReadOnly { get { return true; } } + + public void Clear() { Merge(null, false); } + + public void Add(TItem item) + { + Verify.IsNotNull(item, "item"); + Merge(new [] { item }, true); + } + + public bool Remove(TItem item) + { + Verify.IsNotNull(item, "item"); + + lock (SyncRoot) + { + if (_items.Remove(item)) + { + _SafeRemoveNotifyAndLookup(item); + return true; + } + return false; + } + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() { return _items.GetEnumerator(); } + + #endregion + + #region IEnumerable Members + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } + + #endregion + + #region INotifyCollectionChanged Members + + public event NotifyCollectionChangedEventHandler CollectionChanged + { + add { _items.CollectionChanged += value; } + remove { _items.CollectionChanged -= value; } + } + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/standard.net/NotifyingList.cs b/Microsoft.Windows.Shell/standard.net/NotifyingList.cs new file mode 100644 index 0000000..be91f53 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/NotifyingList.cs @@ -0,0 +1,189 @@ + +namespace Standard +{ + using System.Collections; + using System.Collections.Generic; + using System.Collections.ObjectModel; + using System.Collections.Specialized; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + internal class NotifyingList : IList, INotifyCollectionChanged where T : INotifyPropertyChanged + { + private readonly ObservableCollection _list; + + public event PropertyChangedEventHandler ItemPropertyChanged; + + private void _SafeAddPropertyListener(T item) + { + if (item != null) + { + item.PropertyChanged += _OnItemPropertyChanged; + } + } + + private void _SafeRemovePropertyListener(T item) + { + if (item != null) + { + item.PropertyChanged -= _OnItemPropertyChanged; + } + } + + public NotifyingList() + { + _list = new ObservableCollection(); + } + + public NotifyingList(IEnumerable collection) + { + _list = new ObservableCollection(collection); + foreach (T item in collection) + { + _SafeAddPropertyListener(item); + } + } + + private void _OnItemPropertyChanged(object sender, PropertyChangedEventArgs e) + { + var handler = ItemPropertyChanged; + if (handler != null) + { + handler(sender, e); + } + } + + #region IList Members + + public int IndexOf(T item) + { + return _list.IndexOf(item); + } + + public void Insert(int index, T item) + { + _list.Insert(index, item); + _SafeAddPropertyListener(item); + } + + public void RemoveAt(int index) + { + T item = _list[index]; + _list.RemoveAt(index); + _SafeRemovePropertyListener(item); + } + + public T this[int index] + { + get { return _list[index]; } + set { _list[index] = value; } + } + + #endregion + + #region ICollection Members + + public void Add(T item) + { + _list.Add(item); + _SafeAddPropertyListener(item); + } + + public void Clear() + { + T[] items = new T[_list.Count]; + _list.CopyTo(items, 0); + _list.Clear(); + foreach (T item in items) + { + _SafeRemovePropertyListener(item); + } + } + + public bool Contains(T item) + { + return _list.Contains(item); + } + + public void CopyTo(T[] array, int arrayIndex) + { + _list.CopyTo(array, arrayIndex); + } + + public int Count { get { return _list.Count; } } + + public bool IsReadOnly { get { return false; } } + + public bool Remove(T item) + { + // Don't call through _list.Remove(). + // If equality has been overloaded then we may try removing the handler + // from a different object and we'll leak it. + // Ensure reference equality. + int index = _list.IndexOf(item); + if (index == -1) + { + return false; + } + + RemoveAt(index); + return true; + } + + #endregion + + #region IEnumerable Members + + public IEnumerator GetEnumerator() + { + return _list.GetEnumerator(); + } + + #endregion + + #region IEnumerable Members + + IEnumerator IEnumerable.GetEnumerator() + { + return _list.GetEnumerator(); + } + + #endregion + + #region INotifyCollectionChanged Members + + private event NotifyCollectionChangedEventHandler _sourceCollectionChanged; + + public event NotifyCollectionChangedEventHandler CollectionChanged + { + add + { + if (_sourceCollectionChanged == null) + { + _list.CollectionChanged += _OnSourceCollectionChanged; + } + _sourceCollectionChanged += value; + } + remove + { + _sourceCollectionChanged -= value; + if (_sourceCollectionChanged == null) + { + _list.CollectionChanged -= _OnSourceCollectionChanged; + } + } + } + + private void _OnSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + var handler = _sourceCollectionChanged; + if (handler != null) + { + handler(this, e); + } + } + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Properties/AssemblyInfo.cs b/Microsoft.Windows.Shell/standard.net/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..5e6d9c1 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Properties/AssemblyInfo.cs @@ -0,0 +1,21 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +[assembly: AssemblyTitle("Standard")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Standard")] +[assembly: AssemblyCopyright("Copyright © Joe Castro 2013")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] +[assembly: Guid("559D8E94-8DB7-4891-941E-95122BAFC2B4")] + +[assembly: AssemblyVersion("0.1.0.0")] +[assembly: AssemblyFileVersion("0.1.0.0")] + +// Never intended to ship as a real assembly. These files should be linked into the containing projects. +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames")] diff --git a/Microsoft.Windows.Shell/standard.net/README.md b/Microsoft.Windows.Shell/standard.net/README.md new file mode 100644 index 0000000..62a5882 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/README.md @@ -0,0 +1,4 @@ +standard.net +============ + +Common utility functions I tend to carry from one C# project to the next. \ No newline at end of file diff --git a/Microsoft.Windows.Shell/standard.net/SmallString.cs b/Microsoft.Windows.Shell/standard.net/SmallString.cs new file mode 100644 index 0000000..9b58113 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/SmallString.cs @@ -0,0 +1,257 @@ + +namespace Standard +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + + [System.Diagnostics.DebuggerDisplay("SmallString: { GetString() }")] + internal struct SmallString : IEquatable, IComparable + { + [Flags] + private enum _SmallFlags : byte + { + None = 0, + IsInt64 = 1, + HasHashCode = 2, + Reserved = 4, + } + + private static readonly System.Text.UTF8Encoding s_Encoder = new System.Text.UTF8Encoding(false /* do not emit BOM */, true /* throw on error */); + private readonly byte[] _encodedBytes; + private _SmallFlags _flags; + private int _cachedHashCode; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public SmallString(string value, bool precacheHashCode = false) + { + _flags = _SmallFlags.None; + _cachedHashCode = 0; + + if (!string.IsNullOrEmpty(value)) + { + if (precacheHashCode) + { + _flags |= _SmallFlags.HasHashCode; + _cachedHashCode = value.GetHashCode(); + } + + long numValue; + if (long.TryParse(value, System.Globalization.NumberStyles.None, null, out numValue)) + { + _flags |= _SmallFlags.IsInt64; + _encodedBytes = BitConverter.GetBytes(numValue); + + // It's possible that this doesn't round trip with full fidelity. + // If this assert ever gets hit, consider adding an overload that opts + // out of this optimization. + // (Note that the parameters are not evaluated on retail builds) + Assert.AreEqual(this.GetString(), value); + + return; + } + + _encodedBytes = s_Encoder.GetBytes(value); + Assert.IsNotNull(_encodedBytes); + } + else + { + _encodedBytes = null; + } + } + + private bool _IsInt64 + { + get { return (_flags & _SmallFlags.IsInt64) == _SmallFlags.IsInt64; } + } + + private bool _HasCachedHashCode + { + get { return (_flags & _SmallFlags.HasHashCode) == _SmallFlags.HasHashCode; } + } + + #region Object Overrides + + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "GetString")] + public override string ToString() + { + Assert.Fail(); + throw new NotSupportedException("This exception exists to prevent accidental performance penalties. Call GetString() instead."); + } + + public override int GetHashCode() + { + if (_encodedBytes == null) + { + return 0; + } + + if (!_HasCachedHashCode) + { + // Intentionally hashes similarly to the expanded strings. + _cachedHashCode = GetString().GetHashCode(); + _flags |= _SmallFlags.HasHashCode; + } + + return _cachedHashCode; + } + + public override bool Equals(object obj) + { + try + { + return Equals((SmallString)obj); + } + catch (InvalidCastException) + { + return false; + } + } + + #endregion + + #region IEquatable Members + + public bool Equals(SmallString other) + { + if (_encodedBytes == null) + { + return other._encodedBytes == null; + } + + if (other._encodedBytes == null) + { + return false; + } + + if (_encodedBytes.Length != other._encodedBytes.Length) + { + return false; + } + + // If only one is a number, then they're not equal. + if (((_flags ^ other._flags) & _SmallFlags.IsInt64) == _SmallFlags.IsInt64) + { + return false; + } + + if (_HasCachedHashCode && other._HasCachedHashCode) + { + if (_cachedHashCode != other._cachedHashCode) + { + return false; + } + } + + if (_IsInt64) + { + return BitConverter.ToInt64(_encodedBytes, 0) == BitConverter.ToInt64(other._encodedBytes, 0); + } + + // Note that this is doing a literal binary comparison of the two strings. + // It's possible for two real strings to compare equally even though they + // can be encoded in different ways with UTF8. + return Utility.MemCmp(_encodedBytes, other._encodedBytes, _encodedBytes.Length); + } + + #endregion + + public string GetString() + { + if (_encodedBytes == null) + { + return ""; + } + + if (_IsInt64) + { + return BitConverter.ToInt64(_encodedBytes, 0).ToString(CultureInfo.InvariantCulture); + } + + return s_Encoder.GetString(_encodedBytes); + } + + public static bool operator==(SmallString left, SmallString right) + { + return left.Equals(right); + } + + public static bool operator!=(SmallString left, SmallString right) + { + return !left.Equals(right); + } + + #region IComparable Members + + public int CompareTo(SmallString other) + { + // If either of the strings contains multibyte characters + // then we can't do a strictly bitwise comparison. + // We can look for a signaled high-bit in the byte to detect this. + // Opportunistically, we're going to assume that the strings are + // ASCII compatible until we find out they aren't. + + if (_encodedBytes == null) + { + if (other._encodedBytes == null) + { + return 0; + } + Assert.AreNotEqual(0, other._encodedBytes.Length); + return -1; + } + else if (other._encodedBytes == null) + { + Assert.AreNotEqual(0, _encodedBytes.Length); + return 1; + } + + bool? isThisStringShorter = null; + int cb = _encodedBytes.Length; + int cbDiffernce = other._encodedBytes.Length - cb; + + if (cbDiffernce < 0) + { + isThisStringShorter = false; + cb = other._encodedBytes.Length; + } + else if (cbDiffernce > 0) + { + isThisStringShorter = true; + } + + for (int i = 0; i < cb; ++i) + { + bool isEitherHighBitSet = ((_encodedBytes[i] | other._encodedBytes[i]) & 0x80) != 0; + // If the byte array contains multibyte characters + // we need to do a real string comparison. + if (isEitherHighBitSet) + { + string left = this.GetString(); + string right = other.GetString(); + + return string.Compare(left, right, StringComparison.Ordinal); + } + + if (_encodedBytes[i] != other._encodedBytes[i]) + { + return _encodedBytes[i] - other._encodedBytes[i]; + } + } + + if (isThisStringShorter == null) + { + return 0; + } + + if (isThisStringShorter == false) + { + return -1; + } + + return 1; + } + + #endregion + } +} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/standard.net/SmallUri.cs b/Microsoft.Windows.Shell/standard.net/SmallUri.cs new file mode 100644 index 0000000..95db8f6 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/SmallUri.cs @@ -0,0 +1,155 @@ + +namespace Standard +{ + using System; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.Text; + + [DebuggerDisplay("SmallUri: { GetUri() }")] + internal struct SmallUri : IEquatable + { + private static readonly UTF8Encoding s_Encoder = new UTF8Encoding(false /* do not emit BOM */, true /* throw on error */); + private readonly byte[] _utf8String; + private readonly bool _isHttp; + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public SmallUri(Uri value) + { + _isHttp = false; + _utf8String = null; + + if (value == null) + { + return; + } + + if (!value.IsAbsoluteUri) + { + throw new ArgumentException("The parameter is not a valid absolute uri", "value"); + } + + string strValue = value.OriginalString; + if (strValue.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) + { + _isHttp = true; + strValue = strValue.Substring(7); + } + + _utf8String = s_Encoder.GetBytes(strValue); + Assert.IsNotNull(_utf8String); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public SmallUri(string value) + { + _isHttp = false; + _utf8String = null; + + if (string.IsNullOrEmpty(value)) + { + return; + } + + if (!Uri.IsWellFormedUriString(value, UriKind.Absolute)) + { + throw new ArgumentException("The parameter is not a valid uri", "value"); + } + + if (value.StartsWith("http://", StringComparison.OrdinalIgnoreCase)) + { + _isHttp = true; + value = value.Substring(7); + } + + _utf8String = s_Encoder.GetBytes(value); + Assert.IsNotNull(_utf8String); + } + + #region Object Overrides + + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "GetString")] + public override string ToString() + { + Assert.Fail(); + throw new NotSupportedException("This exception exists to prevent accidental performance penalties. Call GetString() instead."); + } + + public override int GetHashCode() + { + // Intentionally hashes similarly to the expanded strings. + return GetString().GetHashCode(); + } + + public override bool Equals(object obj) + { + try + { + return Equals((SmallUri)obj); + } + catch (InvalidCastException) + { + return false; + } + } + + #endregion + + #region IEquatable Members + + public bool Equals(SmallUri other) + { + if (_utf8String == null) + { + return other._utf8String == null; + } + + if (other._utf8String == null) + { + return false; + } + + if (_isHttp != other._isHttp) + { + return false; + } + + if (_utf8String.Length != other._utf8String.Length) + { + return false; + } + + return Utility.MemCmp(_utf8String, other._utf8String, _utf8String.Length); + } + + #endregion + + public string GetString() + { + if (_utf8String == null) + { + return ""; + } + return GetUri().ToString(); + } + + public Uri GetUri() + { + if (_utf8String == null) + { + return null; + } + return new Uri((_isHttp ? "http://" : "") + s_Encoder.GetString(_utf8String), UriKind.Absolute); + } + + public static bool operator ==(SmallUri left, SmallUri right) + { + return left.Equals(right); + } + + public static bool operator !=(SmallUri left, SmallUri right) + { + return !left.Equals(right); + } + } +} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/standard.net/Standard.Native.csproj b/Microsoft.Windows.Shell/standard.net/Standard.Native.csproj new file mode 100644 index 0000000..b592bd6 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Standard.Native.csproj @@ -0,0 +1,66 @@ + + + + + Debug + AnyCPU + {48634441-DEDA-4D0D-8D35-14E61A29A363} + Library + Properties + Standard.Native + Standard.Native + v4.0 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Microsoft.Windows.Shell/standard.net/Standard.Wpf.csproj b/Microsoft.Windows.Shell/standard.net/Standard.Wpf.csproj new file mode 100644 index 0000000..d592bcc --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Standard.Wpf.csproj @@ -0,0 +1,82 @@ + + + + + Debug + AnyCPU + {89835A37-CA82-4036-A9E3-FC3456290F65} + Library + Properties + Standard.Wpf + Standard.Wpf + v4.0 + 512 + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + true + AllRules.ruleset + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Microsoft.Windows.Shell/standard.net/Standard.csproj b/Microsoft.Windows.Shell/standard.net/Standard.csproj new file mode 100644 index 0000000..c45ae93 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Standard.csproj @@ -0,0 +1,81 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {A1326555-AD64-4A93-A95C-B68ABD5672D4} + Library + Properties + Standard + Standard + v4.0 + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + true + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + true + GlobalSuppressions.cs + prompt + true + AllRules.ruleset + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Microsoft.Windows.Shell/standard.net/Standard.sln b/Microsoft.Windows.Shell/standard.net/Standard.sln new file mode 100644 index 0000000..c6d54c8 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Standard.sln @@ -0,0 +1,42 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Standard.Wpf", "Standard.Wpf.csproj", "{89835A37-CA82-4036-A9E3-FC3456290F65}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Standard", "Standard.csproj", "{A1326555-AD64-4A93-A95C-B68ABD5672D4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Standard.Native", "Standard.Native.csproj", "{48634441-DEDA-4D0D-8D35-14E61A29A363}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {89835A37-CA82-4036-A9E3-FC3456290F65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {89835A37-CA82-4036-A9E3-FC3456290F65}.Debug|Any CPU.Build.0 = Debug|Any CPU + {89835A37-CA82-4036-A9E3-FC3456290F65}.Debug|x86.ActiveCfg = Debug|Any CPU + {89835A37-CA82-4036-A9E3-FC3456290F65}.Release|Any CPU.ActiveCfg = Release|Any CPU + {89835A37-CA82-4036-A9E3-FC3456290F65}.Release|Any CPU.Build.0 = Release|Any CPU + {89835A37-CA82-4036-A9E3-FC3456290F65}.Release|x86.ActiveCfg = Release|Any CPU + {A1326555-AD64-4A93-A95C-B68ABD5672D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A1326555-AD64-4A93-A95C-B68ABD5672D4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A1326555-AD64-4A93-A95C-B68ABD5672D4}.Debug|x86.ActiveCfg = Debug|x86 + {A1326555-AD64-4A93-A95C-B68ABD5672D4}.Debug|x86.Build.0 = Debug|x86 + {A1326555-AD64-4A93-A95C-B68ABD5672D4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A1326555-AD64-4A93-A95C-B68ABD5672D4}.Release|Any CPU.Build.0 = Release|Any CPU + {A1326555-AD64-4A93-A95C-B68ABD5672D4}.Release|x86.ActiveCfg = Release|x86 + {A1326555-AD64-4A93-A95C-B68ABD5672D4}.Release|x86.Build.0 = Release|x86 + {48634441-DEDA-4D0D-8D35-14E61A29A363}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {48634441-DEDA-4D0D-8D35-14E61A29A363}.Debug|Any CPU.Build.0 = Debug|Any CPU + {48634441-DEDA-4D0D-8D35-14E61A29A363}.Debug|x86.ActiveCfg = Debug|Any CPU + {48634441-DEDA-4D0D-8D35-14E61A29A363}.Release|Any CPU.ActiveCfg = Release|Any CPU + {48634441-DEDA-4D0D-8D35-14E61A29A363}.Release|Any CPU.Build.0 = Release|Any CPU + {48634441-DEDA-4D0D-8D35-14E61A29A363}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Microsoft.Windows.Shell/standard.net/Utilities.cs b/Microsoft.Windows.Shell/standard.net/Utilities.cs new file mode 100644 index 0000000..27371ae --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Utilities.cs @@ -0,0 +1,827 @@ +// This file contains general utilities to aid in development. +// Classes here generally shouldn't be exposed publicly since +// they're not particular to any library functionality. +// Because the classes here are internal, it's likely this file +// might be included in multiple assemblies. +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Reflection; + using System.Runtime.InteropServices; + using System.Security.Cryptography; + using System.Text; + + internal enum SafeCopyFileOptions + { + PreserveOriginal, + Overwrite, + FindBetterName, + } + + internal static partial class Utility + { + private static readonly Random _randomNumberGenerator = new Random(); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static bool _MemCmp(IntPtr left, IntPtr right, long cb) + { + int offset = 0; + + for (; offset < (cb - sizeof(Int64)); offset += sizeof(Int64)) + { + Int64 left64 = Marshal.ReadInt64(left, offset); + Int64 right64 = Marshal.ReadInt64(right, offset); + + if (left64 != right64) + { + return false; + } + } + + for (; offset < cb; offset += sizeof(byte)) + { + byte left8 = Marshal.ReadByte(left, offset); + byte right8 = Marshal.ReadByte(right, offset); + + if (left8 != right8) + { + return false; + } + } + + return true; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Exception FailableFunction(Func function, out T result) + { + return FailableFunction(5, function, out result); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static T FailableFunction(Func function) + { + T result; + Exception e = FailableFunction(function, out result); + if (e != null) + { + throw e; + } + return result; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static T FailableFunction(int maxRetries, Func function) + { + T result; + Exception e = FailableFunction(maxRetries, function, out result); + if (e != null) + { + throw e; + } + return result; + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Exception FailableFunction(int maxRetries, Func function, out T result) + { + Assert.IsNotNull(function); + Assert.BoundedInteger(1, maxRetries, 100); + int i = 0; + while (true) + { + try + { + result = function(); + return null; + } + catch (Exception e) + { + if (i == maxRetries) + { + result = default(T); + return e; + } + } + ++i; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string GetHashString(string value) + { + using (MD5 md5 = MD5.Create()) + { + byte[] signatureHash = md5.ComputeHash(Encoding.UTF8.GetBytes(value)); + string signature = signatureHash.Aggregate( + new StringBuilder(), + (sb, b) => sb.Append(b.ToString("x2", CultureInfo.InvariantCulture))).ToString(); + return signature; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int GET_X_LPARAM(IntPtr lParam) + { + return LOWORD(lParam.ToInt32()); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int GET_Y_LPARAM(IntPtr lParam) + { + return HIWORD(lParam.ToInt32()); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int HIWORD(int i) + { + return (short)(i >> 16); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int LOWORD(int i) + { + return (short)(i & 0xFFFF); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static bool AreStreamsEqual(Stream left, Stream right) + { + if (null == left) + { + return right == null; + } + if (null == right) + { + return false; + } + + if (!left.CanRead || !right.CanRead) + { + throw new NotSupportedException("The streams can't be read for comparison"); + } + + if (left.Length != right.Length) + { + return false; + } + + var length = (int)left.Length; + + // seek to beginning + left.Position = 0; + right.Position = 0; + + // total bytes read + int totalReadLeft = 0; + int totalReadRight = 0; + + // bytes read on this iteration + int cbReadLeft = 0; + int cbReadRight = 0; + + // where to store the read data + var leftBuffer = new byte[512]; + var rightBuffer = new byte[512]; + + // pin the left buffer + GCHandle handleLeft = GCHandle.Alloc(leftBuffer, GCHandleType.Pinned); + IntPtr ptrLeft = handleLeft.AddrOfPinnedObject(); + + // pin the right buffer + GCHandle handleRight = GCHandle.Alloc(rightBuffer, GCHandleType.Pinned); + IntPtr ptrRight = handleRight.AddrOfPinnedObject(); + + try + { + while (totalReadLeft < length) + { + Assert.AreEqual(totalReadLeft, totalReadRight); + + cbReadLeft = left.Read(leftBuffer, 0, leftBuffer.Length); + cbReadRight = right.Read(rightBuffer, 0, rightBuffer.Length); + + // verify the contents are an exact match + if (cbReadLeft != cbReadRight) + { + return false; + } + + if (!_MemCmp(ptrLeft, ptrRight, cbReadLeft)) + { + return false; + } + + totalReadLeft += cbReadLeft; + totalReadRight += cbReadRight; + } + + Assert.AreEqual(cbReadLeft, cbReadRight); + Assert.AreEqual(totalReadLeft, totalReadRight); + Assert.AreEqual(length, totalReadLeft); + + return true; + } + finally + { + handleLeft.Free(); + handleRight.Free(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool GuidTryParse(string guidString, out Guid guid) + { + Verify.IsNeitherNullNorEmpty(guidString, "guidString"); + + try + { + guid = new Guid(guidString); + return true; + } + catch (FormatException) + { + } + catch (OverflowException) + { + } + // Doesn't seem to be a valid guid. + guid = default(Guid); + return false; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFlagSet(int value, int mask) + { + return 0 != (value & mask); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFlagSet(uint value, uint mask) + { + return 0 != (value & mask); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFlagSet(long value, long mask) + { + return 0 != (value & mask); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsFlagSet(ulong value, ulong mask) + { + return 0 != (value & mask); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsInterfaceImplemented(Type objectType, Type interfaceType) + { + Assert.IsNotNull(objectType); + Assert.IsNotNull(interfaceType); + Assert.IsTrue(interfaceType.IsInterface); + + return objectType.GetInterfaces().Any(type => type == interfaceType); + } + + /// + /// Wrapper around File.Copy to provide feedback as to whether the file wasn't copied because it didn't exist. + /// + /// + /// + /// + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string SafeCopyFile(string sourceFileName, string destFileName, SafeCopyFileOptions options) + { + switch (options) + { + case SafeCopyFileOptions.PreserveOriginal: + if (!File.Exists(destFileName)) + { + File.Copy(sourceFileName, destFileName); + return destFileName; + } + return null; + case SafeCopyFileOptions.Overwrite: + File.Copy(sourceFileName, destFileName, true); + return destFileName; + case SafeCopyFileOptions.FindBetterName: + string directoryPart = Path.GetDirectoryName(destFileName); + string fileNamePart = Path.GetFileNameWithoutExtension(destFileName); + string extensionPart = Path.GetExtension(destFileName); + foreach (string path in GenerateFileNames(directoryPart, fileNamePart, extensionPart)) + { + if (!File.Exists(path)) + { + File.Copy(sourceFileName, path); + return path; + } + } + return null; + } + throw new ArgumentException("Invalid enumeration value", "options"); + } + + /// + /// Simple guard against the exceptions that File.Delete throws on null and empty strings. + /// + /// The path to delete. Unlike File.Delete, this can be null or empty. + /// + /// Note that File.Delete, and by extension SafeDeleteFile, does not throw an exception + /// if the file does not exist. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDeleteFile(string path) + { + if (!string.IsNullOrEmpty(path)) + { + File.Delete(path); + } + } + + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDispose(ref T disposable) where T : IDisposable + { + // Dispose can safely be called on an object multiple times. + IDisposable t = disposable; + disposable = default(T); + if (null != t) + { + t.Dispose(); + } + } + + /// + /// Utility to help classes catenate their properties for implementing ToString(). + /// + /// The StringBuilder to catenate the results into. + /// The name of the property to be catenated. + /// The value of the property to be catenated. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void GeneratePropertyString(StringBuilder source, string propertyName, string value) + { + Assert.IsNotNull(source); + Assert.IsFalse(string.IsNullOrEmpty(propertyName)); + + if (0 != source.Length) + { + source.Append(' '); + } + + source.Append(propertyName); + source.Append(": "); + if (string.IsNullOrEmpty(value)) + { + source.Append(""); + } + else + { + source.Append('\"'); + source.Append(value); + source.Append('\"'); + } + } + + /// + /// Generates ToString functionality for a struct. This is an expensive way to do it, + /// it exists for the sake of debugging while classes are in flux. + /// Eventually this should just be removed and the classes should + /// do this without reflection. + /// + /// + /// + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [Obsolete] + public static string GenerateToString(T @object) where T : struct + { + var sbRet = new StringBuilder(); + foreach (PropertyInfo property in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)) + { + if (0 != sbRet.Length) + { + sbRet.Append(", "); + } + Assert.AreEqual(0, property.GetIndexParameters().Length); + object value = property.GetValue(@object, null); + string format = null == value ? "{0}: " : "{0}: \"{1}\""; + sbRet.AppendFormat(format, property.Name, value); + } + return sbRet.ToString(); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void CopyStream(Stream destination, Stream source) + { + Assert.IsNotNull(source); + Assert.IsNotNull(destination); + + destination.Position = 0; + + // If we're copying from, say, a web stream, don't fail because of this. + if (source.CanSeek) + { + source.Position = 0; + + // Consider that this could throw because + // the source stream doesn't know it's size... + destination.SetLength(source.Length); + } + + var buffer = new byte[4096]; + int cbRead; + + do + { + cbRead = source.Read(buffer, 0, buffer.Length); + if (0 != cbRead) + { + destination.Write(buffer, 0, cbRead); + } + } + while (buffer.Length == cbRead); + + // Reset the Seek pointer before returning. + destination.Position = 0; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string HashStreamMD5(Stream stm) + { + stm.Position = 0; + var hashBuilder = new StringBuilder(); + using (MD5 md5 = MD5.Create()) + { + foreach (byte b in md5.ComputeHash(stm)) + { + hashBuilder.Append(b.ToString("x2", CultureInfo.InvariantCulture)); + } + } + + return hashBuilder.ToString(); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void EnsureDirectory(string path) + { + if (!path.EndsWith(@"\", StringComparison.Ordinal)) + { + path += @"\"; + } + + path = Path.GetDirectoryName(path); + + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool MemCmp(byte[] left, byte[] right, int cb) + { + Assert.IsNotNull(left); + Assert.IsNotNull(right); + + Assert.IsTrue(cb <= Math.Min(left.Length, right.Length)); + + // pin this buffer + GCHandle handleLeft = GCHandle.Alloc(left, GCHandleType.Pinned); + IntPtr ptrLeft = handleLeft.AddrOfPinnedObject(); + + // pin the other buffer + GCHandle handleRight = GCHandle.Alloc(right, GCHandleType.Pinned); + IntPtr ptrRight = handleRight.AddrOfPinnedObject(); + + bool fRet = _MemCmp(ptrLeft, ptrRight, cb); + + handleLeft.Free(); + handleRight.Free(); + + return fRet; + } + + private class _UrlDecoder + { + private readonly Encoding _encoding; + private readonly char[] _charBuffer; + private readonly byte[] _byteBuffer; + private int _byteCount; + private int _charCount; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public _UrlDecoder(int size, Encoding encoding) + { + _encoding = encoding; + _charBuffer = new char[size]; + _byteBuffer = new byte[size]; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void AddByte(byte b) + { + _byteBuffer[_byteCount++] = b; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void AddChar(char ch) + { + _FlushBytes(); + _charBuffer[_charCount++] = ch; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private void _FlushBytes() + { + if (_byteCount > 0) + { + _charCount += _encoding.GetChars(_byteBuffer, 0, _byteCount, _charBuffer, _charCount); + _byteCount = 0; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public string GetString() + { + _FlushBytes(); + if (_charCount > 0) + { + return new string(_charBuffer, 0, _charCount); + } + return ""; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string UrlDecode(string url) + { + if (url == null) + { + return null; + } + + var decoder = new _UrlDecoder(url.Length, Encoding.UTF8); + int length = url.Length; + for (int i = 0; i < length; ++i) + { + char ch = url[i]; + + if (ch == '+') + { + decoder.AddByte((byte)' '); + continue; + } + + if (ch == '%' && i < length - 2) + { + // decode %uXXXX into a Unicode character. + if (url[i + 1] == 'u' && i < length - 5) + { + int a = _HexToInt(url[i + 2]); + int b = _HexToInt(url[i + 3]); + int c = _HexToInt(url[i + 4]); + int d = _HexToInt(url[i + 5]); + if (a >= 0 && b >= 0 && c >= 0 && d >= 0) + { + decoder.AddChar((char)((a << 12) | (b << 8) | (c << 4) | d)); + i += 5; + + continue; + } + } + else + { + // decode %XX into a Unicode character. + int a = _HexToInt(url[i + 1]); + int b = _HexToInt(url[i + 2]); + + if (a >= 0 && b >= 0) + { + decoder.AddByte((byte)((a << 4) | b)); + i += 2; + + continue; + } + } + } + + // Add any 7bit character as a byte. + if ((ch & 0xFF80) == 0) + { + decoder.AddByte((byte)ch); + } + else + { + decoder.AddChar(ch); + } + } + + return decoder.GetString(); + } + + /// + /// Encodes a URL string. Duplicated functionality from System.Web.HttpUtility.UrlEncode. + /// + /// + /// + /// + /// Duplicated from System.Web.HttpUtility because System.Web isn't part of the client profile. + /// URL Encoding replaces ' ' with '+' and unsafe ASCII characters with '%XX'. + /// Safe characters are defined in RFC2396 (http://www.ietf.org/rfc/rfc2396.txt). + /// They are the 7-bit ASCII alphanumerics and the mark characters "-_.!~*'()". + /// This implementation does not treat '~' as a safe character to be consistent with the System.Web version. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string UrlEncode(string url) + { + if (url == null) + { + return null; + } + + byte[] bytes = Encoding.UTF8.GetBytes(url); + + bool needsEncoding = false; + int unsafeCharCount = 0; + foreach (byte b in bytes) + { + if (b == ' ') + { + needsEncoding = true; + } + else if (!_UrlEncodeIsSafe(b)) + { + ++unsafeCharCount; + needsEncoding = true; + } + } + + if (needsEncoding) + { + var buffer = new byte[bytes.Length + (unsafeCharCount * 2)]; + int writeIndex = 0; + foreach (byte b in bytes) + { + if (_UrlEncodeIsSafe(b)) + { + buffer[writeIndex++] = b; + } + else if (b == ' ') + { + buffer[writeIndex++] = (byte)'+'; + } + else + { + buffer[writeIndex++] = (byte)'%'; + buffer[writeIndex++] = _IntToHex((b >> 4) & 0xF); + buffer[writeIndex++] = _IntToHex(b & 0xF); + } + } + bytes = buffer; + Assert.AreEqual(buffer.Length, writeIndex); + } + + return Encoding.ASCII.GetString(bytes); + } + + // HttpUtility's UrlEncode is slightly different from the RFC. + // RFC2396 describes unreserved characters as alphanumeric or + // the list "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")" + // The System.Web version unnecessarily escapes '~', which should be okay... + // Keeping that same pattern here just to be consistent. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static bool _UrlEncodeIsSafe(byte b) + { + if (_IsAsciiAlphaNumeric(b)) + { + return true; + } + + switch ((char)b) + { + case '-': + case '_': + case '.': + case '!': + //case '~': + case '*': + case '\'': + case '(': + case ')': + return true; + } + + return false; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static bool _IsAsciiAlphaNumeric(byte b) + { + return (b >= 'a' && b <= 'z') + || (b >= 'A' && b <= 'Z') + || (b >= '0' && b <= '9'); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static byte _IntToHex(int n) + { + Assert.BoundedInteger(0, n, 16); + if (n <= 9) + { + return (byte)(n + '0'); + } + return (byte)(n - 10 + 'A'); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static int _HexToInt(char h) + { + if (h >= '0' && h <= '9') + { + return h - '0'; + } + + if (h >= 'a' && h <= 'f') + { + return h - 'a' + 10; + } + + if (h >= 'A' && h <= 'F') + { + return h - 'A' + 10; + } + + Assert.Fail("Invalid hex character " + h); + return -1; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string MakeValidFileName(string invalidPath) + { + return invalidPath + .Replace('\\', '_') + .Replace('/', '_') + .Replace(':', '_') + .Replace('*', '_') + .Replace('?', '_') + .Replace('\"', '_') + .Replace('<', '_') + .Replace('>', '_') + .Replace('|', '_'); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IEnumerable GenerateFileNames(string directory, string primaryFileName, string extension) + { + Verify.IsNeitherNullNorEmpty(directory, "directory"); + Verify.IsNeitherNullNorEmpty(primaryFileName, "primaryFileName"); + + primaryFileName = MakeValidFileName(primaryFileName); + + for (int i = 0; i <= 50; ++i) + { + if (0 == i) + { + yield return Path.Combine(directory, primaryFileName) + extension; + } + else if (40 >= i) + { + yield return Path.Combine(directory, primaryFileName) + " (" + i.ToString((IFormatProvider)null) + ")" + extension; + } + else + { + // At this point we're hitting pathological cases. This should stir things up enough that it works. + // If this fails because of naming conflicts after an extra 10 tries, then I don't care. + yield return Path.Combine(directory, primaryFileName) + " (" + _randomNumberGenerator.Next(41, 9999) + ")" + extension; + } + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool TryFileMove(string sourceFileName, string destFileName) + { + if (!File.Exists(destFileName)) + { + try + { + File.Move(sourceFileName, destFileName); + } + catch (IOException) + { + return false; + } + return true; + } + return false; + } + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Verify.cs b/Microsoft.Windows.Shell/standard.net/Verify.cs new file mode 100644 index 0000000..8b81f25 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Verify.cs @@ -0,0 +1,341 @@ +// This file contains general utilities to aid in development. +// Classes here generally shouldn't be exposed publicly since +// they're not particular to any library functionality. +// Because the classes here are internal, it's likely this file +// might be included in multiple assemblies. +namespace Standard +{ + using System; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.IO; + using System.Threading; + + /// + /// A static class for retail validated assertions. + /// Instead of breaking into the debugger an exception is thrown. + /// + internal static class Verify + { + /// + /// Ensure that the current thread's apartment state is what's expected. + /// + /// + /// The required apartment state for the current thread. + /// + /// + /// The message string for the exception to be thrown if the state is invalid. + /// + /// + /// Thrown if the calling thread's apartment state is not the same as the requiredState. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsApartmentState(ApartmentState requiredState, string message) + { + if (Thread.CurrentThread.GetApartmentState() != requiredState) + { + Assert.Fail(); + throw new InvalidOperationException(message); + } + } + + /// + /// Ensure that an argument is neither null nor empty. + /// + /// The string to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Performance", "CA1820:TestForEmptyStringsUsingStringLength")] + [DebuggerStepThrough] + public static void IsNeitherNullNorEmpty(string value, string name) + { + // catch caller errors, mixing up the parameters. Name should never be empty. + Assert.IsNeitherNullNorEmpty(name); + + // Notice that ArgumentNullException and ArgumentException take the parameters in opposite order :P + const string errorMessage = "The parameter can not be either null or empty."; + if (null == value) + { + Assert.Fail(); + throw new ArgumentNullException(name, errorMessage); + } + if ("" == value) + { + Assert.Fail(); + throw new ArgumentException(errorMessage, name); + } + } + + /// + /// Ensure that an argument is neither null nor does it consist only of whitespace. + /// + /// The string to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Performance", "CA1820:TestForEmptyStringsUsingStringLength")] + [DebuggerStepThrough] + public static void IsNeitherNullNorWhitespace(string value, string name) + { + // catch caller errors, mixing up the parameters. Name should never be empty. + Assert.IsNeitherNullNorEmpty(name); + + // Notice that ArgumentNullException and ArgumentException take the parameters in opposite order :P + const string errorMessage = "The parameter can not be either null or empty or consist only of white space characters."; + if (null == value) + { + Assert.Fail(); + throw new ArgumentNullException(name, errorMessage); + } + if ("" == value.Trim()) + { + Assert.Fail(); + throw new ArgumentException(errorMessage, name); + } + } + + /// Verifies that an argument is not null. + /// Type of the object to validate. Must be a class. + /// The object to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsNotDefault(T obj, string name) where T : struct + { + if (default(T).Equals(obj)) + { + Assert.Fail(); + throw new ArgumentException("The parameter must not be the default value.", name); + } + } + + /// Verifies that an argument is not null. + /// Type of the object to validate. Must be a class. + /// The object to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsNotNull(T obj, string name) where T : class + { + if (null == obj) + { + Assert.Fail(); + throw new ArgumentNullException(name); + } + } + + /// Verifies that an argument is not null. + /// Type of the object to validate. Must be a class. + /// The object to validate. + /// The name of the parameter that will be presented if an exception is thrown. + /// The message to display with the exception + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsNotNull(T obj, string name, string message) where T : class + { + if (null == obj) + { + Assert.Fail(); + throw new ArgumentNullException(name, message); + } + } + + /// Verifies that an argument is null. + /// Type of the object to validate. Must be a class. + /// The object to validate. + /// The name of the parameter that will be presented if an exception is thrown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsNull(T obj, string name) where T : class + { + if (null != obj) + { + Assert.Fail(); + throw new ArgumentException("The parameter must be null.", name); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void PropertyIsNotNull(T obj, string name) where T : class + { + if (null == obj) + { + Assert.Fail(); + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The property {0} cannot be null at this time.", name)); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void PropertyIsNull(T obj, string name) where T : class + { + if (null != obj) + { + Assert.Fail(); + throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "The property {0} must be null at this time.", name)); + } + } + + /// + /// Verifies the specified statement is true. Throws an ArgumentException if it's not. + /// + /// The statement to be verified as true. + /// Name of the parameter to include in the ArgumentException. + /// The message to include in the ArgumentException. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsTrue(bool statement, string name, string message = null) + { + if (!statement) + { + Assert.Fail(); + throw new ArgumentException(message ?? "", name); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void IsFalse(bool statement, string name, string message = null) + { + if (statement) + { + Assert.Fail(); + throw new ArgumentException(message ?? "", name); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void AreEqual(T expected, T actual, string parameterName, string message) + { + if (null == expected) + { + // Two nulls are considered equal, regardless of type semantics. + if (null != actual && !actual.Equals(expected)) + { + Assert.Fail(); + throw new ArgumentException(message, parameterName); + } + } + else if (!expected.Equals(actual)) + { + Assert.Fail(); + throw new ArgumentException(message, parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void AreNotEqual(T notExpected, T actual, string parameterName, string message) + { + if (null == notExpected) + { + // Two nulls are considered equal, regardless of type semantics. + if (null == actual || actual.Equals(notExpected)) + { + Assert.Fail(); + throw new ArgumentException(message, parameterName); + } + } + else if (notExpected.Equals(actual)) + { + Assert.Fail(); + throw new ArgumentException(message, parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void UriIsAbsolute(Uri uri, string parameterName) + { + Verify.IsNotNull(uri, parameterName); + if (!uri.IsAbsoluteUri) + { + Assert.Fail(); + throw new ArgumentException("The URI must be absolute.", parameterName); + } + } + + /// + /// Verifies that the specified value is within the expected range. The assertion fails if it isn't. + /// + /// The lower bound inclusive value. + /// The value to verify. + /// The upper bound exclusive value. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void BoundedInteger(int lowerBoundInclusive, int value, int upperBoundExclusive, string parameterName) + { + if (value < lowerBoundInclusive || value >= upperBoundExclusive) + { + Assert.Fail(); + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The integer value must be bounded with [{0}, {1})", lowerBoundInclusive, upperBoundExclusive), parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void BoundedDoubleInc(double lowerBoundInclusive, double value, double upperBoundInclusive, string message, string parameter) + { + if (value < lowerBoundInclusive || value > upperBoundInclusive) + { + Assert.Fail(); + throw new ArgumentException(message, parameter); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void TypeSupportsInterface(Type type, Type interfaceType, string parameterName) + { + Assert.IsNeitherNullNorEmpty(parameterName); + Verify.IsNotNull(type, "type"); + Verify.IsNotNull(interfaceType, "interfaceType"); + + if (type.GetInterface(interfaceType.Name) == null) + { + Assert.Fail(); + throw new ArgumentException("The type of this parameter does not support a required interface", parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + public static void FileExists(string filePath, string parameterName) + { + Verify.IsNeitherNullNorEmpty(filePath, parameterName); + if (!File.Exists(filePath)) + { + Assert.Fail(); + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "No file exists at \"{0}\"", filePath), parameterName); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DebuggerStepThrough] + internal static void ImplementsInterface(object parameter, Type interfaceType, string parameterName) + { + Assert.IsNotNull(parameter); + Assert.IsNotNull(interfaceType); + Assert.IsTrue(interfaceType.IsInterface); + + bool isImplemented = false; + foreach (var ifaceType in parameter.GetType().GetInterfaces()) + { + if (ifaceType == interfaceType) + { + isImplemented = true; + break; + } + } + + if (!isImplemented) + { + Assert.Fail(); + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The parameter must implement interface {0}.", interfaceType.ToString()), parameterName); + } + } + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Windows/ComGuids.cs b/Microsoft.Windows.Shell/standard.net/Windows/ComGuids.cs new file mode 100644 index 0000000..9644fda --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Windows/ComGuids.cs @@ -0,0 +1,159 @@ +namespace Standard +{ + using System.Diagnostics.CodeAnalysis; + + internal static partial class IID + { + /// IID_IApplicationAssociationRegistration + public const string ApplicationAssociationRegistration = "4e530b0a-e611-4c77-a3ac-9031d022281b"; + /// IID_IConnectionPoint + public const string ConnectionPoint = "B196B286-BAB4-101A-B69C-00AA00341D07"; + /// IID_IConnectionPointContainer + public const string ConnectionPointContainer = "B196B284-BAB4-101A-B69C-00AA00341D07"; + public const string DragSourceHelper = "DE5BF786-477A-11D2-839D-00C04FD918D0"; + public const string DragSourceHelper2 = "83E07D0D-0C5F-4163-BF1A-60B274051E40"; + public const string DropTargetHelper = "4657278B-411B-11D2-839A-00C04FD918D0"; + /// IID_IEnumConnectionPoints + public const string EnumConnectionPoints = "B196B285-BAB4-101A-B69C-00AA00341D07"; + /// IID_IEnumConnections + public const string EnumConnections = "B196B287-BAB4-101A-B69C-00AA00341D07"; + /// IID_IEnumIDList + public const string EnumIdList = "000214F2-0000-0000-C000-000000000046"; + /// IID_IEnumObjects + public const string EnumObjects = "2c1c7e2e-2d0e-4059-831e-1e6f82335c2e"; + /// IID_IFileDialog + public const string FileDialog = "42f85136-db7e-439c-85f1-e4075d135fc8"; + /// IID_IFileDialogEvents + public const string FileDialogEvents = "973510DB-7D7F-452B-8975-74A85828D354"; + /// IID_IFileOpenDialog + public const string FileOpenDialog = "d57c7288-d4ad-4768-be02-9d969532d960"; + /// IID_IFileSaveDialog + public const string FileSaveDialog = "84bccd23-5fde-4cdb-aea4-af64b83d78ab"; + /// IID_IHTMLDocument + public const string HtmlDocument = "626FC520-A41E-11CF-A731-00A0C9082637"; + /// IID_IHTMLDocument2 + public const string HtmlDocument2 = "332C4425-26CB-11D0-B483-00C04FD90119"; + /// IID_IModalWindow + public const string ModalWindow = "b4db1657-70d7-485e-8e3e-6fcb5a5c1802"; + /// IID_IObjectArray + public const string ObjectArray = "92CA9DCD-5622-4bba-A805-5E9F541BD8C9"; + /// IID_IObjectCollection + public const string ObjectCollection = "5632b1a4-e38a-400a-928a-d4cd63230295"; + /// IID_IPropertyNotifySink + public const string PropertyNotifySink = "9BFBBC02-EFF1-101A-84ED-00AA00341D07"; + /// IID_IPropertyStore + public const string PropertyStore = "886d8eeb-8cf2-4446-8d02-cdba1dbdcf99"; + /// IID_IServiceProvider + public const string ServiceProvider = "6d5140c1-7436-11ce-8034-00aa006009fa"; + /// IID_IShellFolder + public const string ShellFolder = "000214E6-0000-0000-C000-000000000046"; + /// IID_IShellLink + public const string ShellLink = "000214F9-0000-0000-C000-000000000046"; + /// IID_IShellItem + public const string ShellItem = "43826d1e-e718-42ee-bc55-a1e261c37bfe"; + /// IID_IShellItem2 + public const string ShellItem2 = "7e9fb0d3-919f-4307-ab2e-9b1860310c93"; + /// IID_IShellItemArray + public const string ShellItemArray = "B63EA76D-1F85-456F-A19C-48159EFA858B"; + /// IID_ITaskbarList + public const string TaskbarList = "56FDF342-FD6D-11d0-958A-006097C9A090"; + /// IID_ITaskbarList2 + public const string TaskbarList2 = "602D4995-B13A-429b-A66E-1935E44F4317"; + /// IID_IUnknown + public const string Unknown = "00000000-0000-0000-C000-000000000046"; + /// IID_IWebBrowser2 + public const string WebBrowser2 = "D30C1661-CDAF-11D0-8A3E-00C04FC9E26E"; + /// DIID_DWebBrowserEvents + public const string WebBrowserEvents = "EAB22AC2-30C1-11CF-A7EB-0000C05BAE0B"; + /// IID_DWebBrowserEvents2 + public const string WebBrowserEvents2 = "34A715A0-6587-11D0-924A-0020AFC7AC4D"; + /// IID_IWICBitmapDecoder + public const string WICBitmapDecoder = "9EDDE9E7-8DEE-47ea-99DF-E6FAF2ED44BF"; + /// IID_IWICBitmapFlipRotator + public const string WICBitmapFlipRotator = "5009834F-2D6A-41ce-9E1B-17C5AFF7A782"; + /// IID_IWICBitmapFrameDecode + public const string WICBitmapFrameDecode = "3B16811B-6A43-4ec9-A813-3D930C13B940"; + /// IID_IWICBitmap + public const string WICBitmap = "00000121-a8f2-4877-ba0a-fd2b6645fb94"; + /// IID_IWICBitmapSource + public const string WICBitmapSource = "00000120-a8f2-4877-ba0a-fd2b6645fb94"; + /// IID_IWICFormatConverter + public const string WICFormatConverter = "00000301-a8f2-4877-ba0a-fd2b6645fb94"; + /// IID_IWICImagingFactory + public const string WICImagingFactory = "ec5ec8a9-c395-4314-9c77-54d7a935ff70"; + /// IID_IWICStream + public const string WICStream = "135FF860-22B7-4ddf-B0F6-218F4F299A43"; + + #region Win7 IIDs + + /// IID_IApplicationDestinations + public const string ApplicationDestinations = "12337d35-94c6-48a0-bce7-6a9c69d4d600"; + /// IID_IApplicationDocumentLists + public const string ApplicationDocumentLists = "3c594f9f-9f30-47a1-979a-c9e83d3d0a06"; + /// IID_ICustomDestinationList + public const string CustomDestinationList = "6332debf-87b5-4670-90c0-5e57b408a49e"; + /// IID_IObjectWithAppUserModelID + public const string ObjectWithAppUserModelId = "36db0196-9665-46d1-9ba7-d3709eecf9ed"; + /// IID_IObjectWithProgID + public const string ObjectWithProgId = "71e806fb-8dee-46fc-bf8c-7748a8a1ae13"; + /// IID_ITaskbarList3 + public const string TaskbarList3 = "ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf"; + /// IID_ITaskbarList4 + public const string TaskbarList4 = "c43dc798-95d1-4bea-9030-bb99e2983a1a"; + + #endregion + } + + internal static partial class SID + { + /// SID_SWebBrowserApp + public const string SWebBrowserApp = "0002DF05-0000-0000-C000-000000000046"; + } + + internal static partial class CLSID + { + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static T CoCreateInstance(string clsid) + { + return (T)System.Activator.CreateInstance(System.Type.GetTypeFromCLSID(new System.Guid(clsid))); + } + + /// CLSID_ApplicationAssociationRegistration + /// IID_IApplicationAssociationRegistration + public const string ApplicationAssociationRegistration = "591209c7-767b-42b2-9fba-44ee4615f2c7"; + /// CLSID_DragDropHelper + public const string DragDropHelper = "4657278A-411B-11d2-839A-00C04FD918D0"; + /// CLSID_FileOpenDialog + /// IID_IFileOpenDialog + public const string FileOpenDialog = "DC1C5A9C-E88A-4dde-A5A1-60F82A20AEF7"; + /// CLSID_FileSaveDialog + /// IID_IFileSaveDialog + public const string FileSaveDialog = "C0B4E2F3-BA21-4773-8DBA-335EC946EB8B"; + /// CLSID_TaskbarList + /// IID_ITaskbarList + public const string TaskbarList = "56FDF344-FD6D-11d0-958A-006097C9A090"; + /// CLSID_EnumerableObjectCollection + /// IID_IEnumObjects. + public const string EnumerableObjectCollection = "2d3468c1-36a7-43b6-ac24-d3f02fd9607a"; + /// CLSID_ShellLink + /// IID_IShellLink + public const string ShellLink = "00021401-0000-0000-C000-000000000046"; + + /// CLSID_WICImagingFactory + public const string WICImagingFactory = "cacaf262-9370-4615-a13b-9f5539da4c0a"; + + #region Win7 CLSIDs + + /// CLSID_DestinationList + /// IID_ICustomDestinationList + public const string DestinationList = "77f10cf0-3db5-4966-b520-b7c54fd35ed6"; + /// CLSID_ApplicationDestinations + /// IID_IApplicationDestinations + public const string ApplicationDestinations = "86c14003-4d6b-4ef3-a7b4-0506663b2e68"; + /// CLSID_ApplicationDocumentLists + /// IID_IApplicationDocumentLists + public const string ApplicationDocumentLists = "86bec222-30f2-47e0-9f25-60d11cd75c28"; + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Windows/ErrorCodes.cs b/Microsoft.Windows.Shell/standard.net/Windows/ErrorCodes.cs new file mode 100644 index 0000000..90ca9c2 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Windows/ErrorCodes.cs @@ -0,0 +1,631 @@ +namespace Standard +{ + using System; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.Reflection; + using System.Runtime.InteropServices; + + /// + /// Wrapper for common Win32 status codes. + /// + [StructLayout(LayoutKind.Explicit)] + internal struct Win32Error + { + [FieldOffset(0)] + private readonly int _value; + + // NOTE: These public static field declarations are automatically + // picked up by (HRESULT's) ToString through reflection. + + /// The operation completed successfully. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_SUCCESS = new Win32Error(0); + /// Incorrect function. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INVALID_FUNCTION = new Win32Error(1); + /// The system cannot find the file specified. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_FILE_NOT_FOUND = new Win32Error(2); + /// The system cannot find the path specified. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_PATH_NOT_FOUND = new Win32Error(3); + /// The system cannot open the file. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_TOO_MANY_OPEN_FILES = new Win32Error(4); + /// Access is denied. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_ACCESS_DENIED = new Win32Error(5); + /// The handle is invalid. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INVALID_HANDLE = new Win32Error(6); + /// Not enough storage is available to complete this operation. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_OUTOFMEMORY = new Win32Error(14); + /// There are no more files. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_NO_MORE_FILES = new Win32Error(18); + /// The process cannot access the file because it is being used by another process. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_SHARING_VIOLATION = new Win32Error(32); + /// The parameter is incorrect. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INVALID_PARAMETER = new Win32Error(87); + /// The data area passed to a system call is too small. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INSUFFICIENT_BUFFER = new Win32Error(122); + /// Cannot nest calls to LoadModule. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_NESTING_NOT_ALLOWED = new Win32Error(215); + /// Illegal operation attempted on a registry key that has been marked for deletion. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_KEY_DELETED = new Win32Error(1018); + /// Element not found. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_NOT_FOUND = new Win32Error(1168); + /// There was no match for the specified key in the index. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_NO_MATCH = new Win32Error(1169); + /// An invalid device was specified. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_BAD_DEVICE = new Win32Error(1200); + /// The operation was canceled by the user. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_CANCELLED = new Win32Error(1223); + /// Cannot find window class. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_CANNOT_FIND_WND_CLASS = new Win32Error(1407); + /// The window class was already registered. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_CLASS_ALREADY_EXISTS = new Win32Error(1410); + /// The specified datatype is invalid. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Win32Error ERROR_INVALID_DATATYPE = new Win32Error(1804); + + /// + /// Create a new Win32 error. + /// + /// The integer value of the error. + public Win32Error(int i) + { + _value = i; + } + + /// Performs HRESULT_FROM_WIN32 conversion. + /// The Win32 error being converted to an HRESULT. + /// The equivilent HRESULT value. + public static explicit operator HRESULT(Win32Error error) + { + // #define __HRESULT_FROM_WIN32(x) + // ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000))) + if (error._value <= 0) + { + return new HRESULT((uint)error._value); + } + return HRESULT.Make(true, Facility.Win32, error._value & 0x0000FFFF); + } + + // Method version of the cast operation + /// Performs HRESULT_FROM_WIN32 conversion. + /// The Win32 error being converted to an HRESULT. + /// The equivilent HRESULT value. + public HRESULT ToHRESULT() + { + return (HRESULT)this; + } + + /// Performs the equivalent of Win32's GetLastError() + /// A Win32Error instance with the result of the native GetLastError + public static Win32Error GetLastError() + { + return new Win32Error(Marshal.GetLastWin32Error()); + } + + public override bool Equals(object obj) + { + try + { + return ((Win32Error)obj)._value == _value; + } + catch (InvalidCastException) + { + return false; + } + } + + public override int GetHashCode() + { + return _value.GetHashCode(); + } + + /// + /// Compare two Win32 error codes for equality. + /// + /// The first error code to compare. + /// The second error code to compare. + /// Whether the two error codes are the same. + public static bool operator ==(Win32Error errLeft, Win32Error errRight) + { + return errLeft._value == errRight._value; + } + + /// + /// Compare two Win32 error codes for inequality. + /// + /// The first error code to compare. + /// The second error code to compare. + /// Whether the two error codes are not the same. + public static bool operator !=(Win32Error errLeft, Win32Error errRight) + { + return !(errLeft == errRight); + } + } + + internal enum Facility + { + /// FACILITY_NULL + Null = 0, + /// FACILITY_RPC + Rpc = 1, + /// FACILITY_DISPATCH + Dispatch = 2, + /// FACILITY_STORAGE + Storage = 3, + /// FACILITY_ITF + Itf = 4, + /// FACILITY_WIN32 + Win32 = 7, + /// FACILITY_WINDOWS + Windows = 8, + /// FACILITY_CONTROL + Control = 10, + /// MSDN doced facility code for ESE errors. + Ese = 0xE5E, + /// FACILITY_WINCODEC (WIC) + WinCodec = 0x898, + } + + /// Wrapper for HRESULT status codes. + [StructLayout(LayoutKind.Explicit)] + internal struct HRESULT + { + [FieldOffset(0)] + private readonly uint _value; + + // NOTE: These public static field declarations are automatically + // picked up by ToString through reflection. + /// S_OK + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT S_OK = new HRESULT(0x00000000); + /// S_FALSE + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT S_FALSE = new HRESULT(0x00000001); + /// E_PENDING + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_PENDING = new HRESULT(0x8000000A); + /// E_NOTIMPL + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_NOTIMPL = new HRESULT(0x80004001); + /// E_NOINTERFACE + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_NOINTERFACE = new HRESULT(0x80004002); + /// E_POINTER + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_POINTER = new HRESULT(0x80004003); + /// E_ABORT + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_ABORT = new HRESULT(0x80004004); + /// E_FAIL + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_FAIL = new HRESULT(0x80004005); + /// E_UNEXPECTED + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_UNEXPECTED = new HRESULT(0x8000FFFF); + /// STG_E_INVALIDFUNCTION + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT STG_E_INVALIDFUNCTION = new HRESULT(0x80030001); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT OLE_E_ADVISENOTSUPPORTED = new HRESULT(0x80040003); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DV_E_FORMATETC = new HRESULT(0x80040064); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DV_E_TYMED = new HRESULT(0x80040069); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DV_E_CLIPFORMAT = new HRESULT(0x8004006A); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DV_E_DVASPECT = new HRESULT(0x8004006B); + + /// REGDB_E_CLASSNOTREG + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT REGDB_E_CLASSNOTREG = new HRESULT(0x80040154); + + /// DESTS_E_NO_MATCHING_ASSOC_HANDLER. Win7 internal error code for Jump Lists. + /// There is no Assoc Handler for the given item registered by the specified application. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DESTS_E_NO_MATCHING_ASSOC_HANDLER = new HRESULT(0x80040F03); + /// DESTS_E_NORECDOCS. Win7 internal error code for Jump Lists. + /// The given item is excluded from the recent docs folder by the NoRecDocs bit on its registration. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DESTS_E_NORECDOCS = new HRESULT(0x80040F04); + /// DESTS_E_NOTALLCLEARED. Win7 internal error code for Jump Lists. + /// Not all of the items were successfully cleared + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT DESTS_E_NOTALLCLEARED = new HRESULT(0x80040F05); + + /// E_ACCESSDENIED + /// Win32Error ERROR_ACCESS_DENIED. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_ACCESSDENIED = new HRESULT(0x80070005); + /// E_OUTOFMEMORY + /// Win32Error ERROR_OUTOFMEMORY. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_OUTOFMEMORY = new HRESULT(0x8007000E); + /// E_INVALIDARG + /// Win32Error ERROR_INVALID_PARAMETER. + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT E_INVALIDARG = new HRESULT(0x80070057); + /// INTSAFE_E_ARITHMETIC_OVERFLOW + public static readonly HRESULT INTSAFE_E_ARITHMETIC_OVERFLOW = new HRESULT(0x80070216); + /// COR_E_OBJECTDISPOSED + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT COR_E_OBJECTDISPOSED = new HRESULT(0x80131622); + /// WC_E_GREATERTHAN + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WC_E_GREATERTHAN = new HRESULT(0xC00CEE23); + /// WC_E_SYNTAX + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WC_E_SYNTAX = new HRESULT(0xC00CEE2D); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_GENERIC_ERROR = E_FAIL; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_INVALIDPARAMETER = E_INVALIDARG; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_OUTOFMEMORY = E_OUTOFMEMORY; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_NOTIMPLEMENTED = E_NOTIMPL; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_ABORTED = E_ABORT; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_ACCESSDENIED = E_ACCESSDENIED; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_VALUEOVERFLOW = INTSAFE_E_ARITHMETIC_OVERFLOW; + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_WRONGSTATE = Make(true, Facility.WinCodec, 0x2f04); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_VALUEOUTOFRANGE = Make(true, Facility.WinCodec, 0x2f05); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_UNKNOWNIMAGEFORMAT = Make(true, Facility.WinCodec, 0x2f07); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_UNSUPPORTEDVERSION = Make(true, Facility.WinCodec, 0x2f0B); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_NOTINITIALIZED = Make(true, Facility.WinCodec, 0x2f0C); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_ALREADYLOCKED = Make(true, Facility.WinCodec, 0x2f0D); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_PROPERTYNOTFOUND = Make(true, Facility.WinCodec, 0x2f40); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_PROPERTYNOTSUPPORTED = Make(true, Facility.WinCodec, 0x2f41); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_PROPERTYSIZE = Make(true, Facility.WinCodec, 0x2f42); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_CODECPRESENT = Make(true, Facility.WinCodec, 0x2f43); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_CODECNOTHUMBNAIL = Make(true, Facility.WinCodec, 0x2f44); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_PALETTEUNAVAILABLE = Make(true, Facility.WinCodec, 0x2f45); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_CODECTOOMANYSCANLINES = Make(true, Facility.WinCodec, 0x2f46); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_INTERNALERROR = Make(true, Facility.WinCodec, 0x2f48); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_SOURCERECTDOESNOTMATCHDIMENSIONS = Make(true, Facility.WinCodec, 0x2f49); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_COMPONENTNOTFOUND = Make(true, Facility.WinCodec, 0x2f50); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_IMAGESIZEOUTOFRANGE = Make(true, Facility.WinCodec, 0x2f51); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_TOOMUCHMETADATA = Make(true, Facility.WinCodec, 0x2f52); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_BADIMAGE = Make(true, Facility.WinCodec, 0x2f60); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_BADHEADER = Make(true, Facility.WinCodec, 0x2f61); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_FRAMEMISSING = Make(true, Facility.WinCodec, 0x2f62); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_BADMETADATAHEADER = Make(true, Facility.WinCodec, 0x2f63); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_BADSTREAMDATA = Make(true, Facility.WinCodec, 0x2f70); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_STREAMWRITE = Make(true, Facility.WinCodec, 0x2f71); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_STREAMREAD = Make(true, Facility.WinCodec, 0x2f72); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_STREAMNOTAVAILABLE = Make(true, Facility.WinCodec, 0x2f73); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT = Make(true, Facility.WinCodec, 0x2f80); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_UNSUPPORTEDOPERATION = Make(true, Facility.WinCodec, 0x2f81); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_INVALIDREGISTRATION = Make(true, Facility.WinCodec, 0x2f8A); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_COMPONENTINITIALIZEFAILURE = Make(true, Facility.WinCodec, 0x2f8B); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_INSUFFICIENTBUFFER = Make(true, Facility.WinCodec, 0x2f8C); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_DUPLICATEMETADATAPRESENT = Make(true, Facility.WinCodec, 0x2f8D); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_PROPERTYUNEXPECTEDTYPE = Make(true, Facility.WinCodec, 0x2f8E); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_UNEXPECTEDSIZE = Make(true, Facility.WinCodec, 0x2f8F); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_INVALIDQUERYREQUEST = Make(true, Facility.WinCodec, 0x2f90); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_UNEXPECTEDMETADATATYPE = Make(true, Facility.WinCodec, 0x2f91); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_REQUESTONLYVALIDATMETADATAROOT = Make(true, Facility.WinCodec, 0x2f92); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly HRESULT WINCODEC_ERR_INVALIDQUERYCHARACTER = Make(true, Facility.WinCodec, 0x2f93); + + /// + /// Create an HRESULT from an integer value. + /// + /// + public HRESULT(uint i) + { + _value = i; + } + + public HRESULT(int i) + { + _value = unchecked((uint)i); + } + + /// + /// Convert an HRESULT to an int. Used for COM interface declarations out of our control. + /// + public static explicit operator int(HRESULT hr) + { + unchecked + { + return (int)hr._value; + } + } + + public static HRESULT Make(bool severe, Facility facility, int code) + { + //#define MAKE_HRESULT(sev,fac,code) \ + // ((HRESULT) (((unsigned long)(sev)<<31) | ((unsigned long)(fac)<<16) | ((unsigned long)(code))) ) + + // Severity has 1 bit reserved. + // bitness is enforced by the boolean parameter. + + // Facility has 11 bits reserved (different than SCODES, which have 4 bits reserved) + // MSDN documentation incorrectly uses 12 bits for the ESE facility (e5e), so go ahead and let that one slide. + // And WIC also ignores it the documented size... + Assert.Implies((int)facility != (int)((int)facility & 0x1FF), facility == Facility.Ese || facility == Facility.WinCodec); + // Code has 4 bits reserved. + Assert.AreEqual(code, code & 0xFFFF); + + return new HRESULT((uint)((severe ? (1 << 31) : 0) | ((int)facility << 16) | code)); + } + + /// + /// retrieve HRESULT_FACILITY + /// + public Facility Facility + { + get + { + return GetFacility((int)_value); + } + } + + public static Facility GetFacility(int errorCode) + { + // #define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff) + return (Facility)((errorCode >> 16) & 0x1fff); + } + + /// + /// retrieve HRESULT_CODE + /// + public int Code + { + get + { + return GetCode((int)_value); + } + } + + public static int GetCode(int error) + { + // #define HRESULT_CODE(hr) ((hr) & 0xFFFF) + return (int)(error & 0xFFFF); + } + + #region Object class override members + + /// + /// Get a string representation of this HRESULT. + /// + /// + public override string ToString() + { + // Use reflection to try to name this HRESULT. + // This is expensive, but if someone's ever printing HRESULT strings then + // I think it's a fair guess that they're not in a performance critical area + // (e.g. printing exception strings). + // This is less error prone than trying to keep the list in the function. + // To properly add an HRESULT's name to the ToString table, just add the HRESULT + // like all the others above. + // + // CONSIDER: This data is static. It could be cached + // after first usage for fast lookup since the keys are unique. + // + foreach (FieldInfo publicStaticField in typeof(HRESULT).GetFields(BindingFlags.Static | BindingFlags.Public)) + { + if (publicStaticField.FieldType == typeof(HRESULT)) + { + var hr = (HRESULT)publicStaticField.GetValue(null); + if (hr == this) + { + return publicStaticField.Name; + } + } + } + + // Try Win32 error codes also + if (Facility == Facility.Win32) + { + foreach (FieldInfo publicStaticField in typeof(Win32Error).GetFields(BindingFlags.Static | BindingFlags.Public)) + { + if (publicStaticField.FieldType == typeof(Win32Error)) + { + var error = (Win32Error)publicStaticField.GetValue(null); + if ((HRESULT)error == this) + { + return "HRESULT_FROM_WIN32(" + publicStaticField.Name + ")"; + } + } + } + } + + // If there's no good name for this HRESULT, + // return the string as readable hex (0x########) format. + return string.Format(CultureInfo.InvariantCulture, "0x{0:X8}", _value); + } + + public override bool Equals(object obj) + { + try + { + return ((HRESULT)obj)._value == _value; + } + catch (InvalidCastException) + { + return false; + } + } + + public override int GetHashCode() + { + return _value.GetHashCode(); + } + + #endregion + + public static bool operator ==(HRESULT hrLeft, HRESULT hrRight) + { + return hrLeft._value == hrRight._value; + } + + public static bool operator !=(HRESULT hrLeft, HRESULT hrRight) + { + return !(hrLeft == hrRight); + } + + public bool Succeeded + { + get { return (int)_value >= 0; } + } + + public bool Failed + { + get { return (int)_value < 0; } + } + + public void ThrowIfFailed() + { + ThrowIfFailed(null); + } + + [ + SuppressMessage( + "Microsoft.Usage", + "CA2201:DoNotRaiseReservedExceptionTypes", + Justification="Only recreating Exceptions that were already raised."), + SuppressMessage( + "Microsoft.Security", + "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands") + ] + public void ThrowIfFailed(string message) + { + if (Failed) + { + if (string.IsNullOrEmpty(message)) + { + message = ToString(); + } +#if DEBUG + else + { + message += " (" + ToString() + ")"; + } +#endif + // Wow. Reflection in a throw call. Later on this may turn out to have been a bad idea. + // If you're throwing an exception I assume it's OK for me to take some time to give it back. + // I want to convert the HRESULT to a more appropriate exception type than COMException. + // Marshal.ThrowExceptionForHR does this for me, but the general call uses GetErrorInfo + // if it's set, and then ignores the HRESULT that I've provided. This makes it so this + // call works the first time but you get burned on the second. To avoid this, I use + // the overload that explicitly ignores the IErrorInfo. + // In addition, the function doesn't allow me to set the Message unless I go through + // the process of implementing an IErrorInfo and then use that. There's no stock + // implementations of IErrorInfo available and I don't think it's worth the maintenance + // overhead of doing it, nor would it have significant value over this approach. + Exception e = Marshal.GetExceptionForHR((int)_value, new IntPtr(-1)); + Assert.IsNotNull(e); + // ArgumentNullException doesn't have the right constructor parameters, + // (nor does Win32Exception...) + // but E_POINTER gets mapped to NullReferenceException, + // so I don't think it will ever matter. + Assert.IsFalse(e is ArgumentNullException); + + // If we're not getting anything better than a COMException from Marshal, + // then at least check the facility and attempt to do better ourselves. + if (e.GetType() == typeof(COMException)) + { + switch (Facility) + { + case Facility.Win32: + e = new Win32Exception(Code, message); + break; + default: + e = new COMException(message, (int)_value); + break; + } + } + else + { + ConstructorInfo cons = e.GetType().GetConstructor(new[] { typeof(string) }); + if (null != cons) + { + e = cons.Invoke(new object[] { message }) as Exception; + Assert.IsNotNull(e); + } + } + throw e; + } + } + + /// + /// Convert the result of Win32 GetLastError() into a raised exception. + /// + public static void ThrowLastError() + { + ((HRESULT)Win32Error.GetLastError()).ThrowIfFailed(); + // Only expecting to call this when we're expecting a failed GetLastError() + Assert.Fail(); + } + } +} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/standard.net/Windows/FileWalker.cs b/Microsoft.Windows.Shell/standard.net/Windows/FileWalker.cs new file mode 100644 index 0000000..aa4c1f4 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Windows/FileWalker.cs @@ -0,0 +1,116 @@ +// Cribbed heavily from MSDN magazine's .Net Matters (12/2005) by Stephen Toub. +// http://msdn.microsoft.com/msdnmag/issues/05/12/NETMatters/ +// This started off an excellent implementation, I'd rather not unnecessarily rewrite it. +// Some small stylistic changes were made to make it more consistent with the rest of the code +// and also changed the recurse criteria. + +namespace Standard +{ + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Security.Permissions; + + internal class FileWalker + { + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IEnumerable GetFiles(DirectoryInfo startDirectory, string pattern, bool recurse) + { + // We suppressed this demand for each p/invoke call, so demand it upfront once + new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand(); + + // Validate parameters + Verify.IsNotNull(startDirectory, "startDirectory"); + Verify.IsNeitherNullNorEmpty(pattern, "pattern"); + + // Setup + var findData = new WIN32_FIND_DATAW(); + var directories = new Stack(); + directories.Push(startDirectory); + + // Process each directory. Only push new directories if we're recursing. + ErrorModes origErrorMode = NativeMethods.SetErrorMode(ErrorModes.FailCriticalErrors); + try + { + while (directories.Count > 0) + { + // Get the name of the next directory and the corresponding search pattern + DirectoryInfo dir = directories.Pop(); + string dirPath = dir.FullName.Trim(); + if (dirPath.Length == 0) + { + continue; + } + char lastChar = dirPath[dirPath.Length - 1]; + if (lastChar != Path.DirectorySeparatorChar && lastChar != Path.AltDirectorySeparatorChar) + { + dirPath += Path.DirectorySeparatorChar; + } + + // Process all files in that directory + using (SafeFindHandle handle = NativeMethods.FindFirstFileW(dirPath + pattern, findData)) + { + Win32Error error; + if (handle.IsInvalid) + { + error = Win32Error.GetLastError(); + if (error == Win32Error.ERROR_ACCESS_DENIED || error == Win32Error.ERROR_FILE_NOT_FOUND) + { + continue; + } + Assert.AreNotEqual(Win32Error.ERROR_SUCCESS, error); + ((HRESULT)error).ThrowIfFailed(); + } + + do + { + if (!Utility.IsFlagSet((int)findData.dwFileAttributes, (int)FileAttributes.Directory)) + { + yield return new FileInfo(dirPath + findData.cFileName); + } + } + while (NativeMethods.FindNextFileW(handle, findData)); + error = Win32Error.GetLastError(); + if (error != Win32Error.ERROR_NO_MORE_FILES) + { + ((HRESULT)error).ThrowIfFailed(); + } + } + + // Push subdirectories onto the stack if we are recursing. + if (recurse) + { + // In a volatile system we can't count on all the file information staying valid. + // Catch reasonable exceptions and move on. + try + { + foreach (DirectoryInfo childDir in dir.GetDirectories()) + { + try + { + FileAttributes attrib = File.GetAttributes(childDir.FullName); + // If it's not a hidden, system folder, nor a reparse point + if (!Utility.IsFlagSet((int)attrib, (int)(FileAttributes.Hidden | FileAttributes.System | FileAttributes.ReparsePoint))) + { + directories.Push(childDir); + } + } + catch (FileNotFoundException) + { + // Shouldn't see this. + Assert.Fail(); + } + catch (DirectoryNotFoundException) { } + } + } + catch (DirectoryNotFoundException) { } + } + } + } + finally + { + NativeMethods.SetErrorMode(origErrorMode); + } + } + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Windows/NativeMethods.cs b/Microsoft.Windows.Shell/standard.net/Windows/NativeMethods.cs new file mode 100644 index 0000000..384b44a --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Windows/NativeMethods.cs @@ -0,0 +1,3687 @@ +namespace Standard +{ + using System; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Runtime.ConstrainedExecution; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.ComTypes; + using System.Security; + using System.Security.Permissions; + using System.Text; + using Microsoft.Win32.SafeHandles; + + // Some COM interfaces and Win32 structures are already declared in the framework. + // Interesting ones to remember in System.Runtime.InteropServices.ComTypes are: + using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; + using IPersistFile = System.Runtime.InteropServices.ComTypes.IPersistFile; + using IStream = System.Runtime.InteropServices.ComTypes.IStream; + + #region Native Values + + internal static class Win32Value + { + public const uint MAX_PATH = 260; + public const uint INFOTIPSIZE = 1024; + public const int TRUE = 1; + public const int FALSE = 0; + public const uint sizeof_WCHAR = 2; + public const uint sizeof_CHAR = 1; + public const uint sizeof_BOOL = 4; + } + + /// + /// HIGHCONTRAST flags + /// + [Flags] + internal enum HCF + { + HIGHCONTRASTON = 0x00000001, + AVAILABLE = 0x00000002, + HOTKEYACTIVE = 0x00000004, + CONFIRMHOTKEY = 0x00000008, + HOTKEYSOUND = 0x00000010, + INDICATOR = 0x00000020, + HOTKEYAVAILABLE = 0x00000040, + } + + internal enum DROPEFFECT + { + NONE = 0, + COPY = 1, + MOVE = 2, + LINK = 4, + SCROLL = unchecked((int)0x80000000), + } + + /// + /// DROPIMAGE_* + /// + internal enum DROPIMAGETYPE + { + INVALID = -1, + NONE = 0, + COPY = DROPEFFECT.COPY, + MOVE = DROPEFFECT.MOVE, + LINK = DROPEFFECT.LINK, + LABEL = 6, + WARNING = 7, + // Windows 7 and later + NOIMAGE = 8, + } + + /// + /// BITMAPINFOHEADER Compression type. BI_*. + /// + internal enum BI + { + RGB = 0, + } + + /// + /// CombingRgn flags. RGN_* + /// + internal enum RGN + { + /// + /// Creates the intersection of the two combined regions. + /// + AND = 1, + /// + /// Creates the union of two combined regions. + /// + OR = 2, + /// + /// Creates the union of two combined regions except for any overlapping areas. + /// + XOR = 3, + /// + /// Combines the parts of hrgnSrc1 that are not part of hrgnSrc2. + /// + DIFF = 4, + /// + /// Creates a copy of the region identified by hrgnSrc1. + /// + COPY = 5, + } + + internal enum CombineRgnResult + { + ERROR = 0, + NULLREGION = 1, + SIMPLEREGION = 2, + COMPLEXREGION = 3, + } + + /// + /// For IWebBrowser2. OLECMDEXECOPT_* + /// + internal enum OLECMDEXECOPT + { + DODEFAULT = 0, + PROMPTUSER = 1, + DONTPROMPTUSER = 2, + SHOWHELP = 3 + } + + /// + /// For IWebBrowser2. OLECMDF_* + /// + internal enum OLECMDF + { + SUPPORTED = 1, + ENABLED = 2, + LATCHED = 4, + NINCHED = 8, + INVISIBLE = 16, + DEFHIDEONCTXTMENU = 32 + } + + /// + /// For IWebBrowser2. OLECMDID_* + /// + internal enum OLECMDID + { + OPEN = 1, + NEW = 2, + SAVE = 3, + SAVEAS = 4, + SAVECOPYAS = 5, + PRINT = 6, + PRINTPREVIEW = 7, + PAGESETUP = 8, + SPELL = 9, + PROPERTIES = 10, + CUT = 11, + COPY = 12, + PASTE = 13, + PASTESPECIAL = 14, + UNDO = 15, + REDO = 16, + SELECTALL = 17, + CLEARSELECTION = 18, + ZOOM = 19, + GETZOOMRANGE = 20, + UPDATECOMMANDS = 21, + REFRESH = 22, + STOP = 23, + HIDETOOLBARS = 24, + SETPROGRESSMAX = 25, + SETPROGRESSPOS = 26, + SETPROGRESSTEXT = 27, + SETTITLE = 28, + SETDOWNLOADSTATE = 29, + STOPDOWNLOAD = 30, + ONTOOLBARACTIVATED = 31, + FIND = 32, + DELETE = 33, + HTTPEQUIV = 34, + HTTPEQUIV_DONE = 35, + ENABLE_INTERACTION = 36, + ONUNLOAD = 37, + PROPERTYBAG2 = 38, + PREREFRESH = 39, + SHOWSCRIPTERROR = 40, + SHOWMESSAGE = 41, + SHOWFIND = 42, + SHOWPAGESETUP = 43, + SHOWPRINT = 44, + CLOSE = 45, + ALLOWUILESSSAVEAS = 46, + DONTDOWNLOADCSS = 47, + UPDATEPAGESTATUS = 48, + PRINT2 = 49, + PRINTPREVIEW2 = 50, + SETPRINTTEMPLATE = 51, + GETPRINTTEMPLATE = 52, + PAGEACTIONBLOCKED = 55, + PAGEACTIONUIQUERY = 56, + FOCUSVIEWCONTROLS = 57, + FOCUSVIEWCONTROLSQUERY = 58, + SHOWPAGEACTIONMENU = 59 + } + + /// + /// For IWebBrowser2. READYSTATE_* + /// + enum READYSTATE + { + UNINITIALIZED = 0, + LOADING = 1, + LOADED = 2, + INTERACTIVE = 3, + COMPLETE = 4 + } + + /// + /// DATAOBJ_GET_ITEM_FLAGS. DOGIF_*. + /// + internal enum DOGIF + { + DEFAULT = 0x0000, + TRAVERSE_LINK = 0x0001, // if the item is a link get the target + NO_HDROP = 0x0002, // don't fallback and use CF_HDROP clipboard format + NO_URL = 0x0004, // don't fallback and use URL clipboard format + ONLY_IF_ONE = 0x0008, // only return the item if there is one item in the array + } + + internal enum DWM_SIT + { + None, + DISPLAYFRAME = 1, + } + + [Flags] + internal enum ErrorModes + { + /// Use the system default, which is to display all error dialog boxes. + Default = 0x0, + /// + /// The system does not display the critical-error-handler message box. + /// Instead, the system sends the error to the calling process. + /// + FailCriticalErrors = 0x1, + /// + /// 64-bit Windows: The system automatically fixes memory alignment faults and makes them + /// invisible to the application. It does this for the calling process and any descendant processes. + /// After this value is set for a process, subsequent attempts to clear the value are ignored. + /// + NoGpFaultErrorBox = 0x2, + /// + /// The system does not display the general-protection-fault message box. + /// This flag should only be set by debugging applications that handle general + /// protection (GP) faults themselves with an exception handler. + /// + NoAlignmentFaultExcept = 0x4, + /// + /// The system does not display a message box when it fails to find a file. + /// Instead, the error is returned to the calling process. + /// + NoOpenFileErrorBox = 0x8000 + } + + /// + /// Non-client hit test values, HT* + /// + internal enum HT + { + ERROR = -2, + TRANSPARENT = -1, + NOWHERE = 0, + CLIENT = 1, + CAPTION = 2, + SYSMENU = 3, + GROWBOX = 4, + MENU = 5, + HSCROLL = 6, + VSCROLL = 7, + MINBUTTON = 8, + MAXBUTTON = 9, + LEFT = 10, + RIGHT = 11, + TOP = 12, + TOPLEFT = 13, + TOPRIGHT = 14, + BOTTOM = 15, + BOTTOMLEFT = 16, + BOTTOMRIGHT = 17, + BORDER = 18, + OBJECT = 19, + CLOSE = 20, + HELP = 21 + } + + /// + /// GetClassLongPtr values, GCLP_* + /// + internal enum GCLP + { + HBRBACKGROUND = -10, + } + + /// + /// GetWindowLongPtr values, GWL_* + /// + internal enum GWL + { + WNDPROC = (-4), + HINSTANCE = (-6), + HWNDPARENT = (-8), + STYLE = (-16), + EXSTYLE = (-20), + USERDATA = (-21), + ID = (-12) + } + + /// + /// SystemMetrics. SM_* + /// + 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, + } + + /// + /// SystemParameterInfo values, SPI_* + /// + internal enum SPI + { + GETBEEP = 0x0001, + SETBEEP = 0x0002, + GETMOUSE = 0x0003, + SETMOUSE = 0x0004, + GETBORDER = 0x0005, + SETBORDER = 0x0006, + GETKEYBOARDSPEED = 0x000A, + SETKEYBOARDSPEED = 0x000B, + LANGDRIVER = 0x000C, + ICONHORIZONTALSPACING = 0x000D, + GETSCREENSAVETIMEOUT = 0x000E, + SETSCREENSAVETIMEOUT = 0x000F, + GETSCREENSAVEACTIVE = 0x0010, + SETSCREENSAVEACTIVE = 0x0011, + GETGRIDGRANULARITY = 0x0012, + SETGRIDGRANULARITY = 0x0013, + SETDESKWALLPAPER = 0x0014, + SETDESKPATTERN = 0x0015, + GETKEYBOARDDELAY = 0x0016, + SETKEYBOARDDELAY = 0x0017, + ICONVERTICALSPACING = 0x0018, + GETICONTITLEWRAP = 0x0019, + SETICONTITLEWRAP = 0x001A, + GETMENUDROPALIGNMENT = 0x001B, + SETMENUDROPALIGNMENT = 0x001C, + SETDOUBLECLKWIDTH = 0x001D, + SETDOUBLECLKHEIGHT = 0x001E, + GETICONTITLELOGFONT = 0x001F, + SETDOUBLECLICKTIME = 0x0020, + SETMOUSEBUTTONSWAP = 0x0021, + SETICONTITLELOGFONT = 0x0022, + GETFASTTASKSWITCH = 0x0023, + SETFASTTASKSWITCH = 0x0024, + + SETDRAGFULLWINDOWS = 0x0025, + GETDRAGFULLWINDOWS = 0x0026, + GETNONCLIENTMETRICS = 0x0029, + SETNONCLIENTMETRICS = 0x002A, + GETMINIMIZEDMETRICS = 0x002B, + SETMINIMIZEDMETRICS = 0x002C, + GETICONMETRICS = 0x002D, + SETICONMETRICS = 0x002E, + SETWORKAREA = 0x002F, + GETWORKAREA = 0x0030, + SETPENWINDOWS = 0x0031, + GETHIGHCONTRAST = 0x0042, + SETHIGHCONTRAST = 0x0043, + GETKEYBOARDPREF = 0x0044, + SETKEYBOARDPREF = 0x0045, + GETSCREENREADER = 0x0046, + SETSCREENREADER = 0x0047, + GETANIMATION = 0x0048, + SETANIMATION = 0x0049, + GETFONTSMOOTHING = 0x004A, + SETFONTSMOOTHING = 0x004B, + SETDRAGWIDTH = 0x004C, + SETDRAGHEIGHT = 0x004D, + SETHANDHELD = 0x004E, + GETLOWPOWERTIMEOUT = 0x004F, + GETPOWEROFFTIMEOUT = 0x0050, + SETLOWPOWERTIMEOUT = 0x0051, + SETPOWEROFFTIMEOUT = 0x0052, + GETLOWPOWERACTIVE = 0x0053, + GETPOWEROFFACTIVE = 0x0054, + SETLOWPOWERACTIVE = 0x0055, + SETPOWEROFFACTIVE = 0x0056, + SETCURSORS = 0x0057, + SETICONS = 0x0058, + GETDEFAULTINPUTLANG = 0x0059, + SETDEFAULTINPUTLANG = 0x005A, + SETLANGTOGGLE = 0x005B, + GETWINDOWSEXTENSION = 0x005C, + SETMOUSETRAILS = 0x005D, + GETMOUSETRAILS = 0x005E, + SETSCREENSAVERRUNNING = 0x0061, + SCREENSAVERRUNNING = SETSCREENSAVERRUNNING, + GETFILTERKEYS = 0x0032, + SETFILTERKEYS = 0x0033, + GETTOGGLEKEYS = 0x0034, + SETTOGGLEKEYS = 0x0035, + GETMOUSEKEYS = 0x0036, + SETMOUSEKEYS = 0x0037, + GETSHOWSOUNDS = 0x0038, + SETSHOWSOUNDS = 0x0039, + GETSTICKYKEYS = 0x003A, + SETSTICKYKEYS = 0x003B, + GETACCESSTIMEOUT = 0x003C, + SETACCESSTIMEOUT = 0x003D, + + GETSERIALKEYS = 0x003E, + SETSERIALKEYS = 0x003F, + GETSOUNDSENTRY = 0x0040, + SETSOUNDSENTRY = 0x0041, + GETSNAPTODEFBUTTON = 0x005F, + SETSNAPTODEFBUTTON = 0x0060, + GETMOUSEHOVERWIDTH = 0x0062, + SETMOUSEHOVERWIDTH = 0x0063, + GETMOUSEHOVERHEIGHT = 0x0064, + SETMOUSEHOVERHEIGHT = 0x0065, + GETMOUSEHOVERTIME = 0x0066, + SETMOUSEHOVERTIME = 0x0067, + GETWHEELSCROLLLINES = 0x0068, + SETWHEELSCROLLLINES = 0x0069, + GETMENUSHOWDELAY = 0x006A, + SETMENUSHOWDELAY = 0x006B, + + GETWHEELSCROLLCHARS = 0x006C, + SETWHEELSCROLLCHARS = 0x006D, + + GETSHOWIMEUI = 0x006E, + SETSHOWIMEUI = 0x006F, + + GETMOUSESPEED = 0x0070, + SETMOUSESPEED = 0x0071, + GETSCREENSAVERRUNNING = 0x0072, + GETDESKWALLPAPER = 0x0073, + + GETAUDIODESCRIPTION = 0x0074, + SETAUDIODESCRIPTION = 0x0075, + + GETSCREENSAVESECURE = 0x0076, + SETSCREENSAVESECURE = 0x0077, + + GETHUNGAPPTIMEOUT = 0x0078, + SETHUNGAPPTIMEOUT = 0x0079, + GETWAITTOKILLTIMEOUT = 0x007A, + SETWAITTOKILLTIMEOUT = 0x007B, + GETWAITTOKILLSERVICETIMEOUT = 0x007C, + SETWAITTOKILLSERVICETIMEOUT = 0x007D, + GETMOUSEDOCKTHRESHOLD = 0x007E, + SETMOUSEDOCKTHRESHOLD = 0x007F, + GETPENDOCKTHRESHOLD = 0x0080, + SETPENDOCKTHRESHOLD = 0x0081, + GETWINARRANGING = 0x0082, + SETWINARRANGING = 0x0083, + GETMOUSEDRAGOUTTHRESHOLD = 0x0084, + SETMOUSEDRAGOUTTHRESHOLD = 0x0085, + GETPENDRAGOUTTHRESHOLD = 0x0086, + SETPENDRAGOUTTHRESHOLD = 0x0087, + GETMOUSESIDEMOVETHRESHOLD = 0x0088, + SETMOUSESIDEMOVETHRESHOLD = 0x0089, + GETPENSIDEMOVETHRESHOLD = 0x008A, + SETPENSIDEMOVETHRESHOLD = 0x008B, + GETDRAGFROMMAXIMIZE = 0x008C, + SETDRAGFROMMAXIMIZE = 0x008D, + GETSNAPSIZING = 0x008E, + SETSNAPSIZING = 0x008F, + GETDOCKMOVING = 0x0090, + SETDOCKMOVING = 0x0091, + + GETACTIVEWINDOWTRACKING = 0x1000, + SETACTIVEWINDOWTRACKING = 0x1001, + GETMENUANIMATION = 0x1002, + SETMENUANIMATION = 0x1003, + GETCOMBOBOXANIMATION = 0x1004, + SETCOMBOBOXANIMATION = 0x1005, + GETLISTBOXSMOOTHSCROLLING = 0x1006, + SETLISTBOXSMOOTHSCROLLING = 0x1007, + GETGRADIENTCAPTIONS = 0x1008, + SETGRADIENTCAPTIONS = 0x1009, + GETKEYBOARDCUES = 0x100A, + SETKEYBOARDCUES = 0x100B, + GETMENUUNDERLINES = GETKEYBOARDCUES, + SETMENUUNDERLINES = SETKEYBOARDCUES, + GETACTIVEWNDTRKZORDER = 0x100C, + SETACTIVEWNDTRKZORDER = 0x100D, + GETHOTTRACKING = 0x100E, + SETHOTTRACKING = 0x100F, + GETMENUFADE = 0x1012, + SETMENUFADE = 0x1013, + GETSELECTIONFADE = 0x1014, + SETSELECTIONFADE = 0x1015, + GETTOOLTIPANIMATION = 0x1016, + SETTOOLTIPANIMATION = 0x1017, + GETTOOLTIPFADE = 0x1018, + SETTOOLTIPFADE = 0x1019, + GETCURSORSHADOW = 0x101A, + SETCURSORSHADOW = 0x101B, + GETMOUSESONAR = 0x101C, + SETMOUSESONAR = 0x101D, + GETMOUSECLICKLOCK = 0x101E, + SETMOUSECLICKLOCK = 0x101F, + GETMOUSEVANISH = 0x1020, + SETMOUSEVANISH = 0x1021, + GETFLATMENU = 0x1022, + SETFLATMENU = 0x1023, + GETDROPSHADOW = 0x1024, + SETDROPSHADOW = 0x1025, + GETBLOCKSENDINPUTRESETS = 0x1026, + SETBLOCKSENDINPUTRESETS = 0x1027, + + GETUIEFFECTS = 0x103E, + SETUIEFFECTS = 0x103F, + + GETDISABLEOVERLAPPEDCONTENT = 0x1040, + SETDISABLEOVERLAPPEDCONTENT = 0x1041, + GETCLIENTAREAANIMATION = 0x1042, + SETCLIENTAREAANIMATION = 0x1043, + GETCLEARTYPE = 0x1048, + SETCLEARTYPE = 0x1049, + GETSPEECHRECOGNITION = 0x104A, + SETSPEECHRECOGNITION = 0x104B, + + GETFOREGROUNDLOCKTIMEOUT = 0x2000, + SETFOREGROUNDLOCKTIMEOUT = 0x2001, + GETACTIVEWNDTRKTIMEOUT = 0x2002, + SETACTIVEWNDTRKTIMEOUT = 0x2003, + GETFOREGROUNDFLASHCOUNT = 0x2004, + SETFOREGROUNDFLASHCOUNT = 0x2005, + GETCARETWIDTH = 0x2006, + SETCARETWIDTH = 0x2007, + + GETMOUSECLICKLOCKTIME = 0x2008, + SETMOUSECLICKLOCKTIME = 0x2009, + GETFONTSMOOTHINGTYPE = 0x200A, + SETFONTSMOOTHINGTYPE = 0x200B, + + GETFONTSMOOTHINGCONTRAST = 0x200C, + SETFONTSMOOTHINGCONTRAST = 0x200D, + + GETFOCUSBORDERWIDTH = 0x200E, + SETFOCUSBORDERWIDTH = 0x200F, + GETFOCUSBORDERHEIGHT = 0x2010, + SETFOCUSBORDERHEIGHT = 0x2011, + + GETFONTSMOOTHINGORIENTATION = 0x2012, + SETFONTSMOOTHINGORIENTATION = 0x2013, + + GETMINIMUMHITRADIUS = 0x2014, + SETMINIMUMHITRADIUS = 0x2015, + GETMESSAGEDURATION = 0x2016, + SETMESSAGEDURATION = 0x2017, + } + + /// + /// SystemParameterInfo flag values, SPIF_* + /// + [Flags] + internal enum SPIF + { + None = 0, + UPDATEINIFILE = 0x01, + SENDWININICHANGE = 0x02, + } + + [Flags] + internal enum STATE_SYSTEM + { + UNAVAILABLE = 0x00000001, // Disabled + SELECTED = 0x00000002, + FOCUSED = 0x00000004, + PRESSED = 0x00000008, + CHECKED = 0x00000010, + MIXED = 0x00000020, // 3-state checkbox or toolbar button + INDETERMINATE = MIXED, + READONLY = 0x00000040, + HOTTRACKED = 0x00000080, + DEFAULT = 0x00000100, + EXPANDED = 0x00000200, + COLLAPSED = 0x00000400, + BUSY = 0x00000800, + FLOATING = 0x00001000, // Children "owned" not "contained" by parent + MARQUEED = 0x00002000, + ANIMATED = 0x00004000, + INVISIBLE = 0x00008000, + OFFSCREEN = 0x00010000, + SIZEABLE = 0x00020000, + MOVEABLE = 0x00040000, + SELFVOICING = 0x00080000, + FOCUSABLE = 0x00100000, + SELECTABLE = 0x00200000, + LINKED = 0x00400000, + TRAVERSED = 0x00800000, + MULTISELECTABLE = 0x01000000, // Supports multiple selection + EXTSELECTABLE = 0x02000000, // Supports extended selection + ALERT_LOW = 0x04000000, // This information is of low priority + ALERT_MEDIUM = 0x08000000, // This information is of medium priority + ALERT_HIGH = 0x10000000, // This information is of high priority + PROTECTED = 0x20000000, // access to this is restricted + VALID = 0x3FFFFFFF, + } + + internal enum StockObject : int + { + WHITE_BRUSH = 0, + LTGRAY_BRUSH = 1, + GRAY_BRUSH = 2, + DKGRAY_BRUSH = 3, + BLACK_BRUSH = 4, + NULL_BRUSH = 5, + HOLLOW_BRUSH = NULL_BRUSH, + WHITE_PEN = 6, + BLACK_PEN = 7, + NULL_PEN = 8, + SYSTEM_FONT = 13, + DEFAULT_PALETTE = 15, + } + + /// + /// CS_* + /// + [Flags] + internal enum CS : uint + { + VREDRAW = 0x0001, + HREDRAW = 0x0002, + DBLCLKS = 0x0008, + OWNDC = 0x0020, + CLASSDC = 0x0040, + PARENTDC = 0x0080, + NOCLOSE = 0x0200, + SAVEBITS = 0x0800, + BYTEALIGNCLIENT = 0x1000, + BYTEALIGNWINDOW = 0x2000, + GLOBALCLASS = 0x4000, + IME = 0x00010000, + DROPSHADOW = 0x00020000 + } + + /// + /// WindowStyle values, WS_* + /// + [Flags] + internal enum WS : uint + { + OVERLAPPED = 0x00000000, + POPUP = 0x80000000, + CHILD = 0x40000000, + MINIMIZE = 0x20000000, + VISIBLE = 0x10000000, + DISABLED = 0x08000000, + CLIPSIBLINGS = 0x04000000, + CLIPCHILDREN = 0x02000000, + MAXIMIZE = 0x01000000, + BORDER = 0x00800000, + DLGFRAME = 0x00400000, + VSCROLL = 0x00200000, + HSCROLL = 0x00100000, + SYSMENU = 0x00080000, + THICKFRAME = 0x00040000, + GROUP = 0x00020000, + TABSTOP = 0x00010000, + + MINIMIZEBOX = 0x00020000, + MAXIMIZEBOX = 0x00010000, + + CAPTION = BORDER | DLGFRAME, + TILED = OVERLAPPED, + ICONIC = MINIMIZE, + SIZEBOX = THICKFRAME, + TILEDWINDOW = OVERLAPPEDWINDOW, + + OVERLAPPEDWINDOW = OVERLAPPED | CAPTION | SYSMENU | THICKFRAME | MINIMIZEBOX | MAXIMIZEBOX, + POPUPWINDOW = POPUP | BORDER | SYSMENU, + CHILDWINDOW = CHILD, + } + + /// + /// Window message values, WM_* + /// + internal enum WM + { + NULL = 0x0000, + CREATE = 0x0001, + DESTROY = 0x0002, + MOVE = 0x0003, + SIZE = 0x0005, + ACTIVATE = 0x0006, + SETFOCUS = 0x0007, + KILLFOCUS = 0x0008, + ENABLE = 0x000A, + SETREDRAW = 0x000B, + SETTEXT = 0x000C, + GETTEXT = 0x000D, + GETTEXTLENGTH = 0x000E, + PAINT = 0x000F, + CLOSE = 0x0010, + QUERYENDSESSION = 0x0011, + QUIT = 0x0012, + QUERYOPEN = 0x0013, + ERASEBKGND = 0x0014, + SYSCOLORCHANGE = 0x0015, + SHOWWINDOW = 0x0018, + CTLCOLOR = 0x0019, + WININICHANGE = 0x001A, + SETTINGCHANGE = 0x001A, + ACTIVATEAPP = 0x001C, + SETCURSOR = 0x0020, + MOUSEACTIVATE = 0x0021, + CHILDACTIVATE = 0x0022, + QUEUESYNC = 0x0023, + GETMINMAXINFO = 0x0024, + + WINDOWPOSCHANGING = 0x0046, + WINDOWPOSCHANGED = 0x0047, + + CONTEXTMENU = 0x007B, + STYLECHANGING = 0x007C, + STYLECHANGED = 0x007D, + DISPLAYCHANGE = 0x007E, + GETICON = 0x007F, + SETICON = 0x0080, + NCCREATE = 0x0081, + NCDESTROY = 0x0082, + NCCALCSIZE = 0x0083, + NCHITTEST = 0x0084, + NCPAINT = 0x0085, + NCACTIVATE = 0x0086, + GETDLGCODE = 0x0087, + SYNCPAINT = 0x0088, + NCMOUSEMOVE = 0x00A0, + NCLBUTTONDOWN = 0x00A1, + NCLBUTTONUP = 0x00A2, + NCLBUTTONDBLCLK = 0x00A3, + NCRBUTTONDOWN = 0x00A4, + NCRBUTTONUP = 0x00A5, + NCRBUTTONDBLCLK = 0x00A6, + NCMBUTTONDOWN = 0x00A7, + NCMBUTTONUP = 0x00A8, + NCMBUTTONDBLCLK = 0x00A9, + + SYSKEYDOWN = 0x0104, + SYSKEYUP = 0x0105, + SYSCHAR = 0x0106, + SYSDEADCHAR = 0x0107, + COMMAND = 0x0111, + SYSCOMMAND = 0x0112, + + MOUSEMOVE = 0x0200, + LBUTTONDOWN = 0x0201, + LBUTTONUP = 0x0202, + LBUTTONDBLCLK = 0x0203, + RBUTTONDOWN = 0x0204, + RBUTTONUP = 0x0205, + RBUTTONDBLCLK = 0x0206, + MBUTTONDOWN = 0x0207, + MBUTTONUP = 0x0208, + MBUTTONDBLCLK = 0x0209, + MOUSEWHEEL = 0x020A, + XBUTTONDOWN = 0x020B, + XBUTTONUP = 0x020C, + XBUTTONDBLCLK = 0x020D, + MOUSEHWHEEL = 0x020E, + PARENTNOTIFY = 0x0210, + + CAPTURECHANGED = 0x0215, + POWERBROADCAST = 0x0218, + DEVICECHANGE = 0x0219, + + ENTERSIZEMOVE = 0x0231, + EXITSIZEMOVE = 0x0232, + + IME_SETCONTEXT = 0x0281, + IME_NOTIFY = 0x0282, + IME_CONTROL = 0x0283, + IME_COMPOSITIONFULL = 0x0284, + IME_SELECT = 0x0285, + IME_CHAR = 0x0286, + IME_REQUEST = 0x0288, + IME_KEYDOWN = 0x0290, + IME_KEYUP = 0x0291, + + NCMOUSELEAVE = 0x02A2, + + TABLET_DEFBASE = 0x02C0, + //WM_TABLET_MAXOFFSET = 0x20, + + TABLET_ADDED = TABLET_DEFBASE + 8, + TABLET_DELETED = TABLET_DEFBASE + 9, + TABLET_FLICK = TABLET_DEFBASE + 11, + TABLET_QUERYSYSTEMGESTURESTATUS = TABLET_DEFBASE + 12, + + CUT = 0x0300, + COPY = 0x0301, + PASTE = 0x0302, + CLEAR = 0x0303, + UNDO = 0x0304, + RENDERFORMAT = 0x0305, + RENDERALLFORMATS = 0x0306, + DESTROYCLIPBOARD = 0x0307, + DRAWCLIPBOARD = 0x0308, + PAINTCLIPBOARD = 0x0309, + VSCROLLCLIPBOARD = 0x030A, + SIZECLIPBOARD = 0x030B, + ASKCBFORMATNAME = 0x030C, + CHANGECBCHAIN = 0x030D, + HSCROLLCLIPBOARD = 0x030E, + QUERYNEWPALETTE = 0x030F, + PALETTEISCHANGING = 0x0310, + PALETTECHANGED = 0x0311, + HOTKEY = 0x0312, + PRINT = 0x0317, + PRINTCLIENT = 0x0318, + APPCOMMAND = 0x0319, + THEMECHANGED = 0x031A, + + DWMCOMPOSITIONCHANGED = 0x031E, + DWMNCRENDERINGCHANGED = 0x031F, + DWMCOLORIZATIONCOLORCHANGED = 0x0320, + DWMWINDOWMAXIMIZEDCHANGE = 0x0321, + + GETTITLEBARINFOEX = 0x033F, + + #region Windows 7 + DWMSENDICONICTHUMBNAIL = 0x0323, + DWMSENDICONICLIVEPREVIEWBITMAP = 0x0326, + #endregion + + USER = 0x0400, + + // This is the hard-coded message value used by WinForms for Shell_NotifyIcon. + // It's relatively safe to reuse. + TRAYMOUSEMESSAGE = 0x800, //WM_USER + 1024 + APP = 0x8000, + } + + /// + /// Window style extended values, WS_EX_* + /// + [Flags] + internal enum WS_EX : uint + { + None = 0, + DLGMODALFRAME = 0x00000001, + NOPARENTNOTIFY = 0x00000004, + TOPMOST = 0x00000008, + ACCEPTFILES = 0x00000010, + TRANSPARENT = 0x00000020, + MDICHILD = 0x00000040, + TOOLWINDOW = 0x00000080, + WINDOWEDGE = 0x00000100, + CLIENTEDGE = 0x00000200, + CONTEXTHELP = 0x00000400, + RIGHT = 0x00001000, + LEFT = 0x00000000, + RTLREADING = 0x00002000, + LTRREADING = 0x00000000, + LEFTSCROLLBAR = 0x00004000, + RIGHTSCROLLBAR = 0x00000000, + CONTROLPARENT = 0x00010000, + STATICEDGE = 0x00020000, + APPWINDOW = 0x00040000, + LAYERED = 0x00080000, + NOINHERITLAYOUT = 0x00100000, // Disable inheritence of mirroring by children + LAYOUTRTL = 0x00400000, // Right to left mirroring + COMPOSITED = 0x02000000, + NOACTIVATE = 0x08000000, + OVERLAPPEDWINDOW = (WINDOWEDGE | CLIENTEDGE), + PALETTEWINDOW = (WINDOWEDGE | TOOLWINDOW | TOPMOST), + } + + /// + /// GetDeviceCaps nIndex values. + /// + internal enum DeviceCap + { + /// Number of bits per pixel + /// + BITSPIXEL = 12, + /// + /// Number of planes + /// + PLANES = 14, + /// + /// Logical pixels inch in X + /// + LOGPIXELSX = 88, + /// + /// Logical pixels inch in Y + /// + LOGPIXELSY = 90, + } + + internal enum FO : int + { + MOVE = 0x0001, + COPY = 0x0002, + DELETE = 0x0003, + RENAME = 0x0004, + } + + /// + /// "FILEOP_FLAGS", FOF_*. + /// + internal enum FOF : ushort + { + MULTIDESTFILES = 0x0001, + CONFIRMMOUSE = 0x0002, + SILENT = 0x0004, + RENAMEONCOLLISION = 0x0008, + NOCONFIRMATION = 0x0010, + WANTMAPPINGHANDLE = 0x0020, + ALLOWUNDO = 0x0040, + FILESONLY = 0x0080, + SIMPLEPROGRESS = 0x0100, + NOCONFIRMMKDIR = 0x0200, + NOERRORUI = 0x0400, + NOCOPYSECURITYATTRIBS = 0x0800, + NORECURSION = 0x1000, + NO_CONNECTED_ELEMENTS = 0x2000, + WANTNUKEWARNING = 0x4000, + NORECURSEREPARSE = 0x8000, + } + + /// + /// EnableMenuItem uEnable values, MF_* + /// + [Flags] + internal enum MF : uint + { + /// + /// Possible return value for EnableMenuItem + /// + DOES_NOT_EXIST = unchecked((uint)-1), + ENABLED = 0, + BYCOMMAND = 0, + GRAYED = 1, + DISABLED = 2, + } + + /// Specifies the type of visual style attribute to set on a window. + internal enum WINDOWTHEMEATTRIBUTETYPE : uint + { + /// Non-client area window attributes will be set. + WTA_NONCLIENT = 1, + } + + /// + /// DWMFLIP3DWINDOWPOLICY. DWMFLIP3D_* + /// + internal enum DWMFLIP3D + { + DEFAULT, + EXCLUDEBELOW, + EXCLUDEABOVE, + //LAST + } + + /// + /// DWMNCRENDERINGPOLICY. DWMNCRP_* + /// + internal enum DWMNCRP + { + USEWINDOWSTYLE, + DISABLED, + ENABLED, + //LAST + } + + /// + /// DWMWINDOWATTRIBUTE. DWMWA_* + /// + internal enum DWMWA + { + NCRENDERING_ENABLED = 1, + NCRENDERING_POLICY, + TRANSITIONS_FORCEDISABLED, + ALLOW_NCPAINT, + CAPTION_BUTTON_BOUNDS, + NONCLIENT_RTL_LAYOUT, + FORCE_ICONIC_REPRESENTATION, + FLIP3D_POLICY, + EXTENDED_FRAME_BOUNDS, + + // New to Windows 7: + + HAS_ICONIC_BITMAP, + DISALLOW_PEEK, + EXCLUDED_FROM_PEEK, + + // LAST + } + + /// + /// WindowThemeNonClientAttributes + /// + [Flags] + internal enum WTNCA : uint + { + /// Prevents the window caption from being drawn. + NODRAWCAPTION = 0x00000001, + /// Prevents the system icon from being drawn. + NODRAWICON = 0x00000002, + /// Prevents the system icon menu from appearing. + NOSYSMENU = 0x00000004, + /// Prevents mirroring of the question mark, even in right-to-left (RTL) layout. + NOMIRRORHELP = 0x00000008, + /// A mask that contains all the valid bits. + VALIDBITS = NODRAWCAPTION | NODRAWICON | NOMIRRORHELP | NOSYSMENU, + } + + /// + /// SetWindowPos options + /// + [Flags] + internal enum SWP + { + ASYNCWINDOWPOS = 0x4000, + DEFERERASE = 0x2000, + DRAWFRAME = 0x0020, + FRAMECHANGED = 0x0020, + HIDEWINDOW = 0x0080, + NOACTIVATE = 0x0010, + NOCOPYBITS = 0x0100, + NOMOVE = 0x0002, + NOOWNERZORDER = 0x0200, + NOREDRAW = 0x0008, + NOREPOSITION = 0x0200, + NOSENDCHANGING = 0x0400, + NOSIZE = 0x0001, + NOZORDER = 0x0004, + SHOWWINDOW = 0x0040, + } + + /// + /// ShowWindow options + /// + internal enum SW + { + HIDE = 0, + SHOWNORMAL = 1, + NORMAL = 1, + SHOWMINIMIZED = 2, + SHOWMAXIMIZED = 3, + MAXIMIZE = 3, + SHOWNOACTIVATE = 4, + SHOW = 5, + MINIMIZE = 6, + SHOWMINNOACTIVE = 7, + SHOWNA = 8, + RESTORE = 9, + SHOWDEFAULT = 10, + FORCEMINIMIZE = 11, + } + + internal enum SC + { + SIZE = 0xF000, + MOVE = 0xF010, + MINIMIZE = 0xF020, + MAXIMIZE = 0xF030, + NEXTWINDOW = 0xF040, + PREVWINDOW = 0xF050, + CLOSE = 0xF060, + VSCROLL = 0xF070, + HSCROLL = 0xF080, + MOUSEMENU = 0xF090, + KEYMENU = 0xF100, + ARRANGE = 0xF110, + RESTORE = 0xF120, + TASKLIST = 0xF130, + SCREENSAVE = 0xF140, + HOTKEY = 0xF150, + DEFAULT = 0xF160, + MONITORPOWER = 0xF170, + CONTEXTHELP = 0xF180, + SEPARATOR = 0xF00F, + /// + /// SCF_ISSECURE + /// + F_ISSECURE = 0x00000001, + ICON = MINIMIZE, + ZOOM = MAXIMIZE, + } + + /// + /// GDI+ Status codes + /// + internal enum Status + { + 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, + ProfileNotFound = 21, + } + + internal enum MOUSEEVENTF : int + { + //mouse event constants + LEFTDOWN = 2, + LEFTUP = 4 + } + + /// + /// MSGFLT_*. New in Vista. Realiased in Windows 7. + /// + internal enum MSGFLT + { + // Win7 versions of this enum: + RESET = 0, + ALLOW = 1, + DISALLOW = 2, + + // Vista versions of this enum: + // ADD = 1, + // REMOVE = 2, + } + + internal enum MSGFLTINFO + { + NONE = 0, + ALREADYALLOWED_FORWND = 1, + ALREADYDISALLOWED_FORWND = 2, + ALLOWED_HIGHER = 3, + } + + internal enum INPUT_TYPE : uint + { + MOUSE = 0, + } + + /// + /// Shell_NotifyIcon messages. NIM_* + /// + internal enum NIM : uint + { + ADD = 0, + MODIFY = 1, + DELETE = 2, + SETFOCUS = 3, + SETVERSION = 4, + } + + /// + /// SHAddToRecentDocuments flags. SHARD_* + /// + internal enum SHARD + { + PIDL = 0x00000001, + PATHA = 0x00000002, + PATHW = 0x00000003, + APPIDINFO = 0x00000004, // indicates the data type is a pointer to a SHARDAPPIDINFO structure + APPIDINFOIDLIST = 0x00000005, // indicates the data type is a pointer to a SHARDAPPIDINFOIDLIST structure + LINK = 0x00000006, // indicates the data type is a pointer to an IShellLink instance + APPIDINFOLINK = 0x00000007, // indicates the data type is a pointer to a SHARDAPPIDINFOLINK structure + } + + [Flags] + enum SLGP + { + SHORTPATH = 0x1, + UNCPRIORITY = 0x2, + RAWPATH = 0x4 + } + + /// + /// Shell_NotifyIcon flags. NIF_* + /// + [Flags] + internal enum NIF : uint + { + MESSAGE = 0x0001, + ICON = 0x0002, + TIP = 0x0004, + STATE = 0x0008, + INFO = 0x0010, + GUID = 0x0020, + + /// + /// Vista only. + /// + REALTIME = 0x0040, + /// + /// Vista only. + /// + SHOWTIP = 0x0080, + + XP_MASK = MESSAGE | ICON | STATE | INFO | GUID, + VISTA_MASK = XP_MASK | REALTIME | SHOWTIP, + } + + /// + /// Shell_NotifyIcon info flags. NIIF_* + /// + internal enum NIIF + { + NONE = 0x00000000, + INFO = 0x00000001, + WARNING = 0x00000002, + ERROR = 0x00000003, + /// XP SP2 and later. + USER = 0x00000004, + /// XP and later. + NOSOUND = 0x00000010, + /// Vista and later. + LARGE_ICON = 0x00000020, + /// Windows 7 and later + NIIF_RESPECT_QUIET_TIME = 0x00000080, + /// XP and later. Native version called NIIF_ICON_MASK. + XP_ICON_MASK = 0x0000000F, + } + + /// + /// AC_* + /// + internal enum AC : byte + { + SRC_OVER = 0, + SRC_ALPHA = 1, + } + + internal enum ULW + { + ALPHA = 2, + COLORKEY = 1, + OPAQUE = 4, + } + + internal enum WVR + { + ALIGNTOP = 0x0010, + ALIGNLEFT = 0x0020, + ALIGNBOTTOM = 0x0040, + ALIGNRIGHT = 0x0080, + HREDRAW = 0x0100, + VREDRAW = 0x0200, + VALIDRECTS = 0x0400, + REDRAW = HREDRAW | VREDRAW, + } + + internal enum DSH + { + ALLOWDROPDESCRIPTIONTEXT = 1, + } + + #endregion + + #region SafeHandles + + internal sealed class SafeFindHandle : SafeHandleZeroOrMinusOneIsInvalid + { + [SecurityCritical] + private SafeFindHandle() : base(true) { } + + protected override bool ReleaseHandle() + { + return NativeMethods.FindClose(handle); + } + } + + internal sealed class SafeDC : SafeHandleZeroOrMinusOneIsInvalid + { + private static class NativeMethods + { + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern SafeDC GetDC(IntPtr hwnd); + + // Weird legacy function, documentation is unclear about how to use it... + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", CharSet = CharSet.Unicode)] + public static extern SafeDC CreateDC([MarshalAs(UnmanagedType.LPWStr)] string lpszDriver, [MarshalAs(UnmanagedType.LPWStr)] string lpszDevice, IntPtr lpszOutput, IntPtr lpInitData); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern SafeDC CreateCompatibleDC(IntPtr hdc); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DeleteDC(IntPtr hdc); + } + + private IntPtr? _hwnd; + private bool _created; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public IntPtr Hwnd + { + set + { + Assert.NullableIsNull(_hwnd); + _hwnd = value; + } + } + + private SafeDC() : base(true) { } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + if (_created) + { + return NativeMethods.DeleteDC(handle); + } + + if (!_hwnd.HasValue || _hwnd.Value == IntPtr.Zero) + { + return true; + } + + return NativeMethods.ReleaseDC(_hwnd.Value, handle) == 1; + } + + [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes"), SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static SafeDC CreateDC(string deviceName) + { + SafeDC dc = null; + try + { + // Should this really be on the driver parameter? + dc = NativeMethods.CreateDC(deviceName, null, IntPtr.Zero, IntPtr.Zero); + } + finally + { + if (dc != null) + { + dc._created = true; + } + } + + if (dc.IsInvalid) + { + dc.Dispose(); + throw new SystemException("Unable to create a device context from the specified device information."); + } + + return dc; + } + + [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes"), SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static SafeDC CreateCompatibleDC(SafeDC hdc) + { + SafeDC dc = null; + try + { + IntPtr hPtr = IntPtr.Zero; + if (hdc != null) + { + hPtr = hdc.handle; + } + dc = NativeMethods.CreateCompatibleDC(hPtr); + if (dc == null) + { + HRESULT.ThrowLastError(); + } + } + finally + { + if (dc != null) + { + dc._created = true; + } + } + + if (dc.IsInvalid) + { + dc.Dispose(); + throw new SystemException("Unable to create a device context from the specified device information."); + } + + return dc; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static SafeDC GetDC(IntPtr hwnd) + { + SafeDC dc = null; + try + { + dc = NativeMethods.GetDC(hwnd); + } + finally + { + if (dc != null) + { + dc.Hwnd = hwnd; + } + } + + if (dc.IsInvalid) + { + // GetDC does not set the last error... + HRESULT.E_FAIL.ThrowIfFailed(); + } + + return dc; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static SafeDC GetDesktop() + { + return GetDC(IntPtr.Zero); + } + + // In method 'SafeDC.WrapDC(IntPtr)', object '<>g__initLocal0' is not disposed along all exception paths. + // Call System.IDisposable.Dispose on object '<>g__initLocal0' before all references to it are out of scope. + // Sure... + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static SafeDC WrapDC(IntPtr hdc) + { + // This won't actually get released by the class, but it allows an IntPtr to be converted for signatures. + return new SafeDC + { + handle = hdc, + _created = false, + _hwnd = IntPtr.Zero, + }; + } + } + + internal sealed class SafeHBITMAP : SafeHandleZeroOrMinusOneIsInvalid + { + private SafeHBITMAP() : base(true) { } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + return NativeMethods.DeleteObject(handle); + } + } + + internal sealed class SafeGdiplusStartupToken : SafeHandleZeroOrMinusOneIsInvalid + { + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private SafeGdiplusStartupToken(IntPtr ptr) : base(true) { + handle = ptr; + } + + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + Status s = NativeMethods.GdiplusShutdown(this.handle); + return s == Status.Ok; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Usage", "CA2201:DoNotRaiseReservedExceptionTypes")] + public static SafeGdiplusStartupToken Startup() + { + IntPtr unsafeHandle; + StartupOutput output; + Status s = NativeMethods.GdiplusStartup(out unsafeHandle, new StartupInput(), out output); + if (s == Status.Ok) + { + SafeGdiplusStartupToken safeHandle = new SafeGdiplusStartupToken(unsafeHandle); + return safeHandle; + } + throw new Exception("Unable to initialize GDI+"); + } + } + + internal sealed class SafeConnectionPointCookie : SafeHandleZeroOrMinusOneIsInvalid + { + private IConnectionPoint _cp; + // handle holds the cookie value. + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Naming", "CA2204:Literals should be spelled correctly", MessageId = "IConnectionPoint")] + public SafeConnectionPointCookie(IConnectionPointContainer target, object sink, Guid eventId) + : base(true) + { + Verify.IsNotNull(target, "target"); + Verify.IsNotNull(sink, "sink"); + Verify.IsNotDefault(eventId, "eventId"); + + handle = IntPtr.Zero; + + IConnectionPoint cp = null; + try + { + int dwCookie; + target.FindConnectionPoint(ref eventId, out cp); + cp.Advise(sink, out dwCookie); + if (dwCookie == 0) + { + throw new InvalidOperationException("IConnectionPoint::Advise returned an invalid cookie."); + } + handle = new IntPtr(dwCookie); + _cp = cp; + cp = null; + } + finally + { + Utility.SafeRelease(ref cp); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void Disconnect() + { + ReleaseHandle(); + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] + protected override bool ReleaseHandle() + { + try + { + if (!this.IsInvalid) + { + int dwCookie = handle.ToInt32(); + handle = IntPtr.Zero; + + Assert.IsNotNull(_cp); + try + { + _cp.Unadvise(dwCookie); + } + finally + { + Utility.SafeRelease(ref _cp); + } + } + return true; + } + catch + { + return false; + } + } + } + + #endregion + + #region Native Types + + [StructLayout(LayoutKind.Sequential)] + internal struct BLENDFUNCTION + { + // Must be AC_SRC_OVER + public AC BlendOp; + // Must be 0. + public byte BlendFlags; + // Alpha transparency between 0 (transparent) - 255 (opaque) + public byte SourceConstantAlpha; + // Must be AC_SRC_ALPHA + public AC AlphaFormat; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct HIGHCONTRAST + { + public int cbSize; + public HCF dwFlags; + //[MarshalAs(UnmanagedType.LPWStr, SizeConst=80)] + //public String lpszDefaultScheme; + public IntPtr lpszDefaultScheme; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct RGBQUAD + { + public byte rgbBlue; + public byte rgbGreen; + public byte rgbRed; + public byte rgbReserved; + } + + [StructLayout(LayoutKind.Sequential, Pack=2)] + internal struct BITMAPINFOHEADER + { + public int biSize; + public int biWidth; + public int biHeight; + public short biPlanes; + public short biBitCount; + public BI biCompression; + public int biSizeImage; + public int biXPelsPerMeter; + public int biYPelsPerMeter; + public int biClrUsed; + public int biClrImportant; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct BITMAPINFO + { + public BITMAPINFOHEADER bmiHeader; + public RGBQUAD bmiColors; + } + + // Win7 only. + [StructLayout(LayoutKind.Sequential)] + internal struct CHANGEFILTERSTRUCT + { + public uint cbSize; + public MSGFLTINFO ExtStatus; + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + internal struct CREATESTRUCT + { + public IntPtr lpCreateParams; + public IntPtr hInstance; + public IntPtr hMenu; + public IntPtr hwndParent; + public int cy; + public int cx; + public int y; + public int x; + public WS style; + [MarshalAs(UnmanagedType.LPWStr)] public string lpszName; + [MarshalAs(UnmanagedType.LPWStr)] public string lpszClass; + public WS_EX dwExStyle; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Pack = 1)] + internal struct SHFILEOPSTRUCT + { + public IntPtr hwnd; + [MarshalAs(UnmanagedType.U4)] + public FO wFunc; + // double-null terminated arrays of LPWSTRS + public string pFrom; + public string pTo; + [MarshalAs(UnmanagedType.U2)] + public FOF fFlags; + [MarshalAs(UnmanagedType.Bool)] + public int fAnyOperationsAborted; + public IntPtr hNameMappings; + public string lpszProgressTitle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct TITLEBARINFO + { + public int cbSize; + public RECT rcTitleBar; + public STATE_SYSTEM rgstate_TitleBar; + public STATE_SYSTEM rgstate_Reserved; + public STATE_SYSTEM rgstate_MinimizeButton; + public STATE_SYSTEM rgstate_MaximizeButton; + public STATE_SYSTEM rgstate_HelpButton; + public STATE_SYSTEM rgstate_CloseButton; + } + + // New to Vista. + [StructLayout(LayoutKind.Sequential)] + internal struct TITLEBARINFOEX + { + public int cbSize; + public RECT rcTitleBar; + public STATE_SYSTEM rgstate_TitleBar; + public STATE_SYSTEM rgstate_Reserved; + public STATE_SYSTEM rgstate_MinimizeButton; + public STATE_SYSTEM rgstate_MaximizeButton; + public STATE_SYSTEM rgstate_HelpButton; + public STATE_SYSTEM rgstate_CloseButton; + public RECT rgrect_TitleBar; + public RECT rgrect_Reserved; + public RECT rgrect_MinimizeButton; + public RECT rgrect_MaximizeButton; + public RECT rgrect_HelpButton; + public RECT rgrect_CloseButton; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential)] + internal class NOTIFYICONDATA + { + public int cbSize; + public IntPtr hWnd; + public int uID; + public NIF uFlags; + public int uCallbackMessage; + public IntPtr hIcon; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 128)] + public char[] szTip = new char[128]; + /// + /// The state of the icon. There are two flags that can be set independently. + /// NIS_HIDDEN = 1. The icon is hidden. + /// NIS_SHAREDICON = 2. The icon is shared. + /// + public uint dwState; + public uint dwStateMask; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] + public char[] szInfo = new char[256]; + // Prior to Vista this was a union of uTimeout and uVersion. As of Vista, uTimeout has been deprecated. + public uint uVersion; // Used with Shell_NotifyIcon flag NIM_SETVERSION. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 64)] + public char[] szInfoTitle = new char[64]; + public uint dwInfoFlags; + public Guid guidItem; + // Vista only + IntPtr hBalloonIcon; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Explicit)] + internal class PROPVARIANT : IDisposable + { + private static class NativeMethods + { + [DllImport("ole32.dll")] + internal static extern HRESULT PropVariantClear(PROPVARIANT pvar); + } + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(0)] + private ushort vt; + [SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")] + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(8)] + private IntPtr pointerVal; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(8)] + private byte byteVal; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(8)] + private long longVal; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + [FieldOffset(8)] + private short boolVal; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public VarEnum VarType + { + get { return (VarEnum)vt; } + } + + // Right now only using this for strings. + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public string GetValue() + { + if (vt == (ushort)VarEnum.VT_LPWSTR) + { + return Marshal.PtrToStringUni(pointerVal); + } + + return null; + } + + public void SetValue(bool f) + { + Clear(); + vt = (ushort)VarEnum.VT_BOOL; + boolVal = (short)(f ? -1 : 0); + } + + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void SetValue(string val) + { + Clear(); + vt = (ushort)VarEnum.VT_LPWSTR; + pointerVal = Marshal.StringToCoTaskMemUni(val); + } + + public void Clear() + { + HRESULT hr = NativeMethods.PropVariantClear(this); + Assert.IsTrue(hr.Succeeded); + } + + #region IDisposable Pattern + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + ~PROPVARIANT() + { + Dispose(false); + } + + [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disposing")] + private void Dispose(bool disposing) + { + Clear(); + } + + #endregion + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal class SHARDAPPIDINFO + { + [MarshalAs(UnmanagedType.Interface)] + object psi; // The namespace location of the the item that should be added to the recent docs folder. + [MarshalAs(UnmanagedType.LPWStr)] + string pszAppID; // The id of the application that should be associated with this recent doc. + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal class SHARDAPPIDINFOIDLIST + { + /// The idlist for the shell item that should be added to the recent docs folder. + IntPtr pidl; + /// The id of the application that should be associated with this recent doc. + [MarshalAs(UnmanagedType.LPWStr)] + string pszAppID; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal class SHARDAPPIDINFOLINK + { + IntPtr psl; // An IShellLink instance that when launched opens a recently used item in the specified + // application. This link is not added to the recent docs folder, but will be added to the + // specified application's destination list. + [MarshalAs(UnmanagedType.LPWStr)] + string pszAppID; // The id of the application that should be associated with this recent doc. + } + + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + internal struct LOGFONT + { + public int lfHeight; + public int lfWidth; + public int lfEscapement; + public int lfOrientation; + public int lfWeight; + public byte lfItalic; + public byte lfUnderline; + public byte lfStrikeOut; + public byte lfCharSet; + public byte lfOutPrecision; + public byte lfClipPrecision; + public byte lfQuality; + public byte lfPitchAndFamily; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string lfFaceName; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MINMAXINFO + { + public POINT ptReserved; + public POINT ptMaxSize; + public POINT ptMaxPosition; + public POINT ptMinTrackSize; + public POINT ptMaxTrackSize; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NONCLIENTMETRICS + { + public int cbSize; + public int iBorderWidth; + public int iScrollWidth; + public int iScrollHeight; + public int iCaptionWidth; + public int iCaptionHeight; + public LOGFONT lfCaptionFont; + public int iSmCaptionWidth; + public int iSmCaptionHeight; + public LOGFONT lfSmCaptionFont; + public int iMenuWidth; + public int iMenuHeight; + public LOGFONT lfMenuFont; + public LOGFONT lfStatusFont; + public LOGFONT lfMessageFont; + // Vista only + public int iPaddedBorderWidth; + + public static NONCLIENTMETRICS VistaMetricsStruct + { + get + { + var ncm = new NONCLIENTMETRICS(); + ncm.cbSize = Marshal.SizeOf(typeof(NONCLIENTMETRICS)); + return ncm; + } + } + + public static NONCLIENTMETRICS XPMetricsStruct + { + get + { + var ncm = new NONCLIENTMETRICS(); + // Account for the missing iPaddedBorderWidth + ncm.cbSize = Marshal.SizeOf(typeof(NONCLIENTMETRICS)) - sizeof(int); + return ncm; + } + } + } + + /// Defines options that are used to set window visual style attributes. + [StructLayout(LayoutKind.Explicit)] + internal struct WTA_OPTIONS + { + // public static readonly uint Size = (uint)Marshal.SizeOf(typeof(WTA_OPTIONS)); + public const uint Size = 8; + + /// + /// A combination of flags that modify window visual style attributes. + /// Can be a combination of the WTNCA constants. + /// + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Used by native code.")] + [FieldOffset(0)] + public WTNCA dwFlags; + + /// + /// A bitmask that describes how the values specified in dwFlags should be applied. + /// If the bit corresponding to a value in dwFlags is 0, that flag will be removed. + /// If the bit is 1, the flag will be added. + /// + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields", Justification = "Used by native code.")] + [FieldOffset(4)] + public WTNCA dwMask; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MARGINS + { + /// Width of left border that retains its size. + public int cxLeftWidth; + /// Width of right border that retains its size. + public int cxRightWidth; + /// Height of top border that retains its size. + public int cyTopHeight; + /// Height of bottom border that retains its size. + public int cyBottomHeight; + }; + + [StructLayout(LayoutKind.Sequential)] + internal class MONITORINFO + { + public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); + public RECT rcMonitor; + public RECT rcWork; + public int dwFlags; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct POINT + { + public int x; + public int y; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential)] + internal class RefPOINT + { + public int x; + public int y; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct RECT + { + private int _left; + private int _top; + private int _right; + private int _bottom; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void Offset(int dx, int dy) + { + _left += dx; + _top += dy; + _right += dx; + _bottom += dy; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Left + { + get { return _left; } + set { _left = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Right + { + get { return _right; } + set { _right = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Top + { + get { return _top; } + set { _top = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Bottom + { + get { return _bottom; } + set { _bottom = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Width + { + get { return _right - _left; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Height + { + get { return _bottom - _top; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public POINT Position + { + get { return new POINT { x = _left, y = _top }; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public SIZE Size + { + get { return new SIZE { cx = Width, cy = Height }; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static RECT Union(RECT rect1, RECT rect2) + { + return new RECT + { + Left = Math.Min(rect1.Left, rect2.Left), + Top = Math.Min(rect1.Top, rect2.Top), + Right = Math.Max(rect1.Right, rect2.Right), + Bottom = Math.Max(rect1.Bottom, rect2.Bottom), + }; + } + + public override bool Equals(object obj) + { + try + { + var rc = (RECT)obj; + return rc._bottom == _bottom + && rc._left == _left + && rc._right == _right + && rc._top == _top; + } + catch (InvalidCastException) + { + return false; + } + } + + public override int GetHashCode() + { + return (_left << 16 | Utility.LOWORD(_right)) ^ (_top << 16 | Utility.LOWORD(_bottom)); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential)] + internal class RefRECT + { + private int _left; + private int _top; + private int _right; + private int _bottom; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public RefRECT(int left, int top, int right, int bottom) + { + _left = left; + _top = top; + _right = right; + _bottom = bottom; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Width + { + get { return _right - _left; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Height + { + get { return _bottom - _top; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Left + { + get { return _left; } + set { _left = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Right + { + get { return _right; } + set { _right = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Top + { + get { return _top; } + set { _top = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public int Bottom + { + get { return _bottom; } + set { _bottom = value; } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public void Offset(int dx, int dy) + { + _left += dx; + _top += dy; + _right += dx; + _bottom += dy; + } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SIZE + { + public int cx; + public int cy; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct StartupOutput + { + public IntPtr hook; + public IntPtr unhook; + } + + [StructLayout(LayoutKind.Sequential)] + internal class StartupInput + { + public int GdiplusVersion = 1; + public IntPtr DebugEventCallback; + public bool SuppressBackgroundThread; + public bool SuppressExternalCodecs; + } + + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + [BestFitMapping(false)] + internal class WIN32_FIND_DATAW + { + public FileAttributes dwFileAttributes; + public System.Runtime.InteropServices.ComTypes.FILETIME ftCreationTime; + public System.Runtime.InteropServices.ComTypes.FILETIME ftLastAccessTime; + public System.Runtime.InteropServices.ComTypes.FILETIME ftLastWriteTime; + public int nFileSizeHigh; + public int nFileSizeLow; + public int dwReserved0; + public int dwReserved1; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string cFileName; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] + public string cAlternateFileName; + } + + [StructLayout(LayoutKind.Sequential)] + internal class WINDOWPLACEMENT + { + public int length = Marshal.SizeOf(typeof(WINDOWPLACEMENT)); + public int flags; + public SW showCmd; + public POINT ptMinPosition; + public POINT ptMaxPosition; + public RECT rcNormalPosition; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct WINDOWPOS + { + public IntPtr hwnd; + public IntPtr hwndInsertAfter; + public int x; + public int y; + public int cx; + public int cy; + public int flags; + } + + [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)] + internal struct WNDCLASSEX + { + public int cbSize; + public CS style; + public WndProc lpfnWndProc; + public int cbClsExtra; + public int cbWndExtra; + public IntPtr hInstance; + public IntPtr hIcon; + public IntPtr hCursor; + public IntPtr hbrBackground; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpszMenuName; + [MarshalAs(UnmanagedType.LPWStr)] + public string lpszClassName; + public IntPtr hIconSm; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MOUSEINPUT + { + public int dx; + public int dy; + public int mouseData; + public int dwFlags; + public int time; + public IntPtr dwExtraInfo; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct INPUT + { + public uint type; + public MOUSEINPUT mi; + }; + + [StructLayout(LayoutKind.Sequential)] + internal struct UNSIGNED_RATIO + { + public uint uiNumerator; + public uint uiDenominator; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct DWM_TIMING_INFO + { + public int cbSize; + public UNSIGNED_RATIO rateRefresh; + public ulong qpcRefreshPeriod; + public UNSIGNED_RATIO rateCompose; + public ulong qpcVBlank; + public ulong cRefresh; + public uint cDXRefresh; + public ulong qpcCompose; + public ulong cFrame; + public uint cDXPresent; + public ulong cRefreshFrame; + public ulong cFrameSubmitted; + public uint cDXPresentSubmitted; + public ulong cFrameConfirmed; + public uint cDXPresentConfirmed; + public ulong cRefreshConfirmed; + public uint cDXRefreshConfirmed; + public ulong cFramesLate; + public uint cFramesOutstanding; + public ulong cFrameDisplayed; + public ulong qpcFrameDisplayed; + public ulong cRefreshFrameDisplayed; + public ulong cFrameComplete; + public ulong qpcFrameComplete; + public ulong cFramePending; + public ulong qpcFramePending; + public ulong cFramesDisplayed; + public ulong cFramesComplete; + public ulong cFramesPending; + public ulong cFramesAvailable; + public ulong cFramesDropped; + public ulong cFramesMissed; + public ulong cRefreshNextDisplayed; + public ulong cRefreshNextPresented; + public ulong cRefreshesDisplayed; + public ulong cRefreshesPresented; + public ulong cRefreshStarted; + public ulong cPixelsReceived; + public ulong cPixelsDrawn; + public ulong cBuffersEmpty; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SHDRAGIMAGE + { + public SIZE sizeDragImage; + public POINT ptOffset; + public IntPtr hbmpDragImage; + public int crColorKey; + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode, Size = 1044)] + internal struct DROPDESCRIPTION + { + public DROPIMAGETYPE type; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string szMessage; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string szInsert; + } + + #endregion + + #region Interfaces + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ServiceProvider) + ] + internal interface IServiceProvider + { + [return: MarshalAs(UnmanagedType.IUnknown)] + object QueryService(ref Guid guidService, ref Guid riid); + } + + [ + ComImport, + Guid(IID.DragSourceHelper), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown) + ] + internal interface IDragSourceHelper + { + void InitializeFromBitmap([In] ref SHDRAGIMAGE pshdi, [In] IDataObject pDataObject); + void InitializeFromWindow(IntPtr hwnd, [In] ref POINT ppt, [In] IDataObject pDataObject); + } + + [ + ComImport, + Guid(IID.DragSourceHelper2), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown) + ] + internal interface IDragSourceHelper2 : IDragSourceHelper + { + #region IDragSourceHelper redeclaration + new void InitializeFromBitmap([In] ref SHDRAGIMAGE pshdi, [In] IDataObject pDataObject); + new void InitializeFromWindow(IntPtr hwnd, [In] ref POINT ppt, [In] IDataObject pDataObject); + #endregion + + void SetFlags(DSH dwFlags); + } + + [ + ComImport, + Guid(IID.DropTargetHelper), + InterfaceType(ComInterfaceType.InterfaceIsIUnknown) + ] + internal interface IDropTargetHelper + { + void DragEnter(IntPtr hwndTarget, IDataObject pDataObject, ref POINT ppt, int effect); + void DragLeave(); + void DragOver(ref POINT ppt, int effect); + void Drop(IDataObject dataObject, ref POINT ppt, int effect); + void Show([MarshalAs(UnmanagedType.Bool)] bool fShow); + } + + #endregion + + /// Delegate declaration that matches native WndProc signatures. + internal delegate IntPtr WndProc(IntPtr hwnd, WM uMsg, IntPtr wParam, IntPtr lParam); + + /// Delegate declaration that matches managed WndProc signatures. + internal delegate IntPtr MessageHandler(WM uMsg, IntPtr wParam, IntPtr lParam, out bool handled); + + // Some native methods are shimmed through public versions that handle converting failures into thrown exceptions. + internal static class NativeMethods + { + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "AdjustWindowRectEx", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _AdjustWindowRectEx(ref RECT lpRect, WS dwStyle, [MarshalAs(UnmanagedType.Bool)] bool bMenu, WS_EX dwExStyle); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static RECT AdjustWindowRectEx(RECT lpRect, WS dwStyle, bool bMenu, WS_EX dwExStyle) + { + // Native version modifies the parameter in place. + if (!_AdjustWindowRectEx(ref lpRect, dwStyle, bMenu, dwExStyle)) + { + HRESULT.ThrowLastError(); + } + + return lpRect; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "AllowSetForegroundWindow", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _AllowSetForegroundWindow(int dwProcessId); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void AllowSetForegroundWindow() + { + int ASFW_ANY = -1; + AllowSetForegroundWindow(ASFW_ANY); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void AllowSetForegroundWindow(int dwProcessId) + { + if (!_AllowSetForegroundWindow(dwProcessId)) + { + HRESULT.ThrowLastError(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "ChangeWindowMessageFilter", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _ChangeWindowMessageFilter(WM message, MSGFLT dwFlag); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "ChangeWindowMessageFilterEx", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _ChangeWindowMessageFilterEx(IntPtr hwnd, WM message, MSGFLT action, [In, Out, Optional] ref CHANGEFILTERSTRUCT pChangeFilterStruct); + + // Note that processes at or below SECURITY_MANDATORY_LOW_RID are not allowed to change the message filter. + // If those processes call this function, it will fail and generate the extended error code, ERROR_ACCESS_DENIED. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static HRESULT ChangeWindowMessageFilterEx(IntPtr hwnd, WM message, MSGFLT action, out MSGFLTINFO filterInfo) + { + filterInfo = MSGFLTINFO.NONE; + + bool ret; + + // This origins of this API were added for Vista. The Ex version was added for Windows 7. + // If we're not on either, then this message filter isolation doesn't exist. + if (!Utility.IsOSVistaOrNewer) + { + return HRESULT.S_FALSE; + } + + // If we're on Vista rather than Win7 then we can't use the Ex version of this function. + // The Ex version is preferred if possible because this results in process-wide modifications of the filter + // and is deprecated as of Win7. + if (!Utility.IsOSWindows7OrNewer) + { + // Note that the Win7 MSGFLT_ALLOW/DISALLOW enum values map to the Vista MSGFLT_ADD/REMOVE + ret = _ChangeWindowMessageFilter(message, action); + if (!ret) + { + return (HRESULT)Win32Error.GetLastError(); + } + return HRESULT.S_OK; + } + + var filterstruct = new CHANGEFILTERSTRUCT { cbSize = (uint)Marshal.SizeOf(typeof(CHANGEFILTERSTRUCT)) }; + ret = _ChangeWindowMessageFilterEx(hwnd, message, action, ref filterstruct); + if (!ret) + { + return (HRESULT)Win32Error.GetLastError(); + } + + filterInfo = filterstruct.ExtStatus; + return HRESULT.S_OK; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + public static extern CombineRgnResult CombineRgn(IntPtr hrgnDest, IntPtr hrgnSrc1, IntPtr hrgnSrc2, RGN fnCombineMode); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", EntryPoint = "CommandLineToArgvW", CharSet = CharSet.Unicode)] + private static extern IntPtr _CommandLineToArgvW([MarshalAs(UnmanagedType.LPWStr)] string cmdLine, out int numArgs); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string[] CommandLineToArgvW(string cmdLine) + { + IntPtr argv = IntPtr.Zero; + try + { + int numArgs = 0; + + argv = _CommandLineToArgvW(cmdLine, out numArgs); + if (argv == IntPtr.Zero) + { + throw new Win32Exception(); + } + var result = new string[numArgs]; + + for (int i = 0; i < numArgs; i++) + { + IntPtr currArg = Marshal.ReadIntPtr(argv, i * Marshal.SizeOf(typeof(IntPtr))); + result[i] = Marshal.PtrToStringUni(currArg); + } + + return result; + } + finally + { + + IntPtr p = _LocalFree(argv); + // Otherwise LocalFree failed. + Assert.AreEqual(IntPtr.Zero, p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateDIBSection", SetLastError = true)] + private static extern SafeHBITMAP _CreateDIBSection(SafeDC hdc, [In] ref BITMAPINFO bitmapInfo, int iUsage, [Out] out IntPtr ppvBits, IntPtr hSection, int dwOffset); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateDIBSection", SetLastError = true)] + private static extern SafeHBITMAP _CreateDIBSectionIntPtr(IntPtr hdc, [In] ref BITMAPINFO bitmapInfo, int iUsage, [Out] out IntPtr ppvBits, IntPtr hSection, int dwOffset); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static SafeHBITMAP CreateDIBSection(SafeDC hdc, ref BITMAPINFO bitmapInfo, out IntPtr ppvBits, IntPtr hSection, int dwOffset) + { + const int DIB_RGB_COLORS = 0; + SafeHBITMAP hBitmap = null; + if (hdc == null) + { + hBitmap = _CreateDIBSectionIntPtr(IntPtr.Zero, ref bitmapInfo, DIB_RGB_COLORS, out ppvBits, hSection, dwOffset); + } + else + { + hBitmap = _CreateDIBSection(hdc, ref bitmapInfo, DIB_RGB_COLORS, out ppvBits, hSection, dwOffset); + } + + if (hBitmap.IsInvalid) + { + HRESULT.ThrowLastError(); + } + + return hBitmap; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateRoundRectRgn", SetLastError = true)] + private static extern IntPtr _CreateRoundRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nWidthEllipse, int nHeightEllipse); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr CreateRoundRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect, int nWidthEllipse, int nHeightEllipse) + { + IntPtr ret = _CreateRoundRectRgn(nLeftRect, nTopRect, nRightRect, nBottomRect, nWidthEllipse, nHeightEllipse); + if (IntPtr.Zero == ret) + { + throw new Win32Exception(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateRectRgn", SetLastError = true)] + private static extern IntPtr _CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect) + { + IntPtr ret = _CreateRectRgn(nLeftRect, nTopRect, nRightRect, nBottomRect); + if (IntPtr.Zero == ret) + { + throw new Win32Exception(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "CreateRectRgnIndirect", SetLastError = true)] + private static extern IntPtr _CreateRectRgnIndirect([In] ref RECT lprc); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr CreateRectRgnIndirect(RECT lprc) + { + IntPtr ret = _CreateRectRgnIndirect(ref lprc); + if (IntPtr.Zero == ret) + { + throw new Win32Exception(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + public static extern IntPtr CreateSolidBrush(int crColor); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "CreateWindowExW")] + private static extern IntPtr _CreateWindowEx( + WS_EX dwExStyle, + [MarshalAs(UnmanagedType.LPWStr)] string lpClassName, + [MarshalAs(UnmanagedType.LPWStr)] string lpWindowName, + WS dwStyle, + int x, + int y, + int nWidth, + int nHeight, + IntPtr hWndParent, + IntPtr hMenu, + IntPtr hInstance, + IntPtr lpParam); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr CreateWindowEx( + WS_EX dwExStyle, + string lpClassName, + string lpWindowName, + WS dwStyle, + int x, + int y, + int nWidth, + int nHeight, + IntPtr hWndParent, + IntPtr hMenu, + IntPtr hInstance, + IntPtr lpParam) + { + IntPtr ret = _CreateWindowEx(dwExStyle, lpClassName, lpWindowName, dwStyle, x, y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + if (IntPtr.Zero == ret) + { + HRESULT.ThrowLastError(); + } + + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", CharSet = CharSet.Unicode, EntryPoint = "DefWindowProcW")] + public static extern IntPtr DefWindowProc(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DeleteObject(IntPtr hObject); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DestroyIcon(IntPtr handle); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DestroyWindow(IntPtr hwnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsWindow(IntPtr hwnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", PreserveSig = false)] + public static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS pMarInset); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", EntryPoint = "DwmGetColorizationColor", PreserveSig = true)] + private static extern HRESULT _DwmGetColorizationColor(out uint pcrColorization, [Out, MarshalAs(UnmanagedType.Bool)] out bool pfOpaqueBlend); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool DwmGetColorizationColor(out uint pcrColorization, out bool pfOpaqueBlend) + { + // Make this call safe to make on downlevel OSes... + if (Utility.IsOSVistaOrNewer && IsThemeActive()) + { + HRESULT hr = _DwmGetColorizationColor(out pcrColorization, out pfOpaqueBlend); + if (hr.Succeeded) + { + return true; + } + } + + // Default values. If for some reason the native DWM API fails it's never enough of a reason + // to bring down the app. Empirically it still sometimes returns errors even when the theme service is on. + // We'll still use the boolean return value to allow the caller to respond if they care. + pcrColorization = 0xFF000000; + pfOpaqueBlend = true; + + return false; + } + + //#define DWM_SIT_DISPLAYFRAME 0x00000001 // Display a window frame around the provided bitmap + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", EntryPoint = "DwmGetCompositionTimingInfo")] + private static extern HRESULT _DwmGetCompositionTimingInfo(IntPtr hwnd, ref DWM_TIMING_INFO pTimingInfo); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static DWM_TIMING_INFO? DwmGetCompositionTimingInfo(IntPtr hwnd) + { + if (!Utility.IsOSVistaOrNewer) + { + // API was new to Vista. + return null; + } + + var dti = new DWM_TIMING_INFO { cbSize = Marshal.SizeOf(typeof(DWM_TIMING_INFO)) }; + HRESULT hr = _DwmGetCompositionTimingInfo(hwnd, ref dti); + if (hr == HRESULT.E_PENDING) + { + // The system isn't yet ready to respond. Return null rather than throw. + return null; + } + hr.ThrowIfFailed(); + + return dti; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", EntryPoint = "DwmIsCompositionEnabled", PreserveSig = false)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _DwmIsCompositionEnabled(); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool DwmIsCompositionEnabled() + { + // Make this call safe to make on downlevel OSes... + if (!Utility.IsOSVistaOrNewer) + { + return false; + } + return _DwmIsCompositionEnabled(); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DwmDefWindowProc(IntPtr hwnd, WM msg, IntPtr wParam, IntPtr lParam, out IntPtr plResult); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", EntryPoint = "DwmSetWindowAttribute")] + private static extern void _DwmSetWindowAttribute(IntPtr hwnd, DWMWA dwAttribute, ref int pvAttribute, int cbAttribute); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void DwmSetWindowAttributeFlip3DPolicy(IntPtr hwnd, DWMFLIP3D flip3dPolicy) + { + Assert.IsTrue(Utility.IsOSVistaOrNewer); + var dwPolicy = (int)flip3dPolicy; + _DwmSetWindowAttribute(hwnd, DWMWA.FLIP3D_POLICY, ref dwPolicy, sizeof(int)); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void DwmSetWindowAttributeDisallowPeek(IntPtr hwnd, bool disallowPeek) + { + Assert.IsTrue(Utility.IsOSWindows7OrNewer); + int dwDisallow = (int)(disallowPeek ? Win32Value.TRUE : Win32Value.FALSE); + _DwmSetWindowAttribute(hwnd, DWMWA.DISALLOW_PEEK, ref dwDisallow, sizeof(int)); + } + + public static void DwmSetWindowAttributeForceIconicRepresentation(IntPtr hwnd, bool forceIconicRepresentation) + { + Assert.IsTrue(Utility.IsOSWindows7OrNewer); + int dwForce = (int)(forceIconicRepresentation ? Win32Value.TRUE : Win32Value.FALSE); + _DwmSetWindowAttribute(hwnd, DWMWA.FORCE_ICONIC_REPRESENTATION, ref dwForce, sizeof(int)); + } + + public static void DwmSetWindowAttributeHasIconicBitmap(IntPtr hwnd, bool hasIconicBitmap) + { + Assert.IsTrue(Utility.IsOSWindows7OrNewer); + int dwHasIconic = (int)(hasIconicBitmap ? Win32Value.TRUE : Win32Value.FALSE); + _DwmSetWindowAttribute(hwnd, DWMWA.FORCE_ICONIC_REPRESENTATION, ref dwHasIconic, sizeof(int)); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "EnableMenuItem")] + private static extern int _EnableMenuItem(IntPtr hMenu, SC uIDEnableItem, MF uEnable); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static MF EnableMenuItem(IntPtr hMenu, SC uIDEnableItem, MF uEnable) + { + // Returns the previous state of the menu item, or -1 if the menu item does not exist. + int iRet = _EnableMenuItem(hMenu, uIDEnableItem, uEnable); + return (MF)iRet; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "RemoveMenu", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _RemoveMenu(IntPtr hMenu, uint uPosition, uint uFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void RemoveMenu(IntPtr hMenu, SC uPosition, MF uFlags) + { + if (!_RemoveMenu(hMenu, (uint)uPosition, (uint)uFlags)) + { + throw new Win32Exception(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "DrawMenuBar", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _DrawMenuBar(IntPtr hWnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void DrawMenuBar(IntPtr hWnd) + { + if (!_DrawMenuBar(hWnd)) + { + throw new Win32Exception(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll")] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool FindClose(IntPtr handle); + + // Not shimming this SetLastError=true function because callers want to evaluate the reason for failure. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + public static extern SafeFindHandle FindFirstFileW(string lpFileName, [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_DATAW lpFindFileData); + + // Not shimming this SetLastError=true function because callers want to evaluate the reason for failure. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool FindNextFileW(SafeFindHandle hndFindFile, [In, Out, MarshalAs(UnmanagedType.LPStruct)] WIN32_FIND_DATAW lpFindFileData); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetClientRect", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _GetClientRect(IntPtr hwnd, [Out] out RECT lpRect); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static RECT GetClientRect(IntPtr hwnd) + { + RECT rc; + if (!_GetClientRect(hwnd, out rc)) + { + HRESULT.ThrowLastError(); + } + return rc; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetCursorPos", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _GetCursorPos(out POINT lpPoint); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static POINT GetCursorPos() + { + POINT pt; + if (!_GetCursorPos(out pt)) + { + HRESULT.ThrowLastError(); + } + + return pt; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("uxtheme.dll", EntryPoint = "GetCurrentThemeName", CharSet = CharSet.Unicode)] + private static extern HRESULT _GetCurrentThemeName( + StringBuilder pszThemeFileName, + int dwMaxNameChars, + StringBuilder pszColorBuff, + int cchMaxColorChars, + StringBuilder pszSizeBuff, + int cchMaxSizeChars); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void GetCurrentThemeName(out string themeFileName, out string color, out string size) + { + // Not expecting strings longer than MAX_PATH. We will return the error + var fileNameBuilder = new StringBuilder((int)Win32Value.MAX_PATH); + var colorBuilder = new StringBuilder((int)Win32Value.MAX_PATH); + var sizeBuilder = new StringBuilder((int)Win32Value.MAX_PATH); + + // This will throw if the theme service is not active (e.g. not UxTheme!IsThemeActive). + _GetCurrentThemeName(fileNameBuilder, fileNameBuilder.Capacity, + colorBuilder, colorBuilder.Capacity, + sizeBuilder, sizeBuilder.Capacity) + .ThrowIfFailed(); + + themeFileName = fileNameBuilder.ToString(); + color = colorBuilder.ToString(); + size = sizeBuilder.ToString(); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("uxtheme.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsThemeActive(); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [Obsolete("Use SafeDC.GetDC instead.", true)] + public static void GetDC() { } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll")] + public static extern int GetDeviceCaps(SafeDC hdc, DeviceCap nIndex); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", EntryPoint = "GetModuleFileName", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern int _GetModuleFileName(IntPtr hModule, StringBuilder lpFilename, int nSize); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string GetModuleFileName(IntPtr hModule) + { + var buffer = new StringBuilder((int)Win32Value.MAX_PATH); + while (true) + { + int size = _GetModuleFileName(hModule, buffer, buffer.Capacity); + if (size == 0) + { + HRESULT.ThrowLastError(); + } + + // GetModuleFileName returns nSize when it's truncated but does NOT set the last error. + // MSDN documentation says this has changed in Windows 2000+. + if (size == buffer.Capacity) + { + // Enlarge the buffer and try again. + buffer.EnsureCapacity(buffer.Capacity * 2); + continue; + } + + return buffer.ToString(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", EntryPoint = "GetModuleHandleW", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern IntPtr _GetModuleHandle([MarshalAs(UnmanagedType.LPWStr)] string lpModuleName); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr GetModuleHandle(string lpModuleName) + { + IntPtr retPtr = _GetModuleHandle(lpModuleName); + if (retPtr == IntPtr.Zero) + { + HRESULT.ThrowLastError(); + } + return retPtr; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetMonitorInfo", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _GetMonitorInfo(IntPtr hMonitor, [In, Out] MONITORINFO lpmi); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static MONITORINFO GetMonitorInfo(IntPtr hMonitor) + { + var mi = new MONITORINFO(); + if (!_GetMonitorInfo(hMonitor, mi)) + { + throw new Win32Exception(); + } + return mi; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "GetStockObject", SetLastError = true)] + private static extern IntPtr _GetStockObject(StockObject fnObject); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr GetStockObject(StockObject fnObject) + { + IntPtr retPtr = _GetStockObject(fnObject); + if (retPtr == null) + { + HRESULT.ThrowLastError(); + } + return retPtr; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern IntPtr GetSystemMenu(IntPtr hWnd, [MarshalAs(UnmanagedType.Bool)] bool bRevert); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern int GetSystemMetrics(SM nIndex); + + // This is aliased as a macro in 32bit Windows. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr GetWindowLongPtr(IntPtr hwnd, GWL nIndex) + { + IntPtr ret = IntPtr.Zero; + if (8 == IntPtr.Size) + { + ret = GetWindowLongPtr64(hwnd, nIndex); + } + else + { + ret = new IntPtr(GetWindowLongPtr32(hwnd, nIndex)); + } + if (IntPtr.Zero == ret) + { + throw new Win32Exception(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint="SetProp", CharSet=CharSet.Unicode, SetLastError=true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SetProp(IntPtr hWnd, [MarshalAs(UnmanagedType.LPWStr)] string lpString, IntPtr hData); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SetProp(IntPtr hwnd, string lpString, IntPtr hData) + { + if (!_SetProp(hwnd, lpString, hData)) + { + HRESULT.ThrowLastError(); + } + } + + /// + /// Sets attributes to control how visual styles are applied to a specified window. + /// + /// + /// Handle to a window to apply changes to. + /// + /// + /// Value of type WINDOWTHEMEATTRIBUTETYPE that specifies the type of attribute to set. + /// The value of this parameter determines the type of data that should be passed in the pvAttribute parameter. + /// Can be the following value: + /// WTA_NONCLIENT (Specifies non-client related attributes). + /// pvAttribute must be a pointer of type WTA_OPTIONS. + /// + /// + /// A pointer that specifies attributes to set. Type is determined by the value of the eAttribute value. + /// + /// + /// Specifies the size, in bytes, of the data pointed to by pvAttribute. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("uxtheme.dll", PreserveSig = false)] + public static extern void SetWindowThemeAttribute([In] IntPtr hwnd, [In] WINDOWTHEMEATTRIBUTETYPE eAttribute, [In] ref WTA_OPTIONS pvAttribute, [In] uint cbAttribute); + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetWindowLong", SetLastError = true)] + private static extern int GetWindowLongPtr32(IntPtr hWnd, GWL nIndex); + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetWindowLongPtr", SetLastError = true)] + private static extern IntPtr GetWindowLongPtr64(IntPtr hWnd, GWL nIndex); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool GetWindowPlacement(IntPtr hwnd, WINDOWPLACEMENT lpwndpl); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static WINDOWPLACEMENT GetWindowPlacement(IntPtr hwnd) + { + WINDOWPLACEMENT wndpl = new WINDOWPLACEMENT(); + if (GetWindowPlacement(hwnd, wndpl)) + { + return wndpl; + } + throw new Win32Exception(); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "GetWindowRect", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _GetWindowRect(IntPtr hWnd, out RECT lpRect); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static RECT GetWindowRect(IntPtr hwnd) + { + RECT rc; + if (!_GetWindowRect(hwnd, out rc)) + { + HRESULT.ThrowLastError(); + } + return rc; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipCreateBitmapFromStream(IStream stream, out IntPtr bitmap); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipCreateHBITMAPFromBitmap(IntPtr bitmap, out IntPtr hbmReturn, Int32 background); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipCreateHICONFromBitmap(IntPtr bitmap, out IntPtr hbmReturn); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipDisposeImage(IntPtr image); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdipImageForceValidation(IntPtr image); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdiplusStartup(out IntPtr token, StartupInput input, out StartupOutput output); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdiplus.dll")] + public static extern Status GdiplusShutdown(IntPtr token); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool IsWindowVisible(IntPtr hwnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", EntryPoint = "LocalFree", SetLastError = true)] + private static extern IntPtr _LocalFree(IntPtr hMem); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "PostMessage", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _PostMessage(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void PostMessage(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam) + { + if (!_PostMessage(hWnd, Msg, wParam, lParam)) + { + throw new Win32Exception(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClassExW")] + private static extern short _RegisterClassEx([In] ref WNDCLASSEX lpwcx); + + // Note that this will throw HRESULT_FROM_WIN32(ERROR_CLASS_ALREADY_EXISTS) on duplicate registration. + // If needed, consider adding a Try* version of this function that returns the error code since that + // may be ignorable. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static short RegisterClassEx(ref WNDCLASSEX lpwcx) + { + short ret = _RegisterClassEx(ref lpwcx); + if (ret == 0) + { + HRESULT.ThrowLastError(); + } + + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "RegisterWindowMessage", SetLastError = true, CharSet = CharSet.Unicode)] + private static extern uint _RegisterWindowMessage([MarshalAs(UnmanagedType.LPWStr)] string lpString); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static WM RegisterWindowMessage(string lpString) + { + uint iRet = _RegisterWindowMessage(lpString); + if (iRet == 0) + { + HRESULT.ThrowLastError(); + } + return (WM)iRet; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetActiveWindow", SetLastError = true)] + private static extern IntPtr _SetActiveWindow(IntPtr hWnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SetActiveWindow(IntPtr hwnd) + { + Verify.IsNotDefault(hwnd, "hwnd"); + IntPtr ret = _SetActiveWindow(hwnd); + if (ret == IntPtr.Zero) + { + HRESULT.ThrowLastError(); + } + + return ret; + } + + // This is aliased as a macro in 32bit Windows. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SetClassLongPtr(IntPtr hwnd, GCLP nIndex, IntPtr dwNewLong) + { + if (8 == IntPtr.Size) + { + return SetClassLongPtr64(hwnd, nIndex, dwNewLong); + } + return new IntPtr(SetClassLongPtr32(hwnd, nIndex, dwNewLong.ToInt32())); + } + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetClassLong", SetLastError = true)] + private static extern int SetClassLongPtr32(IntPtr hWnd, GCLP nIndex, int dwNewLong); + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetClassLongPtr", SetLastError = true)] + private static extern IntPtr SetClassLongPtr64(IntPtr hWnd, GCLP nIndex, IntPtr dwNewLong); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", SetLastError = true)] + public static extern ErrorModes SetErrorMode(ErrorModes newMode); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("kernel32.dll", SetLastError = true, EntryPoint = "SetProcessWorkingSetSize")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SetProcessWorkingSetSize(IntPtr hProcess, IntPtr dwMinimiumWorkingSetSize, IntPtr dwMaximumWorkingSetSize); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SetProcessWorkingSetSize(IntPtr hProcess, int dwMinimumWorkingSetSize, int dwMaximumWorkingSetSize) + { + if (!_SetProcessWorkingSetSize(hProcess, new IntPtr(dwMinimumWorkingSetSize), new IntPtr(dwMaximumWorkingSetSize))) + { + throw new Win32Exception(); + } + } + + // This is aliased as a macro in 32bit Windows. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SetWindowLongPtr(IntPtr hwnd, GWL nIndex, IntPtr dwNewLong) + { + if (8 == IntPtr.Size) + { + return SetWindowLongPtr64(hwnd, nIndex, dwNewLong); + } + return new IntPtr(SetWindowLongPtr32(hwnd, nIndex, dwNewLong.ToInt32())); + } + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetWindowLong", SetLastError = true)] + private static extern int SetWindowLongPtr32(IntPtr hWnd, GWL nIndex, int dwNewLong); + + [SuppressMessage("Microsoft.Interoperability", "CA1400:PInvokeEntryPointsShouldExist")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetWindowLongPtr", SetLastError = true)] + private static extern IntPtr SetWindowLongPtr64(IntPtr hWnd, GWL nIndex, IntPtr dwNewLong); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetWindowRgn", SetLastError = true)] + private static extern int _SetWindowRgn(IntPtr hWnd, IntPtr hRgn, [MarshalAs(UnmanagedType.Bool)] bool bRedraw); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SetWindowRgn(IntPtr hWnd, IntPtr hRgn, bool bRedraw) + { + int err = _SetWindowRgn(hWnd, hRgn, bRedraw); + if (0 == err) + { + throw new Win32Exception(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SetWindowPos", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, SWP uFlags) + { + if (!_SetWindowPos(hWnd, hWndInsertAfter, x, y, cx, cy, uFlags)) + { + throw new Win32Exception(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", SetLastError = false)] + public static extern Win32Error SHFileOperation(ref SHFILEOPSTRUCT lpFileOp); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SystemParametersInfoW", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SystemParametersInfo_String(SPI uiAction, int uiParam, [MarshalAs(UnmanagedType.LPWStr)] string pvParam, SPIF fWinIni); + + /// Overload of SystemParametersInfo for getting and setting NONCLIENTMETRICS. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SystemParametersInfoW", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SystemParametersInfo_NONCLIENTMETRICS(SPI uiAction, int uiParam, [In, Out] ref NONCLIENTMETRICS pvParam, SPIF fWinIni); + + /// Overload of SystemParametersInfo for getting and setting HIGHCONTRAST. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "SystemParametersInfoW", SetLastError = true, CharSet = CharSet.Unicode)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _SystemParametersInfo_HIGHCONTRAST(SPI uiAction, int uiParam, [In, Out] ref HIGHCONTRAST pvParam, SPIF fWinIni); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SystemParametersInfo(SPI uiAction, int uiParam, string pvParam, SPIF fWinIni) + { + if (!_SystemParametersInfo_String(uiAction, uiParam, pvParam, fWinIni)) + { + HRESULT.ThrowLastError(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static NONCLIENTMETRICS SystemParameterInfo_GetNONCLIENTMETRICS() + { + var metrics = Utility.IsOSVistaOrNewer + ? NONCLIENTMETRICS.VistaMetricsStruct + : NONCLIENTMETRICS.XPMetricsStruct; + + if (!_SystemParametersInfo_NONCLIENTMETRICS(SPI.GETNONCLIENTMETRICS, metrics.cbSize, ref metrics, SPIF.None)) + { + HRESULT.ThrowLastError(); + } + + return metrics; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static HIGHCONTRAST SystemParameterInfo_GetHIGHCONTRAST() + { + var hc = new HIGHCONTRAST { cbSize = Marshal.SizeOf(typeof(HIGHCONTRAST)) }; + + if (!_SystemParametersInfo_HIGHCONTRAST(SPI.GETHIGHCONTRAST, hc.cbSize, ref hc, SPIF.None)) + { + HRESULT.ThrowLastError(); + } + + return hc; + } + + // This function is strange in that it returns a BOOL if TPM_RETURNCMD isn't specified, but otherwise the command Id. + // Currently it's only used with TPM_RETURNCMD, so making the signature match that. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + public static extern uint TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, int x, int y, IntPtr hwnd, IntPtr lptpm); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "SelectObject", SetLastError = true)] + private static extern IntPtr _SelectObject(SafeDC hdc, IntPtr hgdiobj); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SelectObject(SafeDC hdc, IntPtr hgdiobj) + { + IntPtr ret = _SelectObject(hdc, hgdiobj); + if (ret == IntPtr.Zero) + { + HRESULT.ThrowLastError(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("gdi32.dll", EntryPoint = "SelectObject", SetLastError = true)] + private static extern IntPtr _SelectObjectSafeHBITMAP(SafeDC hdc, SafeHBITMAP hgdiobj); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr SelectObject(SafeDC hdc, SafeHBITMAP hgdiobj) + { + IntPtr ret = _SelectObjectSafeHBITMAP(hdc, hgdiobj); + if (ret == IntPtr.Zero) + { + HRESULT.ThrowLastError(); + } + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true)] + public static extern int SendInput(int nInputs, ref INPUT pInputs, int cbSize); + + // Depending on the message, callers may want to call GetLastError based on the return value. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true)] + public static extern IntPtr SendMessage(IntPtr hWnd, WM Msg, IntPtr wParam, IntPtr lParam); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool ShowWindow(IntPtr hwnd, SW nCmdShow); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "UnregisterClass", SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _UnregisterClassAtom(IntPtr lpClassName, IntPtr hInstance); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", EntryPoint = "UnregisterClass", CharSet = CharSet.Unicode, SetLastError = true)] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _UnregisterClassName(string lpClassName, IntPtr hInstance); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void UnregisterClass(short atom, IntPtr hinstance) + { + if (!_UnregisterClassAtom(new IntPtr(atom), hinstance)) + { + HRESULT.ThrowLastError(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void UnregisterClass(string lpClassName, IntPtr hInstance) + { + if (!_UnregisterClassName(lpClassName, hInstance)) + { + HRESULT.ThrowLastError(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "UpdateLayeredWindow")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _UpdateLayeredWindow( + IntPtr hwnd, + SafeDC hdcDst, + [In] ref POINT pptDst, + [In] ref SIZE psize, + SafeDC hdcSrc, + [In] ref POINT pptSrc, + int crKey, + ref BLENDFUNCTION pblend, + ULW dwFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "UpdateLayeredWindow")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool _UpdateLayeredWindowIntPtr( + IntPtr hwnd, + IntPtr hdcDst, + IntPtr pptDst, + IntPtr psize, + IntPtr hdcSrc, + IntPtr pptSrc, + int crKey, + ref BLENDFUNCTION pblend, + ULW dwFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void UpdateLayeredWindow( + IntPtr hwnd, + SafeDC hdcDst, + ref POINT pptDst, + ref SIZE psize, + SafeDC hdcSrc, + ref POINT pptSrc, + int crKey, + ref BLENDFUNCTION pblend, + ULW dwFlags) + { + if (!_UpdateLayeredWindow(hwnd, hdcDst, ref pptDst, ref psize, hdcSrc, ref pptSrc, crKey, ref pblend, dwFlags)) + { + HRESULT.ThrowLastError(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void UpdateLayeredWindow( + IntPtr hwnd, + int crKey, + ref BLENDFUNCTION pblend, + ULW dwFlags) + { + if (!_UpdateLayeredWindowIntPtr(hwnd, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, crKey, ref pblend, dwFlags)) + { + HRESULT.ThrowLastError(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll", SetLastError = true, EntryPoint = "RegisterClipboardFormatW", CharSet = CharSet.Unicode)] + private static extern uint _RegisterClipboardFormat(string lpszFormatName); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static uint RegisterClipboardFormat(string formatName) + { + uint ret = _RegisterClipboardFormat(formatName); + if (ret == 0) + { + HRESULT.ThrowLastError(); + } + + return ret; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("ole32.dll")] + public static extern void ReleaseStgMedium(ref STGMEDIUM pmedium); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("ole32.dll")] + public static extern HRESULT CreateStreamOnHGlobal(IntPtr hGlobal, [MarshalAs(UnmanagedType.Bool)] bool fDeleteOnRelease, out IStream ppstm); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("urlmon.dll")] + public static extern HRESULT CopyStgMedium(ref STGMEDIUM pcstgmedSrc, ref STGMEDIUM pstgmedDest); + + + #region Win7 declarations + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", PreserveSig = false)] + public static extern void DwmInvalidateIconicBitmaps(IntPtr hwnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", PreserveSig = false)] + public static extern void DwmSetIconicThumbnail(IntPtr hwnd, IntPtr hbmp, DWM_SIT dwSITFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("dwmapi.dll", PreserveSig = false)] + public static extern void DwmSetIconicLivePreviewBitmap(IntPtr hwnd, IntPtr hbmp, RefPOINT pptClient, DWM_SIT dwSITFlags); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool SetForegroundWindow(IntPtr hWnd); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", PreserveSig = false)] + public static extern void SHGetItemFromDataObject(IDataObject pdtobj, DOGIF dwFlags, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object ppv); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", PreserveSig = false, EntryPoint = "SHAddToRecentDocs")] + private static extern void _SHAddToRecentDocsObj(SHARD uFlags, object pv); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", EntryPoint = "SHAddToRecentDocs")] + private static extern void _SHAddToRecentDocs_String(SHARD uFlags, [MarshalAs(UnmanagedType.LPWStr)] string pv); + + // This overload is required. There's a cast in the Shell code that causes the wrong vtbl to be used + // if we let the marshaller convert the parameter to an IUnknown. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", EntryPoint = "SHAddToRecentDocs")] + private static extern void _SHAddToRecentDocs_ShellLink(SHARD uFlags, IShellLinkW pv); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SHAddToRecentDocs(string path) + { + _SHAddToRecentDocs_String(SHARD.PATHW, path); + } + + // Win7 only. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SHAddToRecentDocs(IShellLinkW shellLink) + { + _SHAddToRecentDocs_ShellLink(SHARD.LINK, shellLink); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SHAddToRecentDocs(SHARDAPPIDINFO info) + { + _SHAddToRecentDocsObj(SHARD.APPIDINFO, info); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SHAddToRecentDocs(SHARDAPPIDINFOIDLIST infodIdList) + { + _SHAddToRecentDocsObj(SHARD.APPIDINFOIDLIST, infodIdList); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", PreserveSig = false)] + public static extern HRESULT SHCreateItemFromParsingName([MarshalAs(UnmanagedType.LPWStr)] string pszPath, IBindCtx pbc, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.Interface)] out object ppv); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool Shell_NotifyIcon(NIM dwMessage, [In] NOTIFYICONDATA lpdata); + + /// + /// Sets the User Model AppID for the current process, enabling Windows to retrieve this ID + /// + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll", PreserveSig = false)] + public static extern void SetCurrentProcessExplicitAppUserModelID([MarshalAs(UnmanagedType.LPWStr)] string AppID); + + /// + /// Retrieves the User Model AppID that has been explicitly set for the current process via SetCurrentProcessExplicitAppUserModelID + /// + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [DllImport("shell32.dll")] + public static extern HRESULT GetCurrentProcessExplicitAppUserModelID([Out, MarshalAs(UnmanagedType.LPWStr)] out string AppID); + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Windows/ShellProvider.cs b/Microsoft.Windows.Shell/standard.net/Windows/ShellProvider.cs new file mode 100644 index 0000000..3127fcf --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Windows/ShellProvider.cs @@ -0,0 +1,1311 @@ +namespace Standard +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.ComTypes; + using System.Text; + using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; + + #region Enums and Static Property Classes + + /// ASSOCIATIONLEVEL, AL_* + internal enum AL + { + MACHINE, + EFFECTIVE, + USER, + } + + /// ASSOCIATIONTYPE, AT_* + internal enum AT + { + FILEEXTENSION, + URLPROTOCOL, + STARTMENUCLIENT, + MIMETYPE, + } + + /// FileDialog AddPlace options. FDAP_* + internal enum FDAP : uint + { + BOTTOM = 0x00000000, + TOP = 0x00000001, + } + + /// IFileDialog options. FOS_* + [Flags] + internal enum FOS : uint + { + OVERWRITEPROMPT = 0x00000002, + STRICTFILETYPES = 0x00000004, + NOCHANGEDIR = 0x00000008, + PICKFOLDERS = 0x00000020, + FORCEFILESYSTEM = 0x00000040, + ALLNONSTORAGEITEMS = 0x00000080, + NOVALIDATE = 0x00000100, + ALLOWMULTISELECT = 0x00000200, + PATHMUSTEXIST = 0x00000800, + FILEMUSTEXIST = 0x00001000, + CREATEPROMPT = 0x00002000, + SHAREAWARE = 0x00004000, + NOREADONLYRETURN = 0x00008000, + NOTESTFILECREATE = 0x00010000, + HIDEMRUPLACES = 0x00020000, + HIDEPINNEDPLACES = 0x00040000, + NODEREFERENCELINKS = 0x00100000, + DONTADDTORECENT = 0x02000000, + FORCESHOWHIDDEN = 0x10000000, + DEFAULTNOMINIMODE = 0x20000000, + FORCEPREVIEWPANEON = 0x40000000, + } + + /// FDE_OVERWRITE_RESPONSE. FDEOR_* + internal enum FDEOR + { + DEFAULT = 0x00000000, + ACCEPT = 0x00000001, + REFUSE = 0x00000002, + } + + /// FDE_SHAREVIOLATION_RESPONSE. FDESVR_* + internal enum FDESVR + { + DEFAULT = 0x00000000, + ACCEPT = 0x00000001, + REFUSE = 0x00000002, + } + + /// ShellItem attribute flags. SIATTRIBFLAGS_* + internal enum SIATTRIBFLAGS + { + AND = 0x00000001, + OR = 0x00000002, + APPCOMPAT = 0x00000003, + } + + internal enum APPDOCLISTTYPE + { + ADLT_RECENT = 0, // The recently used documents list + ADLT_FREQUENT, // The frequently used documents list + } + + /// + /// Flags for SetTabProperties. STPF_* + /// + /// The native enum was called STPFLAG. + [Flags] + internal enum STPF + { + NONE = 0x00000000, + USEAPPTHUMBNAILALWAYS = 0x00000001, + USEAPPTHUMBNAILWHENACTIVE = 0x00000002, + USEAPPPEEKALWAYS = 0x00000004, + USEAPPPEEKWHENACTIVE = 0x00000008, + } + + /// + /// Flags for Setting Taskbar Progress state. TBPF_* + /// + /// + /// The native enum was called TBPFLAG. + /// + internal enum TBPF + { + NOPROGRESS = 0x00000000, + INDETERMINATE = 0x00000001, + NORMAL = 0x00000002, + ERROR = 0x00000004, + PAUSED = 0x00000008, + } + + /// + /// THUMBBUTTON mask. THB_* + /// + [Flags] + internal enum THB : uint + { + BITMAP = 0x0001, + ICON = 0x0002, + TOOLTIP = 0x0004, + FLAGS = 0x0008, + } + + /// + /// THUMBBUTTON flags. THBF_* + /// + [Flags] + internal enum THBF : uint + { + ENABLED = 0x0000, + DISABLED = 0x0001, + DISMISSONCLICK = 0x0002, + NOBACKGROUND = 0x0004, + HIDDEN = 0x0008, + // Added post-beta + NONINTERACTIVE = 0x0010, + } + + /// + /// GetPropertyStoreFlags. GPS_*. + /// + /// + /// These are new for Vista, but are used in downlevel components + /// + internal enum GPS + { + // If no flags are specified (GPS_DEFAULT), a read-only property store is returned that includes properties for the file or item. + // In the case that the shell item is a file, the property store contains: + // 1. properties about the file from the file system + // 2. properties from the file itself provided by the file's property handler, unless that file is offline, + // see GPS_OPENSLOWITEM + // 3. if requested by the file's property handler and supported by the file system, properties stored in the + // alternate property store. + // + // Non-file shell items should return a similar read-only store + // + // Specifying other GPS_ flags modifies the store that is returned + DEFAULT = 0x00000000, + HANDLERPROPERTIESONLY = 0x00000001, // only include properties directly from the file's property handler + READWRITE = 0x00000002, // Writable stores will only include handler properties + TEMPORARY = 0x00000004, // A read/write store that only holds properties for the lifetime of the IShellItem object + FASTPROPERTIESONLY = 0x00000008, // do not include any properties from the file's property handler (because the file's property handler will hit the disk) + OPENSLOWITEM = 0x00000010, // include properties from a file's property handler, even if it means retrieving the file from offline storage. + DELAYCREATION = 0x00000020, // delay the creation of the file's property handler until those properties are read, written, or enumerated + BESTEFFORT = 0x00000040, // For readonly stores, succeed and return all available properties, even if one or more sources of properties fails. Not valid with GPS_READWRITE. + NO_OPLOCK = 0x00000080, // some data sources protect the read property store with an oplock, this disables that + MASK_VALID = 0x000000FF, + } + + /// + /// KNOWNDESTCATEGORY. KDC_* + /// + internal enum KDC + { + FREQUENT = 1, + RECENT, + } + + // IShellFolder::GetAttributesOf flags + [Flags] + internal enum SFGAO : uint + { + /// Objects can be copied + /// DROPEFFECT_COPY + CANCOPY = 0x1, + /// Objects can be moved + /// DROPEFFECT_MOVE + CANMOVE = 0x2, + /// Objects can be linked + /// + /// DROPEFFECT_LINK. + /// + /// If this bit is set on an item in the shell folder, a + /// 'Create Shortcut' menu item will be added to the File + /// menu and context menus for the item. If the user selects + /// that command, your IContextMenu::InvokeCommand() will be called + /// with 'link'. + /// That flag will also be used to determine if 'Create Shortcut' + /// should be added when the item in your folder is dragged to another + /// folder. + /// + CANLINK = 0x4, + /// supports BindToObject(IID_IStorage) + STORAGE = 0x00000008, + /// Objects can be renamed + CANRENAME = 0x00000010, + /// Objects can be deleted + CANDELETE = 0x00000020, + /// Objects have property sheets + HASPROPSHEET = 0x00000040, + + // unused = 0x00000080, + + /// Objects are drop target + DROPTARGET = 0x00000100, + CAPABILITYMASK = 0x00000177, + // unused = 0x00000200, + // unused = 0x00000400, + // unused = 0x00000800, + // unused = 0x00001000, + /// Object is encrypted (use alt color) + ENCRYPTED = 0x00002000, + /// 'Slow' object + ISSLOW = 0x00004000, + /// Ghosted icon + GHOSTED = 0x00008000, + /// Shortcut (link) + LINK = 0x00010000, + /// Shared + SHARE = 0x00020000, + /// Read-only + READONLY = 0x00040000, + /// Hidden object + HIDDEN = 0x00080000, + DISPLAYATTRMASK = 0x000FC000, + /// May contain children with SFGAO_FILESYSTEM + FILESYSANCESTOR = 0x10000000, + /// Support BindToObject(IID_IShellFolder) + FOLDER = 0x20000000, + /// Is a win32 file system object (file/folder/root) + FILESYSTEM = 0x40000000, + /// May contain children with SFGAO_FOLDER (may be slow) + HASSUBFOLDER = 0x80000000, + CONTENTSMASK = 0x80000000, + /// Invalidate cached information (may be slow) + VALIDATE = 0x01000000, + /// Is this removeable media? + REMOVABLE = 0x02000000, + /// Object is compressed (use alt color) + COMPRESSED = 0x04000000, + /// Supports IShellFolder, but only implements CreateViewObject() (non-folder view) + BROWSABLE = 0x08000000, + /// Is a non-enumerated object (should be hidden) + NONENUMERATED = 0x00100000, + /// Should show bold in explorer tree + NEWCONTENT = 0x00200000, + /// Obsolete + CANMONIKER = 0x00400000, + /// Obsolete + HASSTORAGE = 0x00400000, + /// Supports BindToObject(IID_IStream) + STREAM = 0x00400000, + /// May contain children with SFGAO_STORAGE or SFGAO_STREAM + STORAGEANCESTOR = 0x00800000, + /// For determining storage capabilities, ie for open/save semantics + STORAGECAPMASK = 0x70C50008, + /// + /// Attributes that are masked out for PKEY_SFGAOFlags because they are considered + /// to cause slow calculations or lack context + /// (SFGAO_VALIDATE | SFGAO_ISSLOW | SFGAO_HASSUBFOLDER and others) + /// + PKEYSFGAOMASK = 0x81044000, + } + + /// + /// IShellFolder::EnumObjects grfFlags bits. Also called SHCONT + /// + internal enum SHCONTF + { + CHECKING_FOR_CHILDREN = 0x0010, // hint that client is checking if (what) child items the folder contains - not all details (e.g. short file name) are needed + FOLDERS = 0x0020, // only want folders enumerated (SFGAO_FOLDER) + NONFOLDERS = 0x0040, // include non folders (items without SFGAO_FOLDER) + INCLUDEHIDDEN = 0x0080, // show items normally hidden (items with SFGAO_HIDDEN) + INIT_ON_FIRST_NEXT = 0x0100, // DEFUNCT - this is always assumed + NETPRINTERSRCH = 0x0200, // hint that client is looking for printers + SHAREABLE = 0x0400, // hint that client is looking sharable resources (local drives or hidden root shares) + STORAGE = 0x0800, // include all items with accessible storage and their ancestors + NAVIGATION_ENUM = 0x1000, // mark child folders to indicate that they should provide a "navigation" enumeration by default + FASTITEMS = 0x2000, // hint that client is only interested in items that can be enumerated quickly + FLATLIST = 0x4000, // enumerate items as flat list even if folder is stacked + ENABLE_ASYNC = 0x8000, // inform enumerator that client is listening for change notifications so enumerator does not need to be complete, items can be reported via change notifications + } + + /// + /// IShellFolder::GetDisplayNameOf/SetNameOf uFlags. Also called SHGDNF. + /// + /// + /// For compatibility with SIGDN, these bits must all sit in the LOW word. + /// + [Flags] + internal enum SHGDN + { + SHGDN_NORMAL = 0x0000, // default (display purpose) + SHGDN_INFOLDER = 0x0001, // displayed under a folder (relative) + SHGDN_FOREDITING = 0x1000, // for in-place editing + SHGDN_FORADDRESSBAR = 0x4000, // UI friendly parsing name (remove ugly stuff) + SHGDN_FORPARSING = 0x8000, // parsing name for ParseDisplayName() + } + + /// + /// SHELLITEMCOMPAREHINTF. SICHINT_*. + /// + internal enum SICHINT : uint + { + /// iOrder based on display in a folder view + DISPLAY = 0x00000000, + /// exact instance compare + ALLFIELDS = 0x80000000, + /// iOrder based on canonical name (better performance) + CANONICAL = 0x10000000, + TEST_FILESYSPATH_IF_NOT_EQUAL = 0x20000000, + }; + + /// + /// ShellItem enum. SIGDN_*. + /// + internal enum SIGDN : uint + { // lower word (& with 0xFFFF) + NORMALDISPLAY = 0x00000000, // SHGDN_NORMAL + PARENTRELATIVEPARSING = 0x80018001, // SHGDN_INFOLDER | SHGDN_FORPARSING + DESKTOPABSOLUTEPARSING = 0x80028000, // SHGDN_FORPARSING + PARENTRELATIVEEDITING = 0x80031001, // SHGDN_INFOLDER | SHGDN_FOREDITING + DESKTOPABSOLUTEEDITING = 0x8004c000, // SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + FILESYSPATH = 0x80058000, // SHGDN_FORPARSING + URL = 0x80068000, // SHGDN_FORPARSING + PARENTRELATIVEFORADDRESSBAR = 0x8007c001, // SHGDN_INFOLDER | SHGDN_FORPARSING | SHGDN_FORADDRESSBAR + PARENTRELATIVE = 0x80080001, // SHGDN_INFOLDER + } + + /// + /// STR_GPS_* + /// + /// + /// When requesting a property store through IShellFolder, you can specify the equivalent of + /// GPS_DEFAULT by passing in a null IBindCtx parameter. + /// + /// You can specify the equivalent of GPS_READWRITE by passing a mode of STGM_READWRITE | STGM_EXCLUSIVE + /// in the bind context + /// + /// Here are the string versions of GPS_ flags, passed to IShellFolder::BindToObject() via IBindCtx::RegisterObjectParam() + /// These flags are valid when requesting an IPropertySetStorage or IPropertyStore handler + /// + /// The meaning of these flags are described above. + /// + /// There is no STR_ equivalent for GPS_TEMPORARY because temporary property stores + /// are provided by IShellItem2 only -- not by the underlying IShellFolder. + /// + internal static class STR_GPS + { + public const string HANDLERPROPERTIESONLY = "GPS_HANDLERPROPERTIESONLY"; + public const string FASTPROPERTIESONLY = "GPS_FASTPROPERTIESONLY"; + public const string OPENSLOWITEM = "GPS_OPENSLOWITEM"; + public const string DELAYCREATION = "GPS_DELAYCREATION"; + public const string BESTEFFORT = "GPS_BESTEFFORT"; + public const string NO_OPLOCK = "GPS_NO_OPLOCK"; + } + + #endregion + + #region Structs + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + internal struct COMDLG_FILTERSPEC + { + [MarshalAs(UnmanagedType.LPWStr)] + public string pszName; + [MarshalAs(UnmanagedType.LPWStr)] + public string pszSpec; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 8, CharSet = CharSet.Unicode)] + internal struct THUMBBUTTON + { + /// + /// WPARAM value for a THUMBBUTTON being clicked. + /// + public const int THBN_CLICKED = 0x1800; + + public THB dwMask; + public uint iId; + public uint iBitmap; + public IntPtr hIcon; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] + public string szTip; + public THBF dwFlags; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + internal struct PKEY + { + /// fmtid + private readonly Guid _fmtid; + /// pid + private readonly uint _pid; + + public PKEY(Guid fmtid, uint pid) + { + _fmtid = fmtid; + _pid = pid; + } + + /// PKEY_Title + public static readonly PKEY Title = new PKEY(new Guid("F29F85E0-4FF9-1068-AB91-08002B27B3D9"), 2); + /// PKEY_AppUserModel_ID + public static readonly PKEY AppUserModel_ID = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 5); + /// PKEY_AppUserModel_IsDestListSeparator + public static readonly PKEY AppUserModel_IsDestListSeparator = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 6); + /// PKEY_AppUserModel_RelaunchCommand + public static readonly PKEY AppUserModel_RelaunchCommand = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 2); + /// PKEY_AppUserModel_RelaunchDisplayNameResource + public static readonly PKEY AppUserModel_RelaunchDisplayNameResource = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 4); + /// PKEY_AppUserModel_RelaunchIconResource + public static readonly PKEY AppUserModel_RelaunchIconResource = new PKEY(new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"), 3); + } + + #endregion + + #region Interfaces + + // Application File Extension and URL Protocol Registration + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ApplicationAssociationRegistration), + ] + internal interface IApplicationAssociationRegistration + { + [return: MarshalAs(UnmanagedType.LPWStr)] + string QueryCurrentDefault( + [MarshalAs(UnmanagedType.LPWStr)] string pszQuery, + AT atQueryType, + AL alQueryLevel); + + [return: MarshalAs(UnmanagedType.Bool)] + bool QueryAppIsDefault( + [MarshalAs(UnmanagedType.LPWStr)] string pszQuery, + AT atQueryType, + AL alQueryLevel, + [MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName); + + [return: MarshalAs(UnmanagedType.Bool)] + bool QueryAppIsDefaultAll( + AL alQueryLevel, + [MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName); + + void SetAppAsDefault( + [MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName, + [MarshalAs(UnmanagedType.LPWStr)] string pszSet, + AT atSetType); + + void SetAppAsDefaultAll([MarshalAs(UnmanagedType.LPWStr)] string pszAppRegistryName); + + void ClearUserAssociations(); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.EnumIdList), + ] + internal interface IEnumIDList + { + [PreserveSig()] + HRESULT Next(uint celt, out IntPtr rgelt, out int pceltFetched); + [PreserveSig()] + HRESULT Skip(uint celt); + void Reset(); + void Clone([Out, MarshalAs(UnmanagedType.Interface)] out IEnumIDList ppenum); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.EnumObjects), + ] + internal interface IEnumObjects + { + //[local] + // This signature might not work... Hopefully don't need this interface though. + void Next(uint celt, [In] ref Guid riid, [Out, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.IUnknown, IidParameterIndex = 1, SizeParamIndex = 0)] object[] rgelt, [Out] out uint pceltFetched); + + /* + [call_as(Next)] HRESULT RemoteNext( + [in] ULONG celt, + [in] REFIID riid, + [out, size_is(celt), length_is(*pceltFetched), iid_is(riid)] void **rgelt, + [out] ULONG *pceltFetched); + */ + + void Skip(uint celt); + + void Reset(); + + IEnumObjects Clone(); + } + + /// Unknown Object Array + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ObjectArray), + ] + internal interface IObjectArray + { + uint GetCount(); + [return: MarshalAs(UnmanagedType.IUnknown)] + object GetAt([In] uint uiIndex, [In] ref Guid riid); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ObjectArray), + ] + interface IObjectCollection : IObjectArray + { + #region IObjectArray redeclarations + new uint GetCount(); + [return: MarshalAs(UnmanagedType.IUnknown)] + new object GetAt([In] uint uiIndex, [In] ref Guid riid); + #endregion + + void AddObject([MarshalAs(UnmanagedType.IUnknown)] object punk); + void AddFromArray(IObjectArray poaSource); + void RemoveObjectAt(uint uiIndex); + void Clear(); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.PropertyStore) + ] + internal interface IPropertyStore + { + uint GetCount(); + PKEY GetAt(uint iProp); + void GetValue([In] ref PKEY pkey, [In, Out] PROPVARIANT pv); + void SetValue([In] ref PKEY pkey, PROPVARIANT pv); + void Commit(); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellFolder), + ] + internal interface IShellFolder + { + void ParseDisplayName( + [In] IntPtr hwnd, + [In] IBindCtx pbc, + [In, MarshalAs(UnmanagedType.LPWStr)] string pszDisplayName, + [In, Out] ref int pchEaten, + [Out] out IntPtr ppidl, + [In, Out] ref uint pdwAttributes); + + IEnumIDList EnumObjects( + [In] IntPtr hwnd, + [In] SHCONTF grfFlags); + + // returns an instance of a sub-folder which is specified by the IDList (pidl). + // IShellFolder or derived interfaces + [return: MarshalAs(UnmanagedType.Interface)] + object BindToObject( + [In] IntPtr pidl, + [In] IBindCtx pbc, + [In] ref Guid riid); + + // produces the same result as BindToObject() + [return: MarshalAs(UnmanagedType.Interface)] + object BindToStorage([In] IntPtr pidl, [In] IBindCtx pbc, [In] ref Guid riid); + + // compares two IDLists and returns the result. The shell + // explorer always passes 0 as lParam, which indicates 'sort by name'. + // It should return 0 (as CODE of the scode), if two id indicates the + // same object; negative value if pidl1 should be placed before pidl2; + // positive value if pidl2 should be placed before pidl1. + // use the macro ResultFromShort() to extract the result comparison + // it deals with the casting and type conversion issues for you + [PreserveSig] + HRESULT CompareIDs([In] IntPtr lParam, [In] IntPtr pidl1, [In] IntPtr pidl2); + + // creates a view object of the folder itself. The view + // object is a difference instance from the shell folder object. + // 'hwndOwner' can be used as the owner window of its dialog box or + // menu during the lifetime of the view object. + // This member function should always create a new + // instance which has only one reference count. The explorer may create + // more than one instances of view object from one shell folder object + // and treat them as separate instances. + // returns IShellView derived interface + [return: MarshalAs(UnmanagedType.Interface)] + object CreateViewObject([In] IntPtr hwndOwner, [In] ref Guid riid); + + // returns the attributes of specified objects in that + // folder. 'cidl' and 'apidl' specifies objects. 'apidl' contains only + // simple IDLists. The explorer initializes *prgfInOut with a set of + // flags to be evaluated. The shell folder may optimize the operation + // by not returning unspecified flags. + void GetAttributesOf( + [In] uint cidl, + [In] IntPtr apidl, + [In, Out] ref SFGAO rgfInOut); + + // creates a UI object to be used for specified objects. + // The shell explorer passes either IID_IDataObject (for transfer operation) + // or IID_IContextMenu (for context menu operation) as riid + // and many other interfaces + [return: MarshalAs(UnmanagedType.Interface)] + object GetUIObjectOf( + [In] IntPtr hwndOwner, + [In] uint cidl, + [In, MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.SysInt, SizeParamIndex = 2)] IntPtr apidl, + [In] ref Guid riid, + [In, Out] ref uint rgfReserved); + + // returns the display name of the specified object. + // If the ID contains the display name (in the locale character set), + // it returns the offset to the name. Otherwise, it returns a pointer + // to the display name string (UNICODE), which is allocated by the + // task allocator, or fills in a buffer. + // use the helper APIS StrRetToStr() or StrRetToBuf() to deal with the different + // forms of the STRRET structure + void GetDisplayNameOf([In] IntPtr pidl, [In] SHGDN uFlags, [Out] out IntPtr pName); + + // sets the display name of the specified object. + // If it changes the ID as well, it returns the new ID which is + // alocated by the task allocator. + void SetNameOf([In] IntPtr hwnd, + [In] IntPtr pidl, + [In, MarshalAs(UnmanagedType.LPWStr)] string pszName, + [In] SHGDN uFlags, + [Out] out IntPtr ppidlOut); + } + + /// + /// Shell Namespace helper + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellItem), + ] + internal interface IShellItem + { + [return: MarshalAs(UnmanagedType.Interface)] + object BindToHandler(IBindCtx pbc, [In] ref Guid bhid, [In] ref Guid riid); + + IShellItem GetParent(); + + [return: MarshalAs(UnmanagedType.LPWStr)] + string GetDisplayName(SIGDN sigdnName); + + SFGAO GetAttributes(SFGAO sfgaoMask); + + int Compare(IShellItem psi, SICHINT hint); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellItemArray), + ] + internal interface IShellItemArray + { + [return: MarshalAs(UnmanagedType.Interface)] + object BindToHandler(IBindCtx pbc, [In] ref Guid rbhid, [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyStore(int flags, [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyDescriptionList([In] ref PKEY keyType, [In] ref Guid riid); + + uint GetAttributes(SIATTRIBFLAGS dwAttribFlags, uint sfgaoMask); + + uint GetCount(); + + IShellItem GetItemAt(uint dwIndex); + + [return: MarshalAs(UnmanagedType.Interface)] + object EnumItems(); + } + + /// + /// Shell Namespace helper 2 + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellItem2), + ] + interface IShellItem2 : IShellItem + { + #region IShellItem redeclarations + [return: MarshalAs(UnmanagedType.Interface)] + new object BindToHandler([In] IBindCtx pbc, [In] ref Guid bhid, [In] ref Guid riid); + new IShellItem GetParent(); + [return: MarshalAs(UnmanagedType.LPWStr)] + new string GetDisplayName(SIGDN sigdnName); + new SFGAO GetAttributes(SFGAO sfgaoMask); + new int Compare(IShellItem psi, SICHINT hint); + #endregion + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyStore( + GPS flags, + [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyStoreWithCreateObject( + GPS flags, + [MarshalAs(UnmanagedType.IUnknown)] object punkCreateObject, // factory for low-rights creation of type ICreateObject + [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyStoreForKeys( + IntPtr rgKeys, + uint cKeys, + GPS flags, + [In] ref Guid riid); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetPropertyDescriptionList( + IntPtr keyType, + [In] ref Guid riid); + + // Ensures any cached information in this item is up to date, or returns __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) if the item does not exist. + void Update(IBindCtx pbc); + + PROPVARIANT GetProperty(IntPtr key); + + Guid GetCLSID(IntPtr key); + + FILETIME GetFileTime(IntPtr key); + + int GetInt32(IntPtr key); + + [return: MarshalAs(UnmanagedType.LPWStr)] + string GetString(IntPtr key); + + uint GetUInt32(IntPtr key); + + ulong GetUInt64(IntPtr key); + + [return: MarshalAs(UnmanagedType.Bool)] + void GetBool(IntPtr key); + } + + [ + ComImport, + InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ShellLink), + ] + internal interface IShellLinkW + { + void GetPath([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, [In, Out] WIN32_FIND_DATAW pfd, SLGP fFlags); + void GetIDList(out IntPtr ppidl); + void SetIDList(IntPtr pidl); + void GetDescription([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxName); + void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName); + void GetWorkingDirectory([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath); + void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir); + void GetArguments([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath); + void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs); + short GetHotKey(); + void SetHotKey(short wHotKey); + uint GetShowCmd(); + void SetShowCmd(uint iShowCmd); + void GetIconLocation([Out, MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath, int cchIconPath, out int piIcon); + void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon); + void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, uint dwReserved); + void Resolve(IntPtr hwnd, uint fFlags); + void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.TaskbarList), + ] + internal interface ITaskbarList + { + /// + /// This function must be called first to validate use of other members. + /// + void HrInit(); + + /// + /// This function adds a tab for hwnd to the taskbar. + /// + /// The HWND for which to add the tab. + void AddTab(IntPtr hwnd); + + /// + /// This function deletes a tab for hwnd from the taskbar. + /// + /// The HWND for which the tab is to be deleted. + void DeleteTab(IntPtr hwnd); + + /// + /// This function activates the tab associated with hwnd on the taskbar. + /// + /// The HWND for which the tab is to be actuvated. + void ActivateTab(IntPtr hwnd); + + /// + /// This function marks hwnd in the taskbar as the active tab. + /// + /// The HWND to activate. + void SetActiveAlt(IntPtr hwnd); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.TaskbarList2), + ] + internal interface ITaskbarList2 : ITaskbarList + { + #region ITaskbarList redeclaration + new void HrInit(); + new void AddTab(IntPtr hwnd); + new void DeleteTab(IntPtr hwnd); + new void ActivateTab(IntPtr hwnd); + new void SetActiveAlt(IntPtr hwnd); + #endregion + + /// + /// Marks a window as full-screen. + /// + /// The handle of the window to be marked. + /// A Boolean value marking the desired full-screen status of the window. + /// + /// Setting the value of fFullscreen to true, the Shell treats this window as a full-screen window, and the taskbar + /// is moved to the bottom of the z-order when this window is active. Setting the value of fFullscreen to false + /// removes the full-screen marking, but does not cause the Shell to treat the window as though it were + /// definitely not full-screen. With a false fFullscreen value, the Shell depends on its automatic detection facility + /// to specify how the window should be treated, possibly still flagging the window as full-screen. + /// + void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); + } + + // Used to remove items from the automatic destination lists created when apps or the system call SHAddToRecentDocs to report usage of a document. + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ApplicationDestinations) + ] + internal interface IApplicationDestinations + { + // Set the App User Model ID for the application removing destinations from its list. If an AppID is not provided + // via this method, the system will use a heuristically determined ID. This method must be called before + // RemoveDestination or RemoveAllDestinations. + void SetAppID([In, MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + + // Remove an IShellItem or an IShellLink from the automatic destination list + void RemoveDestination([MarshalAs(UnmanagedType.IUnknown)] object punk); + + // Clear the frequent and recent destination lists for this application. + void RemoveAllDestinations(); + } + + /// + /// Allows an application to retrieve the most recent and frequent documents opened in that app, as reported via SHAddToRecentDocs + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ApplicationDocumentLists) + ] + internal interface IApplicationDocumentLists + { + /// + /// Set the App User Model ID for the application retrieving this list. If an AppID is not provided via this method, + /// the system will use a heuristically determined ID. This method must be called before GetList. + /// + /// App Id. + void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + + /// + /// Retrieve an IEnumObjects or IObjectArray for IShellItems and/or IShellLinks. + /// Items may appear in both the frequent and recent lists. + /// + /// + /// + [return: MarshalAs(UnmanagedType.IUnknown)] + object GetList([In] APPDOCLISTTYPE listtype, [In] uint cItemsDesired, [In] ref Guid riid); + } + + // Custom Destination List + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.CustomDestinationList) + ] + internal interface ICustomDestinationList + { + void SetAppID([In, MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + + // Retrieve IObjectArray of IShellItems or IShellLinks that represent removed destinations + [return: MarshalAs(UnmanagedType.Interface)] + object BeginList(out uint pcMaxSlots, [In] ref Guid riid); + + // PreserveSig because this will return custom errors when attempting to add unregistered ShellItems. + // Can't readily detect that case without just trying to append it. + [PreserveSig] + HRESULT AppendCategory([MarshalAs(UnmanagedType.LPWStr)] string pszCategory, IObjectArray poa); + void AppendKnownCategory(KDC category); + [PreserveSig] + HRESULT AddUserTasks(IObjectArray poa); + void CommitList(); + + // Retrieve IObjectCollection of IShellItems + [return: MarshalAs(UnmanagedType.Interface)] + object GetRemovedDestinations([In] ref Guid riid); + void DeleteList([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + void AbortList(); + } + + /// + /// Provides access to the App User Model ID on objects supporting this value. + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ObjectWithAppUserModelId) + ] + internal interface IObjectWithAppUserModelId + { + void SetAppID([MarshalAs(UnmanagedType.LPWStr)] string pszAppID); + [return: MarshalAs(UnmanagedType.LPWStr)] + string GetAppID(); + }; + + /// + /// Provides access to the ProgID associated with an object + /// + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ObjectWithProgId) + ] + internal interface IObjectWithProgId + { + void SetProgID([MarshalAs(UnmanagedType.LPWStr)] string pszProgID); + [return: MarshalAs(UnmanagedType.LPWStr)] + string GetProgID(); + }; + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.TaskbarList3), + ] + internal interface ITaskbarList3 : ITaskbarList2 + { + #region ITaskbarList2 redeclaration + + #region ITaskbarList redeclaration + new void HrInit(); + new void AddTab(IntPtr hwnd); + new void DeleteTab(IntPtr hwnd); + new void ActivateTab(IntPtr hwnd); + new void SetActiveAlt(IntPtr hwnd); + #endregion + + new void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); + + #endregion + + [PreserveSig] + HRESULT SetProgressValue(IntPtr hwnd, ulong ullCompleted, ulong ullTotal); + + [PreserveSig] + HRESULT SetProgressState(IntPtr hwnd, TBPF tbpFlags); + + [PreserveSig] + HRESULT RegisterTab(IntPtr hwndTab, IntPtr hwndMDI); + + [PreserveSig] + HRESULT UnregisterTab(IntPtr hwndTab); + + [PreserveSig] + HRESULT SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore); + + [PreserveSig] + HRESULT SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, uint dwReserved); + + [PreserveSig] + HRESULT ThumbBarAddButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); + + [PreserveSig] + HRESULT ThumbBarUpdateButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); + + [PreserveSig] + HRESULT ThumbBarSetImageList(IntPtr hwnd, [MarshalAs(UnmanagedType.IUnknown)] object himl); + + [PreserveSig] + HRESULT SetOverlayIcon(IntPtr hwnd, IntPtr hIcon, [MarshalAs(UnmanagedType.LPWStr)] string pszDescription); + + [PreserveSig] + HRESULT SetThumbnailTooltip(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszTip); + + // Using RefRECT to making passing NULL possible. Removes clipping from the HWND. + [PreserveSig] + HRESULT SetThumbnailClip(IntPtr hwnd, RefRECT prcClip); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.TaskbarList3), + ] + internal interface ITaskbarList4 : ITaskbarList3 + { + #region ITaskbarList3 redeclaration + + #region ITaskbarList2 redeclaration + + #region ITaskbarList redeclaration + new void HrInit(); + new void AddTab(IntPtr hwnd); + new void DeleteTab(IntPtr hwnd); + new void ActivateTab(IntPtr hwnd); + new void SetActiveAlt(IntPtr hwnd); + #endregion + + new void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen); + + #endregion + + [PreserveSig] new HRESULT SetProgressValue(IntPtr hwnd, ulong ullCompleted, ulong ullTotal); + [PreserveSig] new HRESULT SetProgressState(IntPtr hwnd, TBPF tbpFlags); + [PreserveSig] new HRESULT RegisterTab(IntPtr hwndTab, IntPtr hwndMDI); + [PreserveSig] new HRESULT UnregisterTab(IntPtr hwndTab); + [PreserveSig] new HRESULT SetTabOrder(IntPtr hwndTab, IntPtr hwndInsertBefore); + [PreserveSig] new HRESULT SetTabActive(IntPtr hwndTab, IntPtr hwndMDI, uint dwReserved); + [PreserveSig] new HRESULT ThumbBarAddButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); + [PreserveSig] new HRESULT ThumbBarUpdateButtons(IntPtr hwnd, uint cButtons, [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 1)] THUMBBUTTON[] pButtons); + [PreserveSig] new HRESULT ThumbBarSetImageList(IntPtr hwnd, [MarshalAs(UnmanagedType.IUnknown)] object himl); + [PreserveSig] new HRESULT SetOverlayIcon(IntPtr hwnd, IntPtr hIcon, [MarshalAs(UnmanagedType.LPWStr)] string pszDescription); + [PreserveSig] new HRESULT SetThumbnailTooltip(IntPtr hwnd, [MarshalAs(UnmanagedType.LPWStr)] string pszTip); + // Using RefRECT to making passing NULL possible. Removes clipping from the HWND. + [PreserveSig] new HRESULT SetThumbnailClip(IntPtr hwnd, RefRECT prcClip); + + #endregion + + void SetTabProperties(IntPtr hwndTab, STPF stpFlags); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.FileDialogEvents), +] + internal interface IFileDialogEvents + { + [PreserveSig] + HRESULT OnFileOk(IFileDialog pfd); + + [PreserveSig] + HRESULT OnFolderChanging(IFileDialog pfd, IShellItem psiFolder); + + [PreserveSig] + HRESULT OnFolderChange(IFileDialog pfd); + + [PreserveSig] + HRESULT OnSelectionChange(IFileDialog pfd); + + [PreserveSig] + HRESULT OnShareViolation(IFileDialog pfd, IShellItem psi, out FDESVR pResponse); + + [PreserveSig] + HRESULT OnTypeChange(IFileDialog pfd); + + [PreserveSig] + HRESULT OnOverwrite(IFileDialog pfd, IShellItem psi, out FDEOR pResponse); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.ModalWindow), + ] + internal interface IModalWindow + { + [PreserveSig] + HRESULT Show(IntPtr parent); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.FileDialog), + ] + internal interface IFileDialog : IModalWindow + { + #region IModalWindow redeclarations + [PreserveSig] + new HRESULT Show(IntPtr parent); + #endregion + + void SetFileTypes(uint cFileTypes, [In] ref COMDLG_FILTERSPEC rgFilterSpec); + + void SetFileTypeIndex(uint iFileType); + + uint GetFileTypeIndex(); + + uint Advise(IFileDialogEvents pfde); + + void Unadvise(uint dwCookie); + + void SetOptions(FOS fos); + + FOS GetOptions(); + + void SetDefaultFolder(IShellItem psi); + + void SetFolder(IShellItem psi); + + IShellItem GetFolder(); + + IShellItem GetCurrentSelection(); + + void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName); + + [return: MarshalAs(UnmanagedType.LPWStr)] + string GetFileName(); + + void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle); + + void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText); + + void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel); + + IShellItem GetResult(); + + void AddPlace(IShellItem psi, FDAP alignment); + + void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); + + void Close([MarshalAs(UnmanagedType.Error)] int hr); + + void SetClientGuid([In] ref Guid guid); + + void ClearClientData(); + + void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.FileOpenDialog), + ] + internal interface IFileOpenDialog : IFileDialog + { + #region IFileDialog redeclarations + + #region IModalDialog redeclarations + [PreserveSig] + new HRESULT Show(IntPtr parent); + #endregion + + new void SetFileTypes(uint cFileTypes, [In] ref COMDLG_FILTERSPEC rgFilterSpec); + new void SetFileTypeIndex(uint iFileType); + new uint GetFileTypeIndex(); + new uint Advise(IFileDialogEvents pfde); + new void Unadvise(uint dwCookie); + new void SetOptions(FOS fos); + new FOS GetOptions(); + new void SetDefaultFolder(IShellItem psi); + new void SetFolder(IShellItem psi); + new IShellItem GetFolder(); + new IShellItem GetCurrentSelection(); + new void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName); + [return: MarshalAs(UnmanagedType.LPWStr)] + new string GetFileName(); + new void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle); + new void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText); + new void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel); + new IShellItem GetResult(); + new void AddPlace(IShellItem psi, FDAP fdcp); + new void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); + new void Close([MarshalAs(UnmanagedType.Error)] int hr); + new void SetClientGuid([In] ref Guid guid); + new void ClearClientData(); + new void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter); + + #endregion + + IShellItemArray GetResults(); + + IShellItemArray GetSelectedItems(); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.FileSaveDialog), + ] + internal interface IFileSaveDialog : IFileDialog + { + #region IFileDialog redeclarations + + #region IModalDialog redeclarations + [PreserveSig] + new HRESULT Show(IntPtr parent); + #endregion + + new void SetFileTypes(uint cFileTypes, [In] ref COMDLG_FILTERSPEC rgFilterSpec); + new void SetFileTypeIndex(uint iFileType); + new uint GetFileTypeIndex(); + new uint Advise(IFileDialogEvents pfde); + new void Unadvise(uint dwCookie); + new void SetOptions(FOS fos); + new FOS GetOptions(); + new void SetDefaultFolder(IShellItem psi); + new void SetFolder(IShellItem psi); + new IShellItem GetFolder(); + new IShellItem GetCurrentSelection(); + new void SetFileName([MarshalAs(UnmanagedType.LPWStr)] string pszName); + [return: MarshalAs(UnmanagedType.LPWStr)] + new string GetFileName(); + new void SetTitle([MarshalAs(UnmanagedType.LPWStr)] string pszTitle); + new void SetOkButtonLabel([MarshalAs(UnmanagedType.LPWStr)] string pszText); + new void SetFileNameLabel([MarshalAs(UnmanagedType.LPWStr)] string pszLabel); + new IShellItem GetResult(); + new void AddPlace(IShellItem psi, FDAP fdcp); + new void SetDefaultExtension([MarshalAs(UnmanagedType.LPWStr)] string pszDefaultExtension); + new void Close([MarshalAs(UnmanagedType.Error)] int hr); + new void SetClientGuid([In] ref Guid guid); + new void ClearClientData(); + new void SetFilter([MarshalAs(UnmanagedType.Interface)] object pFilter); + + #endregion + + void SetSaveAsItem(IShellItem psi); + + void SetProperties([In, MarshalAs(UnmanagedType.Interface)] object pStore); + + void SetCollectedProperties([In, MarshalAs(UnmanagedType.Interface)] object pList, [In] int fAppendDefault); + + [return: MarshalAs(UnmanagedType.Interface)] + object GetProperties(); + + void ApplyProperties(IShellItem psi, [MarshalAs(UnmanagedType.Interface)] object pStore, [In] ref IntPtr hwnd, [MarshalAs(UnmanagedType.Interface)] object pSink); + } + + internal static class ShellUtil + { + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string GetPathFromShellItem(IShellItem item) + { + return item.GetDisplayName(SIGDN.DESKTOPABSOLUTEPARSING); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IShellItem2 GetShellItemForPath(string path) + { + if (string.IsNullOrEmpty(path)) + { + // Internal function. Should have verified this before calling if we cared. + return null; + } + + Guid iidShellItem2 = new Guid(IID.ShellItem2); + object unk; + HRESULT hr = NativeMethods.SHCreateItemFromParsingName(path, null, ref iidShellItem2, out unk); + + // Silently absorb errors such as ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND. + // Let others pass through + if (hr == (HRESULT)Win32Error.ERROR_FILE_NOT_FOUND || hr == (HRESULT)Win32Error.ERROR_PATH_NOT_FOUND) + { + hr = HRESULT.S_OK; + unk = null; + } + + hr.ThrowIfFailed(); + + return (IShellItem2)unk; + } + } + + #endregion +} diff --git a/Microsoft.Windows.Shell/standard.net/Windows/StreamHelper.cs b/Microsoft.Windows.Shell/standard.net/Windows/StreamHelper.cs new file mode 100644 index 0000000..344d94c --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Windows/StreamHelper.cs @@ -0,0 +1,715 @@ +// The ComStream class is used for the contact property types. +// The types can have unexpected behavior if they're changed by callers, +// so this provides an immutable stream implementation. +// The volatile functions are implemented (not tested) +// in case a separate ReadonlyStream needs to be implemented. +//#define FEATURE_MUTABLE_COM_STREAMS + +namespace Standard +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.ComTypes; + + // disambiguate with System.Runtime.InteropServices.STATSTG + using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG; + + // This is adapted from Microsoft KB article 321340 + /// + /// Wraps an IStream interface pointer from COM into a form consumable by .Net. + /// + /// + /// This implementation is immutable, though it's possible that the underlying + /// stream can be changed in another context. + /// + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + internal sealed class ComStream : Stream + { + private const int STATFLAG_NONAME = 1; + + private IStream _source; + + private void _Validate() + { + if (null == _source) + { + throw new ObjectDisposedException("this"); + } + } + + /// + /// Wraps a native IStream interface into a CLR Stream subclass. + /// + /// + /// The stream that this object wraps. + /// + /// + /// Note that the parameter is passed by ref. On successful creation it is + /// zeroed out to the caller. This object becomes responsible for the lifetime + /// management of the wrapped IStream. + /// + public ComStream(ref IStream stream) + { + Verify.IsNotNull(stream, "stream"); + _source = stream; + // Zero out caller's reference to this. The object now owns the memory. + stream = null; + } + + #region Overridden Stream Methods + + // Experimentally, the base class seems to deal with the IDisposable pattern. + // Overridden implementations aren't called, but Close is as part of the Dispose call. + public override void Close() + { + if (null != _source) + { +#if FEATURE_MUTABLE_COM_STREAMS + Flush(); +#endif + Utility.SafeRelease(ref _source); + } + } + + public override bool CanRead + { + get + { + // For the context of this class, this should be true... + return true; + } + } + + public override bool CanSeek + { + get + { + // This should be true... + return true; + } + } + + public override bool CanWrite + { + get + { +#if FEATURE_MUTABLE_COM_STREAMS + // Really don't know that this is true... + return true; +#endif + return false; + } + } + + public override void Flush() + { +#if FEATURE_MUTABLE_COM_STREAMS + _Validate(); + // Don't have enough context of the underlying object to reliably do anything here. + try + { + _source.Commit(STGC_DEFAULT); + } + catch { } +#endif + } + + public override long Length + { + get + { + _Validate(); + + STATSTG statstg; + _source.Stat(out statstg, STATFLAG_NONAME); + return statstg.cbSize; + } + } + + public override long Position + { + get { return Seek(0, SeekOrigin.Current); } + set { Seek(value, SeekOrigin.Begin); } + } + + public override int Read(byte[] buffer, int offset, int count) + { + _Validate(); + + IntPtr pcbRead = IntPtr.Zero; + + try + { + pcbRead = Marshal.AllocHGlobal(sizeof(Int32)); + + // PERFORMANCE NOTE: This buffer doesn't need to be allocated if offset == 0 + var tempBuffer = new byte[count]; + _source.Read(tempBuffer, count, pcbRead); + Array.Copy(tempBuffer, 0, buffer, offset, Marshal.ReadInt32(pcbRead)); + + return Marshal.ReadInt32(pcbRead); + } + finally + { + Utility.SafeFreeHGlobal(ref pcbRead); + } + } + + public override long Seek(long offset, SeekOrigin origin) + { + _Validate(); + + IntPtr plibNewPosition = IntPtr.Zero; + + try + { + plibNewPosition = Marshal.AllocHGlobal(sizeof(Int64)); + _source.Seek(offset, (int)origin, plibNewPosition); + + return Marshal.ReadInt64(plibNewPosition); + } + finally + { + Utility.SafeFreeHGlobal(ref plibNewPosition); + } + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); +#if FEATURE_MUTABLE_COM_STREAMS + _Validate(); + _source.SetSize(value); +#endif + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); +#if FEATURE_MUTABLE_COM_STREAMS + _Validate(); + + // PERFORMANCE NOTE: This buffer doesn't need to be allocated if offset == 0 + byte[] tempBuffer = new byte[buffer.Length - offset]; + Array.Copy(buffer, offset, tempBuffer, 0, tempBuffer.Length); + _source.Write(tempBuffer, tempBuffer.Length, IntPtr.Zero); +#endif + } + + #endregion + } + + // All these methods return void. Does the standard marshaller convert them to HRESULTs? + /// + /// Wraps a managed stream instance into an interface pointer consumable by COM. + /// + [SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + internal sealed class ManagedIStream : IStream, IDisposable + { + private const int STGTY_STREAM = 2; + private const int STGM_READWRITE = 2; + private const int LOCK_EXCLUSIVE = 2; + + private Stream _source; + + /// + /// Initializes a new instance of the ManagedIStream class with the specified managed Stream object. + /// + /// + /// The stream that this IStream reference is wrapping. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public ManagedIStream(Stream source) + { + Verify.IsNotNull(source, "source"); + _source = source; + } + + private void _Validate() + { + if (null == _source) + { + throw new ObjectDisposedException("this"); + } + } + + // Comments are taken from MSDN IStream documentation. + #region IStream Members + + /// + /// Creates a new stream object with its own seek pointer that + /// references the same bytes as the original stream. + /// + /// + /// When this method returns, contains the new stream object. This parameter is passed uninitialized. + /// + /// + /// For more information, see the existing documentation for IStream::Clone in the MSDN library. + /// This class doesn't implement Clone. A COMException is thrown if it is used. + /// + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)")] + [Obsolete("The method is not implemented", true)] + public void Clone(out IStream ppstm) + { + ppstm = null; + HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); + } + + /// + /// Ensures that any changes made to a stream object that is open in transacted + /// mode are reflected in the parent storage. + /// + /// + /// A value that controls how the changes for the stream object are committed. + /// + /// + /// For more information, see the existing documentation for IStream::Commit in the MSDN library. + /// + public void Commit(int grfCommitFlags) + { + _Validate(); + _source.Flush(); + } + + /// + /// Copies a specified number of bytes from the current seek pointer in the + /// stream to the current seek pointer in another stream. + /// + /// + /// A reference to the destination stream. + /// + /// + /// The number of bytes to copy from the source stream. + /// + /// + /// On successful return, contains the actual number of bytes read from the source. + /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written + /// to this parameter on success.) + /// + /// + /// On successful return, contains the actual number of bytes written to the destination. + /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written + /// to this parameter on success.) + /// + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten) + { + Verify.IsNotNull(pstm, "pstm"); + + _Validate(); + + // Reasonbly sized buffer, don't try to copy large streams in bulk. + var buffer = new byte[4096]; + long cbWritten = 0; + + while (cbWritten < cb) + { + int cbRead = _source.Read(buffer, 0, buffer.Length); + if (0 == cbRead) + { + break; + } + + // COM documentation is a bit vague here whether NULL is valid for the third parameter. + // Going to assume it is, as most implementations I've seen treat it as optional. + // It's possible this will break on some IStream implementations. + pstm.Write(buffer, cbRead, IntPtr.Zero); + cbWritten += cbRead; + } + + if (IntPtr.Zero != pcbRead) + { + Marshal.WriteInt64(pcbRead, cbWritten); + } + + if (IntPtr.Zero != pcbWritten) + { + Marshal.WriteInt64(pcbWritten, cbWritten); + } + } + + /// + /// Restricts access to a specified range of bytes in the stream. + /// + /// + /// The byte offset for the beginning of the range. + /// + /// + /// The length of the range, in bytes, to restrict. + /// + /// + /// The requested restrictions on accessing the range. + /// + /// + /// For more information, see the existing documentation for IStream::LockRegion in the MSDN library. + /// This class doesn't implement LockRegion. A COMException is thrown if it is used. + /// + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)"), Obsolete("The method is not implemented", true)] + public void LockRegion(long libOffset, long cb, int dwLockType) + { + HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); + } + + /// + /// Reads a specified number of bytes from the stream object into memory starting at the current seek pointer. + /// + /// + /// When this method returns, contains the data read from the stream. This parameter is passed uninitialized. + /// + /// + /// The number of bytes to read from the stream object. + /// + /// + /// A pointer to a ULONG variable that receives the actual number of bytes read from the stream object. + /// + /// + /// For more information, see the existing documentation for ISequentialStream::Read in the MSDN library. + /// + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void Read(byte[] pv, int cb, IntPtr pcbRead) + { + _Validate(); + + int cbRead = _source.Read(pv, 0, cb); + + if (IntPtr.Zero != pcbRead) + { + Marshal.WriteInt32(pcbRead, cbRead); + } + } + + + /// + /// Discards all changes that have been made to a transacted stream since the last Commit call. + /// + /// + /// This class doesn't implement Revert. A COMException is thrown if it is used. + /// + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)"), Obsolete("The method is not implemented", true)] + public void Revert() + { + HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); + } + + /// + /// Changes the seek pointer to a new location relative to the beginning of the + /// stream, to the end of the stream, or to the current seek pointer. + /// + /// + /// The displacement to add to dwOrigin. + /// + /// + /// The origin of the seek. The origin can be the beginning of the file, the current seek pointer, or the end of the file. + /// + /// + /// On successful return, contains the offset of the seek pointer from the beginning of the stream. + /// (Note the native signature is to a ULARGE_INTEGER*, so 64 bits are written + /// to this parameter on success.) + /// + /// + /// For more information, see the existing documentation for IStream::Seek in the MSDN library. + /// + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition) + { + _Validate(); + + long position = _source.Seek(dlibMove, (SeekOrigin)dwOrigin); + + if (IntPtr.Zero != plibNewPosition) + { + Marshal.WriteInt64(plibNewPosition, position); + } + } + + /// + /// Changes the size of the stream object. + /// + /// + /// The new size of the stream as a number of bytes. + /// + /// + /// For more information, see the existing documentation for IStream::SetSize in the MSDN library. + /// + public void SetSize(long libNewSize) + { + _Validate(); + _source.SetLength(libNewSize); + } + + /// + /// Retrieves the STATSTG structure for this stream. + /// + /// + /// When this method returns, contains a STATSTG structure that describes this stream object. + /// This parameter is passed uninitialized. + /// + /// + /// Members in the STATSTG structure that this method does not return, thus saving some memory allocation operations. + /// + public void Stat(out STATSTG pstatstg, int grfStatFlag) + { + pstatstg = default(STATSTG); + _Validate(); + + pstatstg.type = STGTY_STREAM; + pstatstg.cbSize = _source.Length; + pstatstg.grfMode = STGM_READWRITE; + pstatstg.grfLocksSupported = LOCK_EXCLUSIVE; + } + + /// + /// Removes the access restriction on a range of bytes previously restricted with the LockRegion method. + /// + /// The byte offset for the beginning of the range. + /// + /// + /// The length, in bytes, of the range to restrict. + /// + /// + /// The access restrictions previously placed on the range. + /// + /// + /// For more information, see the existing documentation for IStream::UnlockRegion in the MSDN library. + /// This class doesn't implement UnlockRegion. A COMException is thrown if it is used. + /// + [SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Standard.HRESULT.ThrowIfFailed(System.String)")] + [Obsolete("The method is not implemented", true)] + public void UnlockRegion(long libOffset, long cb, int dwLockType) + { + HRESULT.STG_E_INVALIDFUNCTION.ThrowIfFailed("The method is not implemented."); + } + + /// + /// Writes a specified number of bytes into the stream object starting at the current seek pointer. + /// + /// + /// The buffer to write this stream to. + /// + /// + /// The number of bytes to write to the stream. + /// + /// + /// On successful return, contains the actual number of bytes written to the stream object. + /// If the caller sets this pointer to null, this method does not provide the actual number + /// of bytes written. + /// + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public void Write(byte[] pv, int cb, IntPtr pcbWritten) + { + _Validate(); + + _source.Write(pv, 0, cb); + + if (IntPtr.Zero != pcbWritten) + { + Marshal.WriteInt32(pcbWritten, cb); + } + } + + #endregion + + #region IDisposable Members + + /// + /// Releases resources controlled by this object. + /// + /// + /// Dispose can be called multiple times, but trying to use the object + /// after it has been disposed will generally throw ObjectDisposedExceptions. + /// + public void Dispose() + { + _source = null; + } + + #endregion + } + +#if CONSIDER_ADDING + /// + /// Wraps an existing stream in a read-only interface. The stream can still be modified externally. + /// + internal class ReadonlyStream : Stream + { + private Stream _stream; + + public ReadonlyStream(Stream source) + { + Verify.IsNotNull(source, "source"); + _stream = source; + } + + public override bool CanRead + { + get + { + return _stream.CanRead; + } + } + + public override bool CanSeek + { + get + { + return _stream.CanSeek; + } + } + + public override bool CanWrite + { + get + { + return false; + } + } + + public override void Flush() { } + + public override long Length + { + get + { + return _stream.Length; + } + } + + public override long Position + { + get + { + return _stream.Position; + } + set + { + _stream.Position = value; + } + } + + public override int Read(byte[] buffer, int offset, int count) + { + return _stream.Read(buffer, offset, count); + } + + public override long Seek(long offset, SeekOrigin origin) + { + return _stream.Seek(offset, origin); + } + + public override void SetLength(long value) + { + throw new NotSupportedException("The stream doesn't support modifications."); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException("The stream doesn't support modifications."); + } + + public override void Close() + { + base.Close(); + } + } + + /// + /// Wraps a string to provide read-only Stream semantics. + /// + internal class StringStream : Stream + { + private string _source; + private int _position; + + public StringStream(string source) + { + _source = source; + _position = 0; + } + + public override bool CanRead + { + get { return true; } + } + + public override bool CanSeek + { + get { return true; } + } + + public override bool CanWrite + { + get { return false; } + } + + public override void Flush() + { + throw new NotSupportedException(); + } + + public override long Length + { + get { return _source.Length * 2; } + } + + public override long Position + { + get + { + return _position; + } + set + { + Validate.BoundedInteger(0, (int)value, (int)Length + 1, "value"); + _position = (int)value; + } + } + + public override int Read(byte[] buffer, int offset, int count) + { + int cbRead = 0; + for (; cbRead < count; ++cbRead) + { + if (Length <= Position) + { + break; + } + buffer[offset + cbRead] = (byte)(0xFF & (_source[(int)Position / 2] >> ((0 == Position % 2) ? 0 : 8))); + ++Position; + } + return cbRead; + } + + public override long Seek(long offset, SeekOrigin origin) + { + switch (origin) + { + case SeekOrigin.Begin: + Position = offset; + break; + case SeekOrigin.Current: + Position += offset; + break; + case SeekOrigin.End: + Position = Length + offset; + break; + default: + throw new FormatException("Bad value for origin"); + } + return Position; + } + + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + } +#endif +} diff --git a/Microsoft.Windows.Shell/standard.net/Windows/Utilities.Windows.cs b/Microsoft.Windows.Shell/standard.net/Windows/Utilities.Windows.cs new file mode 100644 index 0000000..394eaf2 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Windows/Utilities.Windows.cs @@ -0,0 +1,108 @@ +namespace Standard +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.InteropServices; + + internal static partial class Utility + { + private static readonly Version _osVersion = Environment.OSVersion.Version; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDestroyIcon(ref IntPtr hicon) + { + IntPtr p = hicon; + hicon = IntPtr.Zero; + if (IntPtr.Zero != p) + { + NativeMethods.DestroyIcon(p); + } + } + + /// GDI's DeleteObject + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDeleteObject(ref IntPtr gdiObject) + { + IntPtr p = gdiObject; + gdiObject = IntPtr.Zero; + if (IntPtr.Zero != p) + { + NativeMethods.DeleteObject(p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDestroyWindow(ref IntPtr hwnd) + { + IntPtr p = hwnd; + hwnd = IntPtr.Zero; + if (NativeMethods.IsWindow(p)) + { + NativeMethods.DestroyWindow(p); + } + } + + /// GDI+'s DisposeImage + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SafeDisposeImage(ref IntPtr gdipImage) + { + IntPtr p = gdipImage; + gdipImage = IntPtr.Zero; + if (IntPtr.Zero != p) + { + NativeMethods.GdipDisposeImage(p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static void SafeCoTaskMemFree(ref IntPtr ptr) + { + IntPtr p = ptr; + ptr = IntPtr.Zero; + if (IntPtr.Zero != p) + { + Marshal.FreeCoTaskMem(p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static void SafeFreeHGlobal(ref IntPtr hglobal) + { + IntPtr p = hglobal; + hglobal = IntPtr.Zero; + if (IntPtr.Zero != p) + { + Marshal.FreeHGlobal(p); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public static void SafeRelease(ref T comObject) where T : class + { + T t = comObject; + comObject = default(T); + if (null != t) + { + Assert.IsTrue(Marshal.IsComObject(t)); + Marshal.ReleaseComObject(t); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsOSVistaOrNewer + { + get { return _osVersion >= new Version(6, 0); } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsOSWindows7OrNewer + { + get { return _osVersion >= new Version(6, 1); } + } + + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Windows/WicProvider.cs b/Microsoft.Windows.Shell/standard.net/Windows/WicProvider.cs new file mode 100644 index 0000000..7f8d366 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Windows/WicProvider.cs @@ -0,0 +1,717 @@ +// wincodec.idl +namespace Standard +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.ComTypes; + using System.Text; + using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME; + using STATSTG = System.Runtime.InteropServices.ComTypes.STATSTG; + + #region WIC Values + + internal static class WicValues + { + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public const uint WINCODEC_SDK_VERSION = 0x0236; + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid GUID_VendorMicrosoft = new Guid(0xf0e749ca, 0xedef, 0x4589, 0xa7, 0x3a, 0xee, 0xe, 0x62, 0x6a, 0x2a, 0x2b); + } + + /// + /// GUID Identifiers for the image container formats + /// + internal static class WicGUID + { + /// GUID_ContainerFormatBmp + public const string ContainerFormatBmp = "0af1d87e-fcfe-4188-bdeb-a7906471cbe3"; + /// GUID_ContainerFormatPng + public const string ContainerFormatPng = "1b7cfaf4-713f-473c-bbcd-6137425faeaf"; + /// GUID_ContainerFormatIco + public const string ContainerFormatIco = "a3a860c4-338f-4c17-919a-fba4b5628f21"; + /// GUID_ContainerFormatJpeg + public const string ContainerFormatJpeg = "19e4a5aa-5662-4fc5-a0c0-1758028e1057"; + /// GUID_ContainerFormatTiff + public const string ContainerFormatTiff = "163bcc30-e2e9-4f0b-961d-a3e9fdb788a3"; + /// GUID_ContainerFormatGif + public const string ContainerFormatGif = "1f8a5601-7d4d-4cbd-9c82-1bc8d4eeb9a5"; + /// GUID_ContainerFormatWmp + public const string ContainerFormatWmp = "57a37caa-367a-4540-916b-f183c5093a4b"; + } + + /// + /// WIC Category Identifiers + /// + internal static class WicCATID + { + /// CATID_WICBitmapDecoders + public const string WICBitmapDecoders = "7ed96837-96f0-4812-b211-f13c24117ed3"; + /// CATID_WICBitmapEncoders + public const string WICBitmapEncoders = "ac757296-3522-4e11-9862-c17be5a1767e"; + /// CATID_WICPixelFormats + public const string WICPixelFormats = "2b46e70f-cda7-473e-89f6-dc9630a2390b"; + /// CATID_WICFormatConverters + public const string WICFormatConverters = "7835eae8-bf14-49d1-93ce-533a407b2248"; + /// CATID_WICMetadataReader + public const string WICMetadataReader = "05af94d8-7174-4cd2-be4a-4124b80ee4b8"; + /// CATID_WICMetadataWriter + public const string WICMetadataWriter = "abe3b9a4-257d-4b97-bd1a-294af496222e"; + } + + internal static class WicCLSID + { + #region (WIC) GUID identifiers for the codecs + + /// CLSID_WICBmpDecoder + public const string WICBmpDecoder = "6b462062-7cbf-400d-9fdb-813dd10f2778"; + /// CLSID_WICPngDecoder + public const string WICPngDecoder = "389ea17b-5078-4cde-b6ef-25c15175c751"; + /// CLSID_WICIcoDecoder + public const string WICIcoDecoder = "c61bfcdf-2e0f-4aad-a8d7-e06bafebcdfe"; + /// CLSID_WICJpegDecoder + public const string WICJpegDecoder = "9456a480-e88b-43ea-9e73-0b2d9b71b1ca"; + /// CLSID_WICGifDecoder + public const string WICGifDecoder = "381dda3c-9ce9-4834-a23e-1f98f8fc52be"; + /// CLSID_WICTiffDecoder + public const string WICTiffDecoder = "b54e85d9-fe23-499f-8b88-6acea713752b"; + /// CLSID_WICWmpDecoder + public const string WICWmpDecoder = "a26cec36-234c-4950-ae16-e34aace71d0d"; + + /// CLSID_WICBmpEncoder + public const string WICBmpEncoder = "69be8bb4-d66d-47c8-865a-ed1589433782"; + /// CLSID_WICPngEncoder + public const string WICPngEncoder = "27949969-876a-41d7-9447-568f6a35a4dc"; + /// CLSID_WICJpegEncoder + public const string WICJpegEncoder = "1a34f5c1-4a5a-46dc-b644-1f4567e7a676"; + /// CLSID_WICGifEncoder + public const string WICGifEncoder = "114f5598-0b22-40a0-86a1-c83ea495adbd"; + /// CLSID_WICTiffEncoder + public const string WICTiffEncoder = "0131be10-2001-4c5f-a9b0-cc88fab64ce8"; + /// CLSID_WICWmpEncoder + public const string WICWmpEncoder = "ac4ce3cb-e1c1-44cd-8215-5a1665509ec2"; + + #endregion + + #region Category Identifiers + + /// CLSID_WICImagingCategories + public const string WICImagingCategories = "fae3d380-fea4-4623-8c75-c6b61110b681"; + + #endregion + + #region Format converters + + /// CLSID_WICDefaultFormatConverter + public const string WICDefaultFormatConverter = "1a3f11dc-b514-4b17-8c5f-2154513852f1"; + /// CLSID_WICFormatConverterNChannel + public const string WICFormatConverterNChannel = "c17cabb2-d4a3-47d7-a557-339b2efbd4f1"; + /// CLSID_WICFormatConverterWMPhoto + public const string WICFormatConverterWMPhoto = "9cb5172b-d600-46ba-ab77-77bb7e3a00d9"; + + #endregion + } + + /// Pixel format GUIDs. + internal static class WICPixelFormat + { + /* Undefined formats */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormatDontCare = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x00); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormatUndefined = WICPixelFormatDontCare; + + /* Indexed formats */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat1bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x01); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat2bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x02); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat4bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x03); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat8bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x04); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormatBlackWhite = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x05); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat2bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x06); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat4bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x07); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat8bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x08); + + /* sRGB formats (gamma is approx. 2.2) */ + /* For a full definition, see the sRGB spec */ + + /* 16bpp formats */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat16bppBGR555 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x09); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat16bppBGR565 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0a); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat16bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0b); + + /* 24bpp formats */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat24bppBGR = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat24bppRGB = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d); + + /* 32bpp format */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat32bppBGR = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0e); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat32bppBGRA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat32bppPBGRA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x10); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat32bppGrayFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x11); + + /* 48bpp format */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat48bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x12); + + /* scRGB formats. Gamma is 1.0 */ + /* For a full definition, see the scRGB spec */ + + /* 16bpp format */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat16bppGrayFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x13); + + /* 32bpp format */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat32bppBGR101010 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x14); + + /* 48bpp format */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat48bppRGB = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x15); + + /* 64bpp format */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat64bppRGBA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x16); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat64bppPRGBA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x17); + + /* 96bpp format */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat96bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x18); + + /* Floating point scRGB formats */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat128bppRGBAFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x19); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat128bppPRGBAFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1a); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat128bppRGBFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1b); + + /* CMYK formats. */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat32bppCMYK = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1c); + + /* Photon formats */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat64bppRGBAFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1d); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat64bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x40); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat128bppRGBAFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1e); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat128bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x41); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat64bppRGBAHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3a); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat64bppRGBHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x42); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat48bppRGBHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3b); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat32bppRGBE = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3d); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat16bppGrayHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3e); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat32bppGrayFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3f); + + /* More CMYK formats and n-Channel formats */ + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat64bppCMYK = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1f); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat24bpp3Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x20); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat32bpp4Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x21); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat40bpp5Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x22); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat48bpp6Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x23); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat56bpp7Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x24); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat64bpp8Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x25); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat48bpp3Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x26); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat64bpp4Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x27); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat80bpp5Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x28); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat96bpp6Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x29); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat112bpp7Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2a); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat128bpp8Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2b); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat40bppCMYKAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2c); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat80bppCMYKAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2d); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat32bpp3ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2e); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat40bpp4ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2f); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat48bpp5ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x30); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat56bpp6ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x31); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat64bpp7ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x32); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat72bpp8ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x33); + + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat64bpp3ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x34); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat80bpp4ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x35); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat96bpp5ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x36); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat112bpp6ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x37); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat128bpp7ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x38); + [SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public static readonly Guid WICPixelFormat144bpp8ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x39); + } + + [Flags] + internal enum WICComponentType : int + { + WICDecoder = 0x00000001, + WICEncoder = 0x00000002, + WICPixelFormatConverter = 0x00000004, + WICMetadataReader = 0x00000008, + WICMetadataWriter = 0x00000010, + WICPixelFormat = 0x00000020, + WICAllComponents = 0x0000003F, + } + + internal enum WICBitmapDitherType : int + { + None = 0x00000000, + Solid = 0x00000000, + Ordered4x4 = 0x00000001, + Ordered8x8 = 0x00000002, + Ordered16x16 = 0x00000003, + Spiral4x4 = 0x00000004, + Spiral8x8 = 0x00000005, + DualSpiral4x4 = 0x00000006, + DualSpiral8x8 = 0x00000007, + ErrorDiffusion = 0x00000008, + } + + /// WICDecodeMetadata*, WICDecodeOptions + internal enum WICDecodeMetadata : int + { + CacheOnDemand = 0x00000000, + CacheOnLoad = 0x00000001, + } + + [Flags] + internal enum WICComponentSigning : uint + { + WICComponentSigned = 0x00000001, + WICComponentUnsigned = 0x00000002, + WICComponentSafe = 0x00000004, + WICComponentDisabled = 0x80000000, + } + + /// + /// WICBitmapPaletteType* + /// + internal enum WICBitmapPaletteType + { + /// Arbitrary custom palette provided by caller. + Custom = 0x00000000, + /// Optimal palette generated using a median-cut algorithm. + MedianCut = 0x00000001, + /// Black and white palette. + FixedBW = 0x00000002, + + // Symmetric halftone palettes. + // Each of these halftone palettes will be a superset of the system palette. + // E.g. Halftone8 will have it's 8-color on-off primaries and the 16 system + // colors added. With duplicates removed, that leaves 16 colors. + + FixedHalftone8 = 0x00000003, // 8-color, on-off primaries + FixedHalftone27 = 0x00000004, // 3 intensity levels of each color + FixedHalftone64 = 0x00000005, // 4 intensity levels of each color + FixedHalftone125 = 0x00000006, // 5 intensity levels of each color + FixedHalftone216 = 0x00000007, // 6 intensity levels of each color + + /// convenient web palette, same as WICBitmapPaletteTypeFixedHalftone216 + FixedWebPalette = FixedHalftone216, + + // Assymetric halftone palettes. + // These are somewhat less useful than the symmetric ones, but are + // included for completeness. These do not include all of the system + // colors. + + FixedHalftone252 = 0x00000008, // 6-red, 7-green, 6-blue intensities + FixedHalftone256 = 0x00000009, // 8-red, 8-green, 4-blue intensities + + FixedGray4 = 0x0000000A,// 4 shades of gray + FixedGray16 = 0x0000000B,// 16 shades of gray + FixedGray256 = 0x0000000C,// 256 shades of gray + } + + /// + /// WICBitmapTransform*, WICBitmapTransformOptions + /// + internal enum WICBitmapTransform : int + { + Rotate0 = 0x00000000, + Rotate90 = 0x00000001, + Rotate180 = 0x00000002, + Rotate270 = 0x00000003, + FlipHorizontal = 0x00000008, + FlipVertical = 0x00000010, + } + + /// + /// WICBitmap* + /// + internal enum WICBitmapCreateCacheOption : int + { + NoCache = 0x00000000, + CacheOnDemand = 0x00000001, + CacheOnLoad = 0x00000002, + } + + /// + /// WICBitmap* + /// + internal enum WICBitmapAlphaChannelOption : int + { + UseAlpha = 0x00000000, + UsePremultipliedAlpha = 0x00000001, + IgnoreAlpha = 0x00000002, + } + + #endregion + + #region WIC Structures + + [StructLayout(LayoutKind.Sequential)] + internal struct WICRect + { + public int X; + public int Y; + public int Width; + public int Height; + } + + #endregion + + #region WIC Interfaces + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICBitmapDecoder), + ] + internal interface IWICBitmapDecoder + { + uint QueryCapability([In] IStream pIStream); + + void Initialize([In] IStream pIStream, WICDecodeMetadata cacheOptions); + + Guid GetContainerFormat(); + + // returns IWICBitmapDecoderInfo + IntPtr GetDecoderInfo(); + + void CopyPalette([In] /*IWICPalette*/ IntPtr pIPalette); + + // returns IWICMetadataQueryReader + IntPtr GetMetadataQueryReader(); + + // returns IWICBitmapSource + IntPtr GetPreview(); + + void GetColorContexts(int cCount, [In, Out] /*IWICColorContext*/ ref IntPtr ppIColorContexts, out int pcActualCount); + + // returns IWICBitmapSource + IntPtr GetThumbnail(); + + int GetFrameCount(); + + IWICBitmapFrameDecode GetFrame(int index); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICBitmapSource) + ] + internal interface IWICBitmapSource + { + void GetSize(out int puiWidth, out int puiHeight); + + Guid GetPixelFormat(); + + void GetResolution(out double pDpiX, out double pDpiY); + + void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); + + void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICFormatConverter) + ] + interface IWICFormatConverter : IWICBitmapSource + { + #region IWICBitmapSource redeclaration + new void GetSize(out int puiWidth, out int puiHeight); + new Guid GetPixelFormat(); + new void GetResolution(out double pDpiX, out double pDpiY); + new void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); + new void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); + #endregion + + void Initialize( + IWICBitmapSource pISource, + [In] ref Guid dstFormat, + WICBitmapDitherType dither, + IntPtr pIPalette, + double alphaThresholdPercent, + WICBitmapPaletteType paletteTranslate); + + [return: MarshalAs(UnmanagedType.Bool)] + bool CanConvert( + [In] ref Guid srcPixelFormat, + [In] ref Guid dstPixelFormat); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICBitmap) + ] + internal interface IWICBitmap : IWICBitmapSource + { + #region IWICBitmapSource redeclaration + new void GetSize(out int puiWidth, out int puiHeight); + new Guid GetPixelFormat(); + new void GetResolution(out double pDpiX, out double pDpiY); + new void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); + new void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); + #endregion + + // IWICBitmapLock + IntPtr Lock([In] ref WICRect prcLock, int flags); + + void SetPalette(IntPtr pIPalette); + + void SetResolution(double dpiX, double dpiY); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICBitmapFrameDecode) + ] + internal interface IWICBitmapFrameDecode : IWICBitmapSource + { + #region IWICBitmapSource redeclaration + new void GetSize(out int puiWidth, out int puiHeight); + new Guid GetPixelFormat(); + new void GetResolution(out double pDpiX, out double pDpiY); + new void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); + new void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); + #endregion + + // IWICMetadataQueryReader + IntPtr GetMetadataQueryReader(); + + void GetColorContexts(int cCount, [In, Out] ref IntPtr /*IWICColorContext*/ ppIColorContexts, out int pcActualCount); + + IWICBitmapSource GetThumbnail(); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICBitmapFlipRotator) + ] + internal interface IWICBitmapFlipRotator : IWICBitmapSource + { + #region IWICBitmapSource redeclaration + new void GetSize(out int puiWidth, out int puiHeight); + new Guid GetPixelFormat(); + new void GetResolution(out double pDpiX, out double pDpiY); + new void CopyPalette(IntPtr /*IWICPalette*/ pIPalette); + new void CopyPixels(ref WICRect prc, int cbStride, int cbBufferSize, [In, Out] IntPtr pbBuffer); + #endregion + + void Initialize(IWICBitmapSource pISource, WICBitmapTransform options); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICImagingFactory) + ] + internal interface IWICImagingFactory + { + IWICBitmapDecoder CreateDecoderFromFilename( + [MarshalAs(UnmanagedType.LPWStr)] string wzFileName, + [In] ref Guid pguidVendor, + uint dwDesiredAccess, + WICDecodeMetadata metadataOptions); + + IWICBitmapDecoder CreateDecoderFromStream( + [In] IStream pIStream, + [In] ref Guid pguidVendor, + WICDecodeMetadata metadataOptions); + + IWICBitmapDecoder CreateDecoderFromFileHandle( + IntPtr hFile, + [In] ref Guid pguidVendor, + WICDecodeMetadata metadataOptions); + + // returns IWICComponentInfo + IntPtr CreateComponentInfo([In] ref Guid clsidComponent); + + IWICBitmapDecoder CreateDecoder( + [In] ref Guid guidContainerFormat, + [In] ref Guid pguidVendor); + + // IWICBitmapEncoder + IntPtr CreateEncoder( + [In] ref Guid guidContainerFormat, + [In] ref Guid pguidVendor); + + // IWICPalette + IntPtr CreatePalette(); + + IWICFormatConverter CreateFormatConverter(); + + // IWICBitmapScaler + IntPtr CreateBitmapScaler(); + + // IWICBitmapClipper + IntPtr CreateBitmapClipper(); + + IWICBitmapFlipRotator CreateBitmapFlipRotator(); + + IWICStream CreateStream(); + + // IWICColorContext + IntPtr CreateColorContext(); + + // IWICColorTransform + IntPtr CreateColorTransformer(); + + /* Bitmap creation */ + + IWICBitmap CreateBitmap( + int uiWidth, + int uiHeight, + [In] ref Guid pixelFormat, + WICBitmapCreateCacheOption option); + + IWICBitmap CreateBitmapFromSource( + IWICBitmapSource pIBitmapSource, + WICBitmapCreateCacheOption option); + + IWICBitmap CreateBitmapFromSourceRect( + IWICBitmapSource pIBitmapSource, + int x, + int y, + int width, + int height); + + IWICBitmap CreateBitmapFromMemory( + int uiWidth, + int uiHeight, + [In] ref Guid pixelFormat, + int cbStride, + int cbBufferSize, + IntPtr pbBuffer); + + IWICBitmap CreateBitmapFromHBITMAP( + IntPtr hBitmap, + IntPtr hPalette, + WICBitmapAlphaChannelOption options); + + IWICBitmap CreateBitmapFromHICON(IntPtr hIcon); + + // IEnumUnknown + IntPtr CreateComponentEnumerator( + int componentTypes, // WICComponentType + int options); // WICComponentEnumerateOptions + + // IWICFastMetadataEncoder + IntPtr CreateFastMetadataEncoderFromDecoder(IWICBitmapDecoder pIDecoder); + + // IWICFastMetadataEncoder + IntPtr CreateFastMetadataEncoderFromFrameDecode(IntPtr pIFrameDecoder); + + // IWICMetadataQueryWriter + IntPtr CreateQueryWriter( + [In] ref Guid guidMetadataFormat, + [In] ref Guid pguidVendor); + + // IWICMetadataQueryWriter + IntPtr CreateQueryWriterFromReader( + IntPtr pIQueryReader, + [In] ref Guid pguidVendor); + } + + [ + ComImport, + InterfaceType(ComInterfaceType.InterfaceIsIUnknown), + Guid(IID.WICStream) + ] + internal interface IWICStream : IStream + { + #region IStream redeclaration + + new void Clone(out IStream ppstm); + new void Commit(int grfCommitFlags); + new void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten); + new void LockRegion(long libOffset, long cb, int dwLockType); + new void Read(byte[] pv, int cb, IntPtr pcbRead); + new void Revert(); + new void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition); + new void SetSize(long libNewSize); + new void Stat(out STATSTG pstatstg, int grfStatFlag); + new void UnlockRegion(long libOffset, long cb, int dwLockType); + new void Write(byte[] pv, int cb, IntPtr pcbWritten); + + #endregion + + void InitializeFromIStream(IStream pIStream); + void InitializeFromFilename([In, MarshalAs(UnmanagedType.LPWStr)] string wzFileName, int dwDesiredAccess); + void InitializeFromMemory(IntPtr pbBuffer, uint cbBufferSize); + void InitializeFromIStreamRegion(IStream pIStream, ulong ulOffset, ulong ulMaxSize); + } + + #endregion +} diff --git a/Microsoft.Windows.Shell/standard.net/Wpf/CornerRadiusAnimation.cs b/Microsoft.Windows.Shell/standard.net/Wpf/CornerRadiusAnimation.cs new file mode 100644 index 0000000..8f16495 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Wpf/CornerRadiusAnimation.cs @@ -0,0 +1,547 @@ +namespace Standard +{ + using System; + using System.Diagnostics; + using System.Windows; + using System.Windows.Media.Animation; + + internal enum AnimationType + { + Automatic, + FromTo, + FromBy, + From, + To, + By, + } + + /// + /// Animates the value of a CornerRadius property using linear interpolation + /// between two values. The values are determined by the combination of + /// From, To, or By values that are set on the animation. + /// + internal partial class CornerRadiusAnimation : CornerRadiusAnimationBase + { + #region Data + + /// + /// This is used if the user has specified From, To, and/or By values. + /// + private CornerRadius[] _keyValues; + + private AnimationType _animationType; + private bool _isAnimationFunctionValid; + + #endregion + + #region Constructors + + /// + /// Static ctor for CornerRadiusAnimation establishes + /// dependency properties, using as much shared data as possible. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] + static CornerRadiusAnimation() + { + Type typeofProp = typeof(CornerRadius?); + Type typeofThis = typeof(CornerRadiusAnimation); + PropertyChangedCallback propCallback = new PropertyChangedCallback(AnimationFunction_Changed); + ValidateValueCallback validateCallback = new ValidateValueCallback(ValidateFromToOrByValue); + + FromProperty = DependencyProperty.Register( + "From", + typeofProp, + typeofThis, + new PropertyMetadata((CornerRadius?)null, propCallback), + validateCallback); + + ToProperty = DependencyProperty.Register( + "To", + typeofProp, + typeofThis, + new PropertyMetadata((CornerRadius?)null, propCallback), + validateCallback); + + ByProperty = DependencyProperty.Register( + "By", + typeofProp, + typeofThis, + new PropertyMetadata((CornerRadius?)null, propCallback), + validateCallback); + + } + + + /// + /// Creates a new CornerRadiusAnimation with all properties set to + /// their default values. + /// + public CornerRadiusAnimation() + : base() + { + } + + /// + /// Creates a new CornerRadiusAnimation that will animate a + /// CornerRadius property from its base value to the value specified + /// by the "toValue" parameter of this constructor. + /// + public CornerRadiusAnimation(CornerRadius toValue, Duration duration) + : this() + { + To = toValue; + Duration = duration; + } + + /// + /// Creates a new CornerRadiusAnimation that will animate a + /// CornerRadius property from its base value to the value specified + /// by the "toValue" parameter of this constructor. + /// + public CornerRadiusAnimation(CornerRadius toValue, Duration duration, FillBehavior fillBehavior) + : this() + { + To = toValue; + Duration = duration; + FillBehavior = fillBehavior; + } + + /// + /// Creates a new CornerRadiusAnimation that will animate a + /// CornerRadius property from the "fromValue" parameter of this constructor + /// to the "toValue" parameter. + /// + public CornerRadiusAnimation(CornerRadius fromValue, CornerRadius toValue, Duration duration) + : this() + { + From = fromValue; + To = toValue; + Duration = duration; + } + + /// + /// Creates a new CornerRadiusAnimation that will animate a + /// CornerRadius property from the "fromValue" parameter of this constructor + /// to the "toValue" parameter. + /// + public CornerRadiusAnimation(CornerRadius fromValue, CornerRadius toValue, Duration duration, FillBehavior fillBehavior) + : this() + { + From = fromValue; + To = toValue; + Duration = duration; + FillBehavior = fillBehavior; + } + + #endregion + + #region Freezable + + /// + /// Creates a copy of this CornerRadiusAnimation + /// + /// The copy + public new CornerRadiusAnimation Clone() + { + return (CornerRadiusAnimation)base.Clone(); + } + + // + // Note that we don't override the Clone virtuals (CloneCore, CloneCurrentValueCore, + // GetAsFrozenCore, and GetCurrentValueAsFrozenCore) even though this class has state + // not stored in a DP. + // + // We don't need to clone _animationType and _keyValues because they are the the cached + // results of animation function validation, which can be recomputed. The other remaining + // field, isAnimationFunctionValid, defaults to false, which causes this recomputation to happen. + // + + /// + /// Implementation of Freezable.CreateInstanceCore. + /// + /// The new Freezable. + protected override Freezable CreateInstanceCore() + { + return new CornerRadiusAnimation(); + } + + #endregion + + #region Methods + + /// + /// Calculates the value this animation believes should be the current value for the property. + /// + /// + /// This value is the suggested origin value provided to the animation + /// to be used if the animation does not have its own concept of a + /// start value. If this animation is the first in a composition chain + /// this value will be the snapshot value if one is available or the + /// base property value if it is not; otherise this value will be the + /// value returned by the previous animation in the chain with an + /// animationClock that is not Stopped. + /// + /// + /// This value is the suggested destination value provided to the animation + /// to be used if the animation does not have its own concept of an + /// end value. This value will be the base value if the animation is + /// in the first composition layer of animations on a property; + /// otherwise this value will be the output value from the previous + /// composition layer of animations for the property. + /// + /// + /// This is the animationClock which can generate the CurrentTime or + /// CurrentProgress value to be used by the animation to generate its + /// output value. + /// + /// + /// The value this animation believes should be the current value for the property. + /// + protected override CornerRadius GetCurrentValueCore(CornerRadius defaultOriginValue, CornerRadius defaultDestinationValue, AnimationClock animationClock) + { + Debug.Assert(animationClock.CurrentState != ClockState.Stopped); + + if (!_isAnimationFunctionValid) + { + ValidateAnimationFunction(); + } + + double progress = animationClock.CurrentProgress.Value; + + CornerRadius from = new CornerRadius(); + CornerRadius to = new CornerRadius(); + CornerRadius accumulated = new CornerRadius(); + CornerRadius foundation = new CornerRadius(); + + // need to validate the default origin and destination values if + // the animation uses them as the from, to, or foundation values + bool validateOrigin = false; + bool validateDestination = false; + + switch(_animationType) + { + case AnimationType.Automatic: + + from = defaultOriginValue; + to = defaultDestinationValue; + + validateOrigin = true; + validateDestination = true; + + break; + + case AnimationType.From: + + from = _keyValues[0]; + to = defaultDestinationValue; + + validateDestination = true; + + break; + + case AnimationType.To: + + from = defaultOriginValue; + to = _keyValues[0]; + + validateOrigin = true; + + break; + + case AnimationType.By: + + // According to the SMIL specification, a By animation is + // always additive. But we don't force this so that a + // user can re-use a By animation and have it replace the + // animations that precede it in the list without having + // to manually set the From value to the base value. + + to = _keyValues[0]; + foundation = defaultOriginValue; + + validateOrigin = true; + + break; + + case AnimationType.FromTo: + + from = _keyValues[0]; + to = _keyValues[1]; + + if (IsAdditive) + { + foundation = defaultOriginValue; + validateOrigin = true; + } + + break; + + case AnimationType.FromBy: + + from = _keyValues[0]; + to = _AddCornerRadius(_keyValues[0], _keyValues[1]); + + if (IsAdditive) + { + foundation = defaultOriginValue; + validateOrigin = true; + } + + break; + + default: + + Debug.Fail("Unknown animation type."); + + break; + } + + if (validateOrigin + && !_IsValidAnimationValueCornerRadius(defaultOriginValue)) + { + throw new InvalidOperationException(); + } + + if (validateDestination + && !_IsValidAnimationValueCornerRadius(defaultDestinationValue)) + { + throw new InvalidOperationException(); + } + + + if (IsCumulative) + { + double currentRepeat = (double)(animationClock.CurrentIteration - 1); + + if (currentRepeat > 0.0) + { + CornerRadius accumulator = _SubtractCornerRadius(to, from); + + accumulated = _ScaleCornerRadius(accumulator, currentRepeat); + } + } + + // return foundation + accumulated + from + ((to - from) * progress) + + return _AddCornerRadius( + foundation, + _AddCornerRadius( + accumulated, + _InterpolateCornerRadius(from, to, progress))); + } + + private CornerRadius _InterpolateCornerRadius(CornerRadius from, CornerRadius to, double progress) + { + return this._ScaleCornerRadius(this._SubtractCornerRadius(to, from), progress); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")] + private CornerRadius _ScaleCornerRadius(CornerRadius first, double currentRepeat) + { + return new CornerRadius( + first.TopLeft * currentRepeat, + first.TopRight * currentRepeat, + first.BottomRight * currentRepeat, + first.BottomLeft * currentRepeat); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")] + private CornerRadius _SubtractCornerRadius(CornerRadius first, CornerRadius second) + { + return new CornerRadius( + first.TopLeft - second.TopLeft, + first.TopRight - second.TopRight, + first.BottomRight - second.BottomRight, + first.BottomLeft - second.BottomLeft); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "defaultOriginValue")] + private static bool _IsValidAnimationValueCornerRadius(CornerRadius defaultOriginValue) + { + return true; + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")] + private CornerRadius _AddCornerRadius(CornerRadius first, CornerRadius second) + { + return new CornerRadius( + first.TopLeft + second.TopLeft, + first.TopRight + second.TopRight, + first.BottomRight + second.BottomRight, + first.BottomLeft + second.BottomLeft); + } + + private void ValidateAnimationFunction() + { + _animationType = AnimationType.Automatic; + _keyValues = null; + + if (From.HasValue) + { + if (To.HasValue) + { + _animationType = AnimationType.FromTo; + _keyValues = new CornerRadius[2]; + _keyValues[0] = From.Value; + _keyValues[1] = To.Value; + } + else if (By.HasValue) + { + _animationType = AnimationType.FromBy; + _keyValues = new CornerRadius[2]; + _keyValues[0] = From.Value; + _keyValues[1] = By.Value; + } + else + { + _animationType = AnimationType.From; + _keyValues = new CornerRadius[1]; + _keyValues[0] = From.Value; + } + } + else if (To.HasValue) + { + _animationType = AnimationType.To; + _keyValues = new CornerRadius[1]; + _keyValues[0] = To.Value; + } + else if (By.HasValue) + { + _animationType = AnimationType.By; + _keyValues = new CornerRadius[1]; + _keyValues[0] = By.Value; + } + + _isAnimationFunctionValid = true; + } + + #endregion + + #region Properties + + private static void AnimationFunction_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + CornerRadiusAnimation a = (CornerRadiusAnimation)d; + + a._isAnimationFunctionValid = false; + //a.PropertyChanged(e.Property); + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "dependencyProperty"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")] + private void PropertyChanged(DependencyProperty dependencyProperty) + { + //throw new NotImplementedException(); + } + + private static bool ValidateFromToOrByValue(object value) + { + CornerRadius? typedValue = (CornerRadius?)value; + + if (typedValue.HasValue) + { + return _IsValidAnimationValueCornerRadius(typedValue.Value); + } + else + { + return true; + } + } + + /// + /// FromProperty + /// + public static readonly DependencyProperty FromProperty; + + /// + /// From + /// + public CornerRadius? From + { + get + { + return (CornerRadius?)GetValue(FromProperty); + } + set + { + SetValue(FromProperty, value); + } + } + + /// + /// ToProperty + /// + public static readonly DependencyProperty ToProperty; + + /// + /// To + /// + public CornerRadius? To + { + get + { + return (CornerRadius?)GetValue(ToProperty); + } + set + { + SetValue(ToProperty, value); + } + } + + /// + /// ByProperty + /// + public static readonly DependencyProperty ByProperty; + + /// + /// By + /// + public CornerRadius? By + { + get + { + return (CornerRadius?)GetValue(ByProperty); + } + set + { + SetValue(ByProperty, value); + } + } + + + /// + /// If this property is set to true the animation will add its value to + /// the base value instead of replacing it entirely. + /// + public bool IsAdditive + { + get + { + return (bool)GetValue(IsAdditiveProperty); + } + set + { + SetValue(IsAdditiveProperty, value); + } + } + + /// + /// It this property is set to true, the animation will accumulate its + /// value over repeats. For instance if you have a From value of 0.0 and + /// a To value of 1.0, the animation return values from 1.0 to 2.0 over + /// the second reteat cycle, and 2.0 to 3.0 over the third, etc. + /// + public bool IsCumulative + { + get + { + return (bool)GetValue(IsCumulativeProperty); + } + set + { + SetValue(IsCumulativeProperty, value); + } + } + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Wpf/CornerRadiusAnimationBase.cs b/Microsoft.Windows.Shell/standard.net/Wpf/CornerRadiusAnimationBase.cs new file mode 100644 index 0000000..cd04245 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Wpf/CornerRadiusAnimationBase.cs @@ -0,0 +1,191 @@ +namespace Standard +{ + using System; + using System.Windows; + using System.Windows.Media.Animation; + + internal abstract class CornerRadiusAnimationBase : AnimationTimeline + { + #region Constructors + + /// + /// Creates a new CornerRadiusAnimationBase. + /// + protected CornerRadiusAnimationBase() + : base() + { + } + + #endregion + + #region Freezable + + /// + /// Creates a copy of this CornerRadiusAnimationBase + /// + /// The copy + public new CornerRadiusAnimationBase Clone() + { + return (CornerRadiusAnimationBase)base.Clone(); + } + + #endregion + + #region IAnimation + + /// + /// Calculates the value this animation believes should be the current value for the property. + /// + /// + /// This value is the suggested origin value provided to the animation + /// to be used if the animation does not have its own concept of a + /// start value. If this animation is the first in a composition chain + /// this value will be the snapshot value if one is available or the + /// base property value if it is not; otherise this value will be the + /// value returned by the previous animation in the chain with an + /// animationClock that is not Stopped. + /// + /// + /// This value is the suggested destination value provided to the animation + /// to be used if the animation does not have its own concept of an + /// end value. This value will be the base value if the animation is + /// in the first composition layer of animations on a property; + /// otherwise this value will be the output value from the previous + /// composition layer of animations for the property. + /// + /// + /// This is the animationClock which can generate the CurrentTime or + /// CurrentProgress value to be used by the animation to generate its + /// output value. + /// + /// + /// The value this animation believes should be the current value for the property. + /// + public override sealed object GetCurrentValue(object defaultOriginValue, object defaultDestinationValue, AnimationClock animationClock) + { + // Verify that object arguments are non-null since we are a value type + if (defaultOriginValue == null) + { + throw new ArgumentNullException("defaultOriginValue"); + } + if (defaultDestinationValue == null) + { + throw new ArgumentNullException("defaultDestinationValue"); + } + return GetCurrentValue((CornerRadius)defaultOriginValue, (CornerRadius)defaultDestinationValue, animationClock); + } + + /// + /// Returns the type of the target property + /// + public override sealed Type TargetPropertyType + { + get + { + ReadPreamble(); + + return typeof(CornerRadius); + } + } + + #endregion + + #region Methods + + + /// + /// Calculates the value this animation believes should be the current value for the property. + /// + /// + /// This value is the suggested origin value provided to the animation + /// to be used if the animation does not have its own concept of a + /// start value. If this animation is the first in a composition chain + /// this value will be the snapshot value if one is available or the + /// base property value if it is not; otherise this value will be the + /// value returned by the previous animation in the chain with an + /// animationClock that is not Stopped. + /// + /// + /// This value is the suggested destination value provided to the animation + /// to be used if the animation does not have its own concept of an + /// end value. This value will be the base value if the animation is + /// in the first composition layer of animations on a property; + /// otherwise this value will be the output value from the previous + /// composition layer of animations for the property. + /// + /// + /// This is the animationClock which can generate the CurrentTime or + /// CurrentProgress value to be used by the animation to generate its + /// output value. + /// + /// + /// The value this animation believes should be the current value for the property. + /// + public CornerRadius GetCurrentValue(CornerRadius defaultOriginValue, CornerRadius defaultDestinationValue, AnimationClock animationClock) + { + ReadPreamble(); + + if (animationClock == null) + { + throw new ArgumentNullException("animationClock"); + } + + // We check for null above but presharp doesn't notice so we suppress the + // warning here. + + //#pragma warning suppress 6506 + if (animationClock.CurrentState == ClockState.Stopped) + { + return defaultDestinationValue; + } + + /* + if (!AnimatedTypeHelpers.IsValidAnimationValueCornerRadius(defaultDestinationValue)) + { + throw new ArgumentException( + SR.Get( + SRID.Animation_InvalidBaseValue, + defaultDestinationValue, + defaultDestinationValue.GetType(), + GetType()), + "defaultDestinationValue"); + } + */ + + return GetCurrentValueCore(defaultOriginValue, defaultDestinationValue, animationClock); + } + + + /// + /// Calculates the value this animation believes should be the current value for the property. + /// + /// + /// This value is the suggested origin value provided to the animation + /// to be used if the animation does not have its own concept of a + /// start value. If this animation is the first in a composition chain + /// this value will be the snapshot value if one is available or the + /// base property value if it is not; otherise this value will be the + /// value returned by the previous animation in the chain with an + /// animationClock that is not Stopped. + /// + /// + /// This value is the suggested destination value provided to the animation + /// to be used if the animation does not have its own concept of an + /// end value. This value will be the base value if the animation is + /// in the first composition layer of animations on a property; + /// otherwise this value will be the output value from the previous + /// composition layer of animations for the property. + /// + /// + /// This is the animationClock which can generate the CurrentTime or + /// CurrentProgress value to be used by the animation to generate its + /// output value. + /// + /// + /// The value this animation believes should be the current value for the property. + /// + protected abstract CornerRadius GetCurrentValueCore(CornerRadius defaultOriginValue, CornerRadius defaultDestinationValue, AnimationClock animationClock); + + #endregion + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Wpf/DpiHelper.cs b/Microsoft.Windows.Shell/standard.net/Wpf/DpiHelper.cs new file mode 100644 index 0000000..4de8ed7 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Wpf/DpiHelper.cs @@ -0,0 +1,95 @@ +namespace Standard +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Windows; + using System.Windows.Media; + + internal static class DpiHelper + { + private static Matrix _transformToDevice; + private static Matrix _transformToDip; + + [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")] + static DpiHelper() + { + using (SafeDC desktop = SafeDC.GetDesktop()) + { + // Can get these in the static constructor. They shouldn't vary window to window, + // and changing the system DPI requires a restart. + int pixelsPerInchX = NativeMethods.GetDeviceCaps(desktop, DeviceCap.LOGPIXELSX); + int pixelsPerInchY = NativeMethods.GetDeviceCaps(desktop, DeviceCap.LOGPIXELSY); + + _transformToDip = Matrix.Identity; + _transformToDip.Scale(96d / (double)pixelsPerInchX, 96d / (double)pixelsPerInchY); + _transformToDevice = Matrix.Identity; + _transformToDevice.Scale((double)pixelsPerInchX / 96d, (double)pixelsPerInchY / 96d); + } + } + + /// + /// Convert a point in device independent pixels (1/96") to a point in the system coordinates. + /// + /// A point in the logical coordinate system. + /// Returns the parameter converted to the system's coordinates. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Point LogicalPixelsToDevice(Point logicalPoint) + { + return _transformToDevice.Transform(logicalPoint); + } + + /// + /// Convert a point in system coordinates to a point in device independent pixels (1/96"). + /// + /// A point in the physical coordinate system. + /// Returns the parameter converted to the device independent coordinate system. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Point DevicePixelsToLogical(Point devicePoint) + { + return _transformToDip.Transform(devicePoint); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Rect LogicalRectToDevice(Rect logicalRectangle) + { + Point topLeft = LogicalPixelsToDevice(new Point(logicalRectangle.Left, logicalRectangle.Top)); + Point bottomRight = LogicalPixelsToDevice(new Point(logicalRectangle.Right, logicalRectangle.Bottom)); + + return new Rect(topLeft, bottomRight); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Rect DeviceRectToLogical(Rect deviceRectangle) + { + Point topLeft = DevicePixelsToLogical(new Point(deviceRectangle.Left, deviceRectangle.Top)); + Point bottomRight = DevicePixelsToLogical(new Point(deviceRectangle.Right, deviceRectangle.Bottom)); + + return new Rect(topLeft, bottomRight); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Size LogicalSizeToDevice(Size logicalSize) + { + Point pt = LogicalPixelsToDevice(new Point(logicalSize.Width, logicalSize.Height)); + + return new Size { Width = pt.X, Height = pt.Y }; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Size DeviceSizeToLogical(Size deviceSize) + { + Point pt = DevicePixelsToLogical(new Point(deviceSize.Width, deviceSize.Height)); + + return new Size(pt.X, pt.Y); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Thickness LogicalThicknessToDevice(Thickness logicalThickness) + { + Point topLeft = LogicalPixelsToDevice(new Point(logicalThickness.Left, logicalThickness.Top)); + Point bottomRight = LogicalPixelsToDevice(new Point(logicalThickness.Right, logicalThickness.Bottom)); + + return new Thickness(topLeft.X, topLeft.Y, bottomRight.X, bottomRight.Y); + } + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Wpf/GlassHelper.cs b/Microsoft.Windows.Shell/standard.net/Wpf/GlassHelper.cs new file mode 100644 index 0000000..910613c --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Wpf/GlassHelper.cs @@ -0,0 +1,290 @@ +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.Windows; + using System.Windows.Interop; + using System.Windows.Media; + + internal class GlassHelper + { + // Test Notes: + // Things to manually verify when making changes to this class. + // * Do modified windows look correct in non-composited themes? + // * Does changing the theme back and forth leave the window in a visually ugly state? + // * Does it matter which theme was used first? + // * Does glass extension work properly in high-dpi? + // * Which of SetWindowThemeAttribute and ExtendGlassFrame are set first shouldn't matter. + // The hooks injected by one should not block the hooks of the other. + // * Do captions and icons always show up when composition is disabled? + // + // There are not automated unit tests for this class ( Boo!!! :( ) + // Be careful not to break things... + + private static readonly Dictionary _extendedWindows = new Dictionary(); + + // TODO: + // Verify that this really is sufficient. There are DWMWINDOWATTRIBUTEs as well, so this may + // be able to be turned off on a per-HWND basis, but I never see comments about that online... + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsCompositionEnabled + { + get + { + if (!Utility.IsOSVistaOrNewer) + { + return false; + } + + return NativeMethods.DwmIsCompositionEnabled(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool ExtendGlassFrameComplete(Window window) + { + return ExtendGlassFrame(window, new Thickness(-1)); + } + + /// + /// Extends the glass frame of a window. Only works on operating systems that support composition. + /// + /// The window to modify. + /// The margins of the new frame. + /// Whether the frame was successfully extended. + /// + /// This function adds hooks to the Window to respond to changes to whether composition is enabled. + /// + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool ExtendGlassFrame(Window window, Thickness margin) + { + Verify.IsNotNull(window, "window"); + + window.VerifyAccess(); + + IntPtr hwnd = new WindowInteropHelper(window).Handle; + + if (_extendedWindows.ContainsKey(hwnd)) + { + // The hook into the HWND's WndProc has the original margin cached. + // Don't want to support dynamically adjusting that unless there's a need. + throw new InvalidOperationException("Multiple calls to this function for the same Window are not supported."); + } + + return _ExtendGlassFrameInternal(window, margin); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static bool _ExtendGlassFrameInternal(Window window, Thickness margin) + { + Assert.IsNotNull(window); + Assert.IsTrue(window.CheckAccess()); + + // Expect that this might be called on OSes other than Vista. + if (!Utility.IsOSVistaOrNewer) + { + // Not an error. Just not on Vista so we're not going to get glass. + return false; + } + + IntPtr hwnd = new WindowInteropHelper(window).Handle; + if (IntPtr.Zero == hwnd) + { + throw new InvalidOperationException("Window must be shown before extending glass."); + } + + HwndSource hwndSource = HwndSource.FromHwnd(hwnd); + + bool isGlassEnabled = NativeMethods.DwmIsCompositionEnabled(); + + if (!isGlassEnabled) + { + window.Background = SystemColors.WindowBrush; + hwndSource.CompositionTarget.BackgroundColor = SystemColors.WindowColor; + } + else + { + // Apply the transparent background to both the Window and the HWND + window.Background = Brushes.Transparent; + hwndSource.CompositionTarget.BackgroundColor = Colors.Transparent; + + // Thickness is going to be DIPs, need to convert to system coordinates. + Point deviceTopLeft = DpiHelper.LogicalPixelsToDevice(new Point(margin.Left, margin.Top)); + Point deviceBottomRight = DpiHelper.LogicalPixelsToDevice(new Point(margin.Right, margin.Bottom)); + + var dwmMargin = new MARGINS + { + // err on the side of pushing in glass an extra pixel. + cxLeftWidth = (int)Math.Ceiling(deviceTopLeft.X), + cxRightWidth = (int)Math.Ceiling(deviceBottomRight.X), + cyTopHeight = (int)Math.Ceiling(deviceTopLeft.Y), + cyBottomHeight = (int)Math.Ceiling(deviceBottomRight.Y), + }; + + NativeMethods.DwmExtendFrameIntoClientArea(hwnd, ref dwmMargin); + } + + // Even if glass isn't currently enabled, add the hook so we can appropriately respond + // if that changes. + + bool addHook = !_extendedWindows.ContainsKey(hwnd); + + if (addHook) + { + HwndSourceHook hook = delegate(IntPtr innerHwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + if (WM.DWMCOMPOSITIONCHANGED == (WM)msg) + { + _ExtendGlassFrameInternal(window, margin); + handled = false; + } + return IntPtr.Zero; + }; + + _extendedWindows.Add(hwnd, hook); + hwndSource.AddHook(hook); + window.Closing += _OnExtendedWindowClosing; + } + + return isGlassEnabled; + } + + /// + /// Handler for the Closing event on a Window with an extended glass frame. + /// + /// The source of the event. + /// The instance containing the event data. + /// + /// When a Window with an extended glass frame closes, removes any local references to it. + /// + // BUGBUG: Doesn't handle if the Closing gets canceled. + static void _OnExtendedWindowClosing(object sender, CancelEventArgs e) + { + var window = sender as Window; + Assert.IsNotNull(window); + + IntPtr hwnd = new WindowInteropHelper(window).Handle; + + // We use the Closing rather than the Closed event to ensure that we can get this value. + Assert.AreNotEqual(IntPtr.Zero, hwnd); + + HwndSource hwndSource = HwndSource.FromHwnd(hwnd); + + Assert.IsTrue(_extendedWindows.ContainsKey(hwnd)); + + hwndSource.RemoveHook(_extendedWindows[hwnd]); + _extendedWindows.Remove(hwnd); + + window.Closing -= _OnExtendedWindowClosing; + } + + private static readonly Dictionary _attributedWindows = new Dictionary(); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool SetWindowThemeAttribute(Window window, bool showCaption, bool showIcon) + { + Verify.IsNotNull(window, "window"); + + window.VerifyAccess(); + + IntPtr hwnd = new WindowInteropHelper(window).Handle; + + if (_attributedWindows.ContainsKey(hwnd)) + { + // The hook into the HWND's WndProc has the original settings cached. + // Don't want to support dynamically adjusting that unless there's a need. + throw new InvalidOperationException("Multiple calls to this function for the same Window are not supported."); + } + + return _SetWindowThemeAttribute(window, showCaption, showIcon); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static bool _SetWindowThemeAttribute(Window window, bool showCaption, bool showIcon) + { + bool isGlassEnabled; + + Assert.IsNotNull(window); + Assert.IsTrue(window.CheckAccess()); + + // This only is expected to work if Aero glass is enabled. + try + { + isGlassEnabled = NativeMethods.DwmIsCompositionEnabled(); + } + catch (DllNotFoundException) + { + // Not an error. Just not on Vista so we're not going to get glass. + return false; + } + + IntPtr hwnd = new WindowInteropHelper(window).Handle; + if (IntPtr.Zero == hwnd) + { + throw new InvalidOperationException("Window must be shown before we can modify attributes."); + } + + var options = new WTA_OPTIONS + { + dwMask = (WTNCA.NODRAWCAPTION | WTNCA.NODRAWICON) + }; + if (isGlassEnabled) + { + if (!showCaption) + { + options.dwFlags |= WTNCA.NODRAWCAPTION; + } + if (!showIcon) + { + options.dwFlags |= WTNCA.NODRAWICON; + } + } + + NativeMethods.SetWindowThemeAttribute(hwnd, WINDOWTHEMEATTRIBUTETYPE.WTA_NONCLIENT, ref options, WTA_OPTIONS.Size); + + bool addHook = !_attributedWindows.ContainsKey(hwnd); + + if (addHook) + { + HwndSourceHook hook = delegate(IntPtr unusedHwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) + { + if (WM.DWMCOMPOSITIONCHANGED == (WM)msg) + { + _SetWindowThemeAttribute(window, showCaption, showIcon); + handled = false; + } + return IntPtr.Zero; + }; + + _attributedWindows.Add(hwnd, hook); + HwndSource.FromHwnd(hwnd).AddHook(hook); + window.Closing += _OnAttributedWindowClosing; + } + + return isGlassEnabled; + } + + static void _OnAttributedWindowClosing(object sender, CancelEventArgs e) + { + var window = sender as Window; + Assert.IsNotNull(window); + + IntPtr hwnd = new WindowInteropHelper(window).Handle; + + // We use the Closing rather than the Closed event to ensure that we can get this value. + Assert.AreNotEqual(IntPtr.Zero, hwnd); + + HwndSource hwndSource = HwndSource.FromHwnd(hwnd); + + Assert.IsTrue(_attributedWindows.ContainsKey(hwnd)); + + hwndSource.RemoveHook(_attributedWindows[hwnd]); + _attributedWindows.Remove(hwnd); + + window.Closing -= _OnExtendedWindowClosing; + } + + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Wpf/MessageWindow.cs b/Microsoft.Windows.Shell/standard.net/Wpf/MessageWindow.cs new file mode 100644 index 0000000..23a1b4a --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Wpf/MessageWindow.cs @@ -0,0 +1,166 @@ +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.InteropServices; + using System.Windows; + using System.Windows.Threading; + + internal sealed class MessageWindow : DispatcherObject, IDisposable + { + // Alias this to a static so the wrapper doesn't get GC'd + private static readonly WndProc s_WndProc = new WndProc(_WndProc); + private static readonly Dictionary s_windowLookup = new Dictionary(); + + private WndProc _wndProcCallback; + private string _className; + private bool _isDisposed; + + public IntPtr Handle { get; private set; } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] + public MessageWindow(CS classStyle, WS style, WS_EX exStyle, Rect location, string name, WndProc callback) + { + // A null callback means just use DefWindowProc. + _wndProcCallback = callback; + _className = "MessageWindowClass+" + Guid.NewGuid().ToString(); + + var wc = new WNDCLASSEX + { + cbSize = Marshal.SizeOf(typeof(WNDCLASSEX)), + style = classStyle, + lpfnWndProc = s_WndProc, + hInstance = NativeMethods.GetModuleHandle(null), + hbrBackground = NativeMethods.GetStockObject(StockObject.NULL_BRUSH), + lpszMenuName = "", + lpszClassName = _className, + }; + + NativeMethods.RegisterClassEx(ref wc); + + GCHandle gcHandle = default(GCHandle); + try + { + gcHandle = GCHandle.Alloc(this); + IntPtr pinnedThisPtr = (IntPtr)gcHandle; + + Handle = NativeMethods.CreateWindowEx( + exStyle, + _className, + name, + style, + (int)location.X, + (int)location.Y, + (int)location.Width, + (int)location.Height, + IntPtr.Zero, + IntPtr.Zero, + IntPtr.Zero, + pinnedThisPtr); + } + finally + { + gcHandle.Free(); + } + } + + ~MessageWindow() + { + _Dispose(false, false); + } + + public void Dispose() + { + _Dispose(true, false); + GC.SuppressFinalize(this); + } + + // This isn't right if the Dispatcher has already started shutting down. + // The HWND itself will get cleaned up on thread completion, but it will wind up leaking the class ATOM... + [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disposing")] + private void _Dispose(bool disposing, bool isHwndBeingDestroyed) + { + if (_isDisposed) + { + // Block against reentrancy. + return; + } + + _isDisposed = true; + + IntPtr hwnd = Handle; + string className = _className; + + if (isHwndBeingDestroyed) + { + Dispatcher.BeginInvoke(DispatcherPriority.Normal, (DispatcherOperationCallback)(arg => _DestroyWindow(IntPtr.Zero, className))); + } + else if (Handle != IntPtr.Zero) + { + if (CheckAccess()) + { + _DestroyWindow(hwnd, className); + } + else + { + Dispatcher.BeginInvoke(DispatcherPriority.Normal, (DispatcherOperationCallback)(arg => _DestroyWindow(hwnd, className))); + } + } + + s_windowLookup.Remove(hwnd); + + _className = null; + Handle = IntPtr.Zero; + } + + [SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly")] + private static IntPtr _WndProc(IntPtr hwnd, WM msg, IntPtr wParam, IntPtr lParam) + { + IntPtr ret = IntPtr.Zero; + MessageWindow hwndWrapper = null; + + if (msg == WM.CREATE) + { + var createStruct = (CREATESTRUCT)Marshal.PtrToStructure(lParam, typeof(CREATESTRUCT)); + GCHandle gcHandle = GCHandle.FromIntPtr(createStruct.lpCreateParams); + hwndWrapper = (MessageWindow)gcHandle.Target; + s_windowLookup.Add(hwnd, hwndWrapper); + } + else + { + if (!s_windowLookup.TryGetValue(hwnd, out hwndWrapper)) + { + return NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam); + } + } + Assert.IsNotNull(hwndWrapper); + + WndProc callback = hwndWrapper._wndProcCallback; + if (callback != null) + { + ret = callback(hwnd, msg, wParam, lParam); + } + else + { + ret = NativeMethods.DefWindowProc(hwnd, msg, wParam, lParam); + } + + if (msg == WM.NCDESTROY) + { + hwndWrapper._Dispose(true, true); + GC.SuppressFinalize(hwndWrapper); + } + + return ret; + } + + private static object _DestroyWindow(IntPtr hwnd, string className) + { + Utility.SafeDestroyWindow(ref hwnd); + NativeMethods.UnregisterClass(className, NativeMethods.GetModuleHandle(null)); + return null; + } + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Wpf/MshtmlProvider.cs b/Microsoft.Windows.Shell/standard.net/Wpf/MshtmlProvider.cs new file mode 100644 index 0000000..010b6f6 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Wpf/MshtmlProvider.cs @@ -0,0 +1,412 @@ + +[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Scope = "member", Target = "Standard.WebBrowserEvents+_EventSink.#System.Reflection.IReflect.InvokeMember(System.String,System.Reflection.BindingFlags,System.Reflection.Binder,System.Object,System.Object[],System.Reflection.ParameterModifier[],System.Globalization.CultureInfo,System.String[])")] + +// Interface declarations for MSHTML objects. +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.Linq; + using System.Reflection; + using System.Runtime.InteropServices; + using System.Runtime.InteropServices.ComTypes; + using System.Windows.Controls; + + [ + ComImport, + Guid(IID.WebBrowserEvents2), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + TypeLibType(TypeLibTypeFlags.FHidden) + ] + internal interface DWebBrowserEvents2 + { + [DispId(102)] + void StatusTextChange([In] string text); + [DispId(104)] + void DownloadComplete(); + [DispId(105)] + void CommandStateChange([In] long command, [In] bool enable); + [DispId(106)] + void DownloadBegin(); + [DispId(108)] + void ProgressChange([In] int progress, [In] int progressMax); + [DispId(112)] + void PropertyChange([In] string szProperty); + [DispId(113)] + void TitleChange([In] string text); + [DispId(225)] + void PrintTemplateInstantiation([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp); + [DispId(226)] + void PrintTemplateTeardown([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp); + [DispId(227)] + void UpdatePageStatus([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, [In] ref object nPage, [In] ref object fDone); + [DispId(250)] + void BeforeNavigate2( + [In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, + [In] ref object URL, + [In] ref object flags, + [In] ref object targetFrameName, + [In] ref object postData, + [In] ref object headers, + [In, Out] ref bool cancel); + [DispId(251)] + void NewWindow2([In, Out, MarshalAs(UnmanagedType.IDispatch)] ref object pDisp, [In, Out] ref bool cancel); + [DispId(252)] + void NavigateComplete2([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, [In] ref object URL); + [DispId(253)] + void OnQuit(); + [DispId(254)] + void OnVisible([In] bool visible); + [DispId(255)] + void OnToolBar([In] bool toolBar); + [DispId(256)] + void OnMenuBar([In] bool menuBar); + [DispId(257)] + void OnStatusBar([In] bool statusBar); + [DispId(258)] + void OnFullScreen([In] bool fullScreen); + [DispId(259)] + void DocumentComplete([In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, [In] ref object URL); + [DispId(260)] + void OnTheaterMode([In] bool theaterMode); + [DispId(262)] + void WindowSetResizable([In] bool resizable); + [DispId(263)] + void WindowClosing([In] bool isChildWindow, [In, Out] ref bool cancel); + [DispId(264)] + void WindowSetLeft([In] int left); + [DispId(265)] + void WindowSetTop([In] int top); + [DispId(266)] + void WindowSetWidth([In] int width); + [DispId(267)] + void WindowSetHeight([In] int height); + [DispId(268)] + void ClientToHostWindow([In, Out] ref long cx, [In, Out] ref long cy); + [DispId(269)] + void SetSecureLockIcon([In] int secureLockIcon); + [DispId(270)] + void FileDownload([In, Out] ref bool activeDocument, [In, Out] ref bool cancel); + [DispId(271)] + void NavigateError( + [In, MarshalAs(UnmanagedType.IDispatch)] object pDisp, + [In] ref object URL, + [In] ref object frame, + [In] ref object statusCode, + [In, Out] ref bool cancel); + [DispId(272)] + void PrivacyImpactedStateChange([In] bool bImpacted); + [DispId(282)] // IE 7+ + void SetPhishingFilterStatus(uint phishingFilterStatus); + [DispId(283)] // IE 7+ + void WindowStateChanged(uint dwFlags, uint dwValidFlagsMask); + } + + [ + ComImport, + Guid(IID.HtmlDocument2), + InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual) + ] + internal interface IHtmlDocument2 + { + [return: MarshalAs(UnmanagedType.Interface)] + object GetScript(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetAll(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetBody(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetActiveElement(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetImages(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetApplets(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetLinks(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetForms(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetAnchors(); + void SetTitle([In, MarshalAs(UnmanagedType.BStr)] string p); + [return: MarshalAs(UnmanagedType.BStr)] + string GetTitle(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetScripts(); + void SetDesignMode([In, MarshalAs(UnmanagedType.BStr)] string p); + [return: MarshalAs(UnmanagedType.BStr)] + string GetDesignMode(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetSelection(); + [return: MarshalAs(UnmanagedType.BStr)] + string GetReadyState(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetFrames(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetEmbeds(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetPlugins(); + void SetAlinkColor([In, MarshalAs(UnmanagedType.Struct)] object p); + [return: MarshalAs(UnmanagedType.Struct)] + object GetAlinkColor(); + void SetBackColor([In, MarshalAs(UnmanagedType.Struct)] object p); + [return: MarshalAs(UnmanagedType.Struct)] + object GetBackColor(); + void SetForeColor([In, MarshalAs(UnmanagedType.Struct)] object p); + [return: MarshalAs(UnmanagedType.Struct)] + object GetForeColor(); + void SetLinkColor([In, MarshalAs(UnmanagedType.Struct)] object p); + [return: MarshalAs(UnmanagedType.Struct)] + object GetLinkColor(); + void SetVlinkColor([In, MarshalAs(UnmanagedType.Struct)] object p); + [return: MarshalAs(UnmanagedType.Struct)] + object GetVlinkColor(); + [return: MarshalAs(UnmanagedType.BStr)] + string GetReferrer(); + [return: MarshalAs(UnmanagedType.Interface)] + object GetLocation(); + } + + [ + ComImport, + DefaultMember("Name"), + Guid(IID.WebBrowser2), + InterfaceType(ComInterfaceType.InterfaceIsIDispatch), + ] + interface IWebBrowser2 + { + [DispId(100)] + void GoBack(); + [DispId(0x65)] + void GoForward(); + [DispId(0x66)] + void GoHome(); + [DispId(0x67)] + void GoSearch(); + [DispId(0x68)] + void Navigate([MarshalAs(UnmanagedType.BStr)] string URL, [In] ref object Flags, [In] ref object TargetFrameName, [In] ref object PostData, [In] ref object Headers); + [DispId(-550)] + void Refresh(); + [DispId(0x69)] + void Refresh2([In] ref object Level); + [DispId(0x6a)] + void Stop(); + [DispId(300)] + void Quit(); + [DispId(0x12d)] + void ClientToWindow([In, Out] ref int pcx, [In, Out] ref int pcy); + [DispId(0x12e)] + void PutProperty([MarshalAs(UnmanagedType.BStr)] string Property, object vtValue); + [DispId(0x12f)] + object GetProperty([MarshalAs(UnmanagedType.BStr)] string Property); + [DispId(500)] + void Navigate2([In] ref object URL, [In] ref object Flags, [In] ref object TargetFrameName, [In] ref object PostData, [In] ref object Headers); + [DispId(0x1f5)] + OLECMDF QueryStatusWB(OLECMDID cmdID); + [DispId(0x1f6)] + void ExecWB(OLECMDID cmdID, OLECMDEXECOPT cmdexecopt, [In] ref object pvaIn, [In, Out] ref object pvaOut); + [DispId(0x1f7)] + void ShowBrowserBar([In] ref object pvaClsid, [In] ref object pvarShow, [In] ref object pvarSize); + bool AddressBar { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x22b)] get; [DispId(0x22b)] set; } + object Application { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(200)] get; } + bool Busy { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0xd4)] get; } + object Container { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xca)] get; } + object Document { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xcb)] get; } + string FullName { [return: MarshalAs(UnmanagedType.BStr)] [DispId(400)] get; } + bool FullScreen { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x197)] get; [DispId(0x197)] set; } + int Height { [DispId(0xd1)] get; [DispId(0xd1)] set; } + int HWND { [DispId(-515)] get; } + int Left { [DispId(0xce)] get; [DispId(0xce)] set; } + string LocationName { [return: MarshalAs(UnmanagedType.BStr)] [DispId(210)] get; } + string LocationURL { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0xd3)] get; } + bool MenuBar { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x196)] get; [DispId(0x196)] set; } + string Name { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0)] get; } + bool Offline { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(550)] get; [DispId(550)] set; } + object Parent { [return: MarshalAs(UnmanagedType.IDispatch)] [DispId(0xc9)] get; } + string Path { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x191)] get; } + READYSTATE ReadyState { [DispId(-525)] get; } + bool RegisterAsBrowser { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x228)] get; [DispId(0x228)] set; } + bool RegisterAsDropTarget { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x229)] get; [DispId(0x229)] set; } + bool Resizable { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x22c)] get; [DispId(0x22c)] set; } + bool Silent { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x227)] get; [DispId(0x227)] set; } + bool StatusBar { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x193)] get; [DispId(0x193)] set; } + string StatusText { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0x194)] get; [DispId(0x194)] set; } + bool TheaterMode { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x22a)] get; [DispId(0x22a)] set; } + int ToolBar { [DispId(0x195)] get; [DispId(0x195)] set; } + int Top { [DispId(0xcf)] get; [DispId(0xcf)] set; } + bool TopLevelContainer { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0xcc)] get; } + string Type { [return: MarshalAs(UnmanagedType.BStr)] [DispId(0xcd)] get; } + bool Visible { [return: MarshalAs(UnmanagedType.VariantBool)] [DispId(0x192)] get; [DispId(0x192)] set; } + int Width { [DispId(0xd0)] get; [DispId(0xd0)] set; } + } + + internal class WebBrowserEvents : IDisposable + { + private readonly _EventSink _sink; + private SafeConnectionPointCookie _cookie; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public WebBrowserEvents(WebBrowser browser) + { + if (browser.Document == null) + { + throw new InvalidOperationException("Can't add an event sink until the browser's document is non-null"); + } + + var serviceProvider = (IServiceProvider)browser.Document; + var serviceGuid = new Guid(SID.SWebBrowserApp); + var iid = new Guid(IID.ConnectionPointContainer); + var cpc = (IConnectionPointContainer)serviceProvider.QueryService(ref serviceGuid, ref iid); + + _sink = new _EventSink(this); + _cookie = new SafeConnectionPointCookie(cpc, _sink, new Guid(IID.WebBrowserEvents2)); + } + + // Because the DWebBrowserEvents2 interface is internal, provide our own IDispatch front-end for interop. + private class _EventSink : DWebBrowserEvents2, IReflect + { + private readonly WebBrowserEvents _target; + private static readonly Dictionary _dispIdMethodMap = typeof(DWebBrowserEvents2).GetMethods() + .ToDictionary(mi => ((DispIdAttribute[])mi.GetCustomAttributes(typeof(DispIdAttribute), false))[0].Value); + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal _EventSink(WebBrowserEvents target) + { + Assert.IsNotNull(target); + _target = target; + } + + #region DWebBrowserEvents2 Members + + public void StatusTextChange(string text) {} + public void DownloadComplete() {} + public void CommandStateChange(long command, bool enable) {} + public void DownloadBegin() {} + public void ProgressChange(int progress, int progressMax) {} + public void PropertyChange(string szProperty) {} + public void TitleChange(string text) {} + public void PrintTemplateInstantiation(object pDisp) {} + public void PrintTemplateTeardown(object pDisp) {} + public void UpdatePageStatus(object pDisp, ref object nPage, ref object fDone) {} + public void BeforeNavigate2(object pDisp, ref object URL, ref object flags, ref object targetFrameName, ref object postData, ref object headers, ref bool cancel) {} + public void NewWindow2(ref object pDisp, ref bool cancel) {} + public void NavigateComplete2(object pDisp, ref object URL) {} + public void OnQuit() {} + public void OnVisible(bool visible) {} + public void OnToolBar(bool toolBar) {} + public void OnMenuBar(bool menuBar) {} + public void OnStatusBar(bool statusBar) {} + public void OnFullScreen(bool fullScreen) {} + public void DocumentComplete(object pDisp, ref object URL) {} + public void OnTheaterMode(bool theaterMode) {} + public void WindowSetResizable(bool resizable) {} + public void WindowClosing(bool isChildWindow, ref bool cancel) + { + _target._NotifyWindowClosing(); + } + public void WindowSetLeft(int left) {} + public void WindowSetTop(int top) {} + public void WindowSetWidth(int width) {} + public void WindowSetHeight(int height) {} + public void ClientToHostWindow(ref long cx, ref long cy) {} + public void SetSecureLockIcon(int secureLockIcon) {} + public void FileDownload(ref bool activeDocument, ref bool cancel) {} + public void NavigateError(object pDisp, ref object URL, ref object frame, ref object statusCode, ref bool cancel) {} + public void PrivacyImpactedStateChange(bool bImpacted) {} + public void SetPhishingFilterStatus(uint phishingFilterStatus) {} + public void WindowStateChanged(uint dwFlags, uint dwValidFlagsMask) {} + + #endregion + + #region IReflect Members + + FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr) { throw new NotImplementedException(); } + FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) { return null; } + MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr) { throw new NotImplementedException(); } + MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr) { throw new NotImplementedException(); } + MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr) { throw new NotImplementedException(); } + MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) { throw new NotImplementedException(); } + MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr) { return null; } + PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr) { return null; } + PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) { throw new NotImplementedException(); } + PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr) { throw new NotImplementedException(); } + + object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) + { + Verify.IsNotNull(name, "name"); + if (name.StartsWith("[DISPID=", StringComparison.OrdinalIgnoreCase)) + { + int dispid = int.Parse(name.Substring(8, name.Length - 9), CultureInfo.InvariantCulture); + MethodInfo method; + if (_dispIdMethodMap.TryGetValue(dispid, out method)) + { + return method.Invoke(this, invokeAttr, binder, args, culture); + } + } + throw new MissingMethodException(GetType().Name, name); + } + + Type IReflect.UnderlyingSystemType { get { return typeof(DWebBrowserEvents2); } } + + #endregion + } + + public event EventHandler WindowClosing; + + private void _NotifyWindowClosing() + { + var handler = WindowClosing; + if (handler != null) + { + handler(this, EventArgs.Empty); + } + } + + #region IDisposable Pattern + + #if DEBUG + [SuppressMessage("Microsoft.Performance", "CA1821:RemoveEmptyFinalizers")] + ~WebBrowserEvents() + { + Assert.Fail(); + } + #endif + + [SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "_cookie")] + public void Dispose() + { + Utility.SafeDispose(ref _cookie); + GC.SuppressFinalize(this); + } + + #endregion + } + + internal static partial class Utility + { + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static string GetWebPageTitle(WebBrowser browser) + { + if (browser.Document == null) + { + return ""; + } + + return ((IHtmlDocument2)browser.Document).GetTitle(); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SuppressJavaScriptErrors(WebBrowser browser) + { + if (browser.Document != null) + { + var serviceProvider = (IServiceProvider)browser.Document; + var serviceGuid = new Guid(SID.SWebBrowserApp); + var iid = new Guid(IID.WebBrowser2); + var webBrowser2 = (IWebBrowser2)serviceProvider.QueryService(ref serviceGuid, ref iid); + webBrowser2.Silent = true; + } + } + } +} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/standard.net/Wpf/SingleInstance.cs b/Microsoft.Windows.Shell/standard.net/Wpf/SingleInstance.cs new file mode 100644 index 0000000..cbbf478 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Wpf/SingleInstance.cs @@ -0,0 +1,138 @@ +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; + using System.Runtime.Remoting; + using System.Runtime.Remoting.Channels; + using System.Runtime.Remoting.Channels.Ipc; + using System.Runtime.Serialization.Formatters; + using System.Threading; + + internal class SingleInstanceEventArgs : EventArgs + { + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public IList Args { get; internal set; } + } + + internal static class SingleInstance + { + public static event EventHandler SingleInstanceActivated; + + private class _IpcRemoteService : MarshalByRefObject + { + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")] + public int GetProcessId() + { + return System.Diagnostics.Process.GetCurrentProcess().Id; + } + + /// Activate the first instance of the application. + /// Command line arguemnts to proxy. + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic")] + public void InvokeFirstInstance(IList args) + { + if (System.Windows.Application.Current != null && !System.Windows.Application.Current.Dispatcher.HasShutdownStarted) + { + System.Windows.Application.Current.Dispatcher.BeginInvoke((Action)((arg) => SingleInstance._ActivateFirstInstance((IList)arg)), args); + } + } + + /// Overrides the default lease lifetime of 5 minutes so it will ever expire. + public override object InitializeLifetimeService() + { + return null; + } + } + + private const string _RemoteServiceName = "SingleInstanceApplicationService"; + private static Mutex _singleInstanceMutex; + private static IpcServerChannel _channel; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool InitializeAsFirstInstance(string applicationName) + { + IList commandLineArgs = Environment.GetCommandLineArgs() ?? new string[0]; + + // Build a repeatable machine unique name for the channel. + string appId = applicationName + Environment.UserName; + string channelName = appId + ":SingleInstanceIPCChannel"; + + bool isFirstInstance; + _singleInstanceMutex = new Mutex(true, appId, out isFirstInstance); + if (isFirstInstance) + { + _CreateRemoteService(channelName); + } + else + { + _SignalFirstInstance(channelName, commandLineArgs); + } + + return isFirstInstance; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void Cleanup() + { + Utility.SafeDispose(ref _singleInstanceMutex); + + if (_channel != null) + { + ChannelServices.UnregisterChannel(_channel); + _channel = null; + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static void _CreateRemoteService(string channelName) + { + _channel = new IpcServerChannel( + new Dictionary + { + { "name", channelName }, + { "portName", channelName }, + { "exclusiveAddressUse", "false" }, + }, + new BinaryServerFormatterSinkProvider { TypeFilterLevel = TypeFilterLevel.Full }); + + ChannelServices.RegisterChannel(_channel, true); + RemotingServices.Marshal(new _IpcRemoteService(), _RemoteServiceName); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static void _SignalFirstInstance(string channelName, IList args) + { + var secondInstanceChannel = new IpcClientChannel(); + ChannelServices.RegisterChannel(secondInstanceChannel, true); + + string remotingServiceUrl = "ipc://" + channelName + "/" + _RemoteServiceName; + + // Obtain a reference to the remoting service exposed by the first instance of the application + var firstInstanceRemoteServiceReference = (_IpcRemoteService)RemotingServices.Connect(typeof(_IpcRemoteService), remotingServiceUrl); + + // Pass along the current arguments to the first instance if it's up and accepting requests. + if (firstInstanceRemoteServiceReference != null) + { + // Allow the first instance to give itself user focus. + // This could be done with ASFW_ANY if the IPC call is expensive. + int procId = firstInstanceRemoteServiceReference.GetProcessId(); + NativeMethods.AllowSetForegroundWindow(procId); + + firstInstanceRemoteServiceReference.InvokeFirstInstance(args); + } + } + + private static void _ActivateFirstInstance(IList args) + { + if (System.Windows.Application.Current != null && !System.Windows.Application.Current.Dispatcher.HasShutdownStarted) + { + var handler = SingleInstanceActivated; + if (handler != null) + { + handler(System.Windows.Application.Current, new SingleInstanceEventArgs { Args = args }); + } + } + } + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Wpf/SplashScreen.cs b/Microsoft.Windows.Shell/standard.net/Wpf/SplashScreen.cs new file mode 100644 index 0000000..ddedb33 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Wpf/SplashScreen.cs @@ -0,0 +1,350 @@ + +namespace Standard +{ + using System; + using System.Diagnostics.CodeAnalysis; + using System.Globalization; + using System.IO; + using System.Reflection; + using System.Resources; + using System.Runtime.InteropServices; + using System.Windows; + using System.Windows.Threading; + + // Current issues with this implementation: + // * FadeOutDuration will pop the splashscreen in front of the main window. This can be partially managed + // by using IsTopMost, but that has other effects. I should be able to hook the WndProc to keep this + // window from going inactive. + // * FadeInDuration doesn't work because this is being created on the main UI thread. For multiple reasons we + // should probably create this window on a background thread. + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1812:AvoidUninstantiatedInternalClasses")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1001:TypesThatOwnDisposableFieldsShouldBeDisposable")] + internal class SplashScreen + { + private static readonly BLENDFUNCTION _BaseBlendFunction = new BLENDFUNCTION + { + BlendOp = AC.SRC_OVER, + BlendFlags = 0, + SourceConstantAlpha = 255, + AlphaFormat = AC.SRC_ALPHA, + }; + + private MessageWindow _hwndWrapper; + private SafeHBITMAP _hBitmap; + private DispatcherTimer _dt; + private DateTime _fadeOutEnd; + private DateTime _fadeInEnd; + private ResourceManager _resourceManager; + private string _resourceName; + private Dispatcher _dispatcher; + private Assembly _resourceAssembly; + private bool _isClosed = false; + + private void _VerifyMutability() + { + if (_hwndWrapper != null) + { + throw new InvalidOperationException("Splash screen has already been shown."); + } + } + + public SplashScreen() { } + + public Assembly ResourceAssembly + { + get { return _resourceAssembly; } + set + { + _VerifyMutability(); + + Verify.IsNotNull(value, "value"); + + _resourceAssembly = value; + AssemblyName name = new AssemblyName(_resourceAssembly.FullName); + _resourceManager = new ResourceManager(name.Name + ".g", _resourceAssembly); + } + } + + [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase")] + public string ResourceName + { + get { return _resourceName ?? ""; } + set + { + Verify.IsNeitherNullNorEmpty(value, "value"); + _resourceName = value.ToLowerInvariant(); + } + } + + public string ImageFileName { get; set; } + public bool IsTopMost { get; set; } + public bool CloseOnMainWindowCreation { get; set; } + public TimeSpan FadeOutDuration { get; set; } + public TimeSpan FadeInDuration { get; set; } + + private Stream _GetImageStream() + { + Stream imageStream = null; + // Try to use the filepath first. If it's not provided or not available, use the embedded resource. + if (!string.IsNullOrEmpty(ImageFileName) && File.Exists(ImageFileName)) + { + try + { + imageStream = new FileStream(ImageFileName, FileMode.Open); + } + catch (IOException) { } + } + + if (imageStream == null) + { + imageStream = _resourceManager.GetStream(ResourceName, CultureInfo.CurrentUICulture); + if (imageStream == null) + { + throw new IOException("The resource could not be found."); + } + } + + return imageStream; + } + + public void Show() + { + _VerifyMutability(); + + using (Stream imageStream = _GetImageStream()) + { + Size bitmapSize; + _hBitmap = _CreateHBITMAPFromImageStream(imageStream, out bitmapSize); + + Point location = new Point( + (NativeMethods.GetSystemMetrics(SM.CXSCREEN) - bitmapSize.Width) / 2, + (NativeMethods.GetSystemMetrics(SM.CYSCREEN) - bitmapSize.Height) / 2); + + // Pass a null WndProc. Let the MessageWindow use DefWindowProc. + _hwndWrapper = new MessageWindow( + CS.HREDRAW | CS.VREDRAW, + WS.POPUP | WS.VISIBLE, + WS_EX.WINDOWEDGE | WS_EX.TOOLWINDOW | WS_EX.LAYERED | (IsTopMost ? WS_EX.TOPMOST : 0), + new Rect(location, bitmapSize), + "Splash Screen", + null); + + byte opacity = (byte)(FadeInDuration > TimeSpan.Zero ? 0 : 255); + + using (SafeDC hScreenDC = SafeDC.GetDesktop()) + { + using (SafeDC memDC = SafeDC.CreateCompatibleDC(hScreenDC)) + { + IntPtr hOldBitmap = NativeMethods.SelectObject(memDC, _hBitmap); + + RECT hwndRect = NativeMethods.GetWindowRect(_hwndWrapper.Handle); + + POINT hwndPos = hwndRect.Position; + SIZE hwndSize = hwndRect.Size; + POINT origin = new POINT(); + BLENDFUNCTION bf = _BaseBlendFunction; + bf.SourceConstantAlpha = opacity; + + NativeMethods.UpdateLayeredWindow(_hwndWrapper.Handle, hScreenDC, ref hwndPos, ref hwndSize, memDC, ref origin, 0, ref bf, ULW.ALPHA); + NativeMethods.SelectObject(memDC, hOldBitmap); + } + } + + if (CloseOnMainWindowCreation) + { + Dispatcher.CurrentDispatcher.BeginInvoke( + DispatcherPriority.Loaded, + (DispatcherOperationCallback)delegate(object splashObj) + { + var splashScreen = (SplashScreen)splashObj; + if (!splashScreen._isClosed) + { + splashScreen.Close(); + } + return null; + }, + this); + } + + _dispatcher = Dispatcher.CurrentDispatcher; + if (FadeInDuration > TimeSpan.Zero) + { + _fadeInEnd = DateTime.UtcNow + FadeInDuration; + _dt = new DispatcherTimer(FadeInDuration, DispatcherPriority.Normal, _FadeInTick, _dispatcher); + _dt.Start(); + } + } + } + + [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] + public void Close() + { + if (!_dispatcher.CheckAccess()) + { + _dispatcher.Invoke(DispatcherPriority.Normal, (Action)Close); + return; + } + + if (_isClosed) + { + throw new InvalidOperationException("Splash screen was already closed"); + } + + _isClosed = true; + + if (FadeOutDuration <= TimeSpan.Zero) + { + _DestroyResources(); + return; + } + + try + { + NativeMethods.SetActiveWindow(_hwndWrapper.Handle); + } + catch + { + // SetActiveWindow fails if the application is not in the foreground. + // If this is the case, don't bother animating the fade out. + _DestroyResources(); + return; + } + + _fadeOutEnd = DateTime.UtcNow + FadeOutDuration; + if (_dt != null) + { + _dt.Stop(); + } + _dt = new DispatcherTimer(TimeSpan.FromMilliseconds(30), DispatcherPriority.Normal, _FadeOutTick, _dispatcher); + _dt.Start(); + + return; + } + + private void _FadeOutTick(object unused, EventArgs args) + { + DateTime dtNow = DateTime.UtcNow; + if (dtNow >= _fadeOutEnd) + { + _DestroyResources(); + } + else + { + double progress = (_fadeOutEnd - dtNow).TotalMilliseconds / FadeOutDuration.TotalMilliseconds; + BLENDFUNCTION bf = _BaseBlendFunction; + bf.SourceConstantAlpha = (byte)(255 * progress); + NativeMethods.UpdateLayeredWindow(_hwndWrapper.Handle, 0, ref bf, ULW.ALPHA); + } + } + + private void _FadeInTick(object unused, EventArgs args) + { + DateTime dtNow = DateTime.UtcNow; + if (dtNow >= _fadeInEnd) + { + _DestroyResources(); + } + else + { + double progress = 1 - (_fadeInEnd - dtNow).TotalMilliseconds / FadeInDuration.TotalMilliseconds; + progress = Math.Max(0, Math.Min(progress, 1)); + BLENDFUNCTION bf = _BaseBlendFunction; + bf.SourceConstantAlpha = (byte)(int)(255 * progress); + NativeMethods.UpdateLayeredWindow(_hwndWrapper.Handle, 0, ref bf, ULW.ALPHA); + } + } + + private void _DestroyResources() + { + if (_dt != null) + { + _dt.Stop(); + _dt = null; + } + Utility.SafeDispose(ref _hwndWrapper); + Utility.SafeDispose(ref _hBitmap); + if (_resourceManager != null) + { + _resourceManager.ReleaseAllResources(); + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")] + private static SafeHBITMAP _CreateHBITMAPFromImageStream(Stream imgStream, out Size bitmapSize) + { + IWICImagingFactory pImagingFactory = null; + IWICBitmapDecoder pDecoder = null; + IWICStream pStream = null; + IWICBitmapFrameDecode pDecodedFrame = null; + IWICFormatConverter pBitmapSourceFormatConverter = null; + IWICBitmapFlipRotator pBitmapFlipRotator = null; + + SafeHBITMAP hbmp = null; + try + { + using (var istm = new ManagedIStream(imgStream)) + { + pImagingFactory = CLSID.CoCreateInstance(CLSID.WICImagingFactory); + pStream = pImagingFactory.CreateStream(); + pStream.InitializeFromIStream(istm); + + // Create an object that will decode the encoded image + Guid vendor = Guid.Empty; + pDecoder = pImagingFactory.CreateDecoderFromStream(pStream, ref vendor, WICDecodeMetadata.CacheOnDemand); + + pDecodedFrame = pDecoder.GetFrame(0); + pBitmapSourceFormatConverter = pImagingFactory.CreateFormatConverter(); + + // Convert the image from whatever format it is in to 32bpp premultiplied alpha BGRA + Guid pixelFormat = WICPixelFormat.WICPixelFormat32bppPBGRA; + pBitmapSourceFormatConverter.Initialize(pDecodedFrame, ref pixelFormat, WICBitmapDitherType.None, IntPtr.Zero, 0, WICBitmapPaletteType.Custom); + + pBitmapFlipRotator = pImagingFactory.CreateBitmapFlipRotator(); + pBitmapFlipRotator.Initialize(pBitmapSourceFormatConverter, WICBitmapTransform.FlipVertical); + + int width, height; + pBitmapFlipRotator.GetSize(out width, out height); + + bitmapSize = new Size { Width = width, Height = height }; + + var bmi = new BITMAPINFO + { + bmiHeader = new BITMAPINFOHEADER + { + biSize = Marshal.SizeOf(typeof(BITMAPINFOHEADER)), + biWidth = width, + biHeight = height, + biPlanes = 1, + biBitCount = 32, + biCompression = BI.RGB, + biSizeImage = (width * height * 4), + }, + }; + + // Create a 32bpp DIB. This DIB must have an alpha channel for UpdateLayeredWindow to succeed. + IntPtr pBitmapBits; + hbmp = NativeMethods.CreateDIBSection(null, ref bmi, out pBitmapBits, IntPtr.Zero, 0); + + // Copy the decoded image to the new buffer which backs the HBITMAP + var rect = new WICRect { X = 0, Y = 0, Width = width, Height = height }; + pBitmapFlipRotator.CopyPixels(ref rect, width * 4, bmi.bmiHeader.biSizeImage, pBitmapBits); + + var ret = hbmp; + hbmp = null; + return ret; + } + } + finally + { + Utility.SafeRelease(ref pImagingFactory); + Utility.SafeRelease(ref pDecoder); + Utility.SafeRelease(ref pStream); + Utility.SafeRelease(ref pDecodedFrame); + Utility.SafeRelease(ref pBitmapFlipRotator); + Utility.SafeRelease(ref pBitmapSourceFormatConverter); + Utility.SafeDispose(ref hbmp); + } + } + } +} \ No newline at end of file diff --git a/Microsoft.Windows.Shell/standard.net/Wpf/Utilities.Wpf.cs b/Microsoft.Windows.Shell/standard.net/Wpf/Utilities.Wpf.cs new file mode 100644 index 0000000..a6d1e95 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Wpf/Utilities.Wpf.cs @@ -0,0 +1,400 @@ +// This file contains general utilities to aid in development. +// Classes here generally shouldn't be exposed publicly since +// they're not particular to any library functionality. +// Because the classes here are internal, it's likely this file +// might be included in multiple assemblies. +namespace Standard +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Linq; + using System.Reflection; + using System.Windows; + using System.Windows.Media; + using System.Windows.Media.Imaging; + + internal static partial class Utility + { + private static readonly bool _isNotAtRuntime = (bool)System.ComponentModel.DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(System.Windows.DependencyObject)).DefaultValue; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsInDesignMode { get { return _isNotAtRuntime; } } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static byte[] GetBytesFromBitmapSource(BitmapSource bmp) + { + int width = bmp.PixelWidth; + int height = bmp.PixelHeight; + int stride = width * ((bmp.Format.BitsPerPixel + 7) / 8); + + var pixels = new byte[height * stride]; + + bmp.CopyPixels(pixels, stride, 0); + + return pixels; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static BitmapSource GenerateBitmapSource(ImageSource img) + { + return GenerateBitmapSource(img, img.Width, img.Height); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static BitmapSource GenerateBitmapSource(ImageSource img, double renderWidth, double renderHeight) + { + var dv = new DrawingVisual(); + using (DrawingContext dc = dv.RenderOpen()) + { + dc.DrawImage(img, new Rect(0, 0, renderWidth, renderHeight)); + } + var bmp = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32); + bmp.Render(dv); + return bmp; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static BitmapSource GenerateBitmapSource(UIElement element, double renderWidth, double renderHeight, bool performLayout) + { + if (performLayout) + { + element.Measure(new Size(renderWidth, renderHeight)); + element.Arrange(new Rect(new Size(renderWidth, renderHeight))); + } + + var bmp = new RenderTargetBitmap((int)renderWidth, (int)renderHeight, 96, 96, PixelFormats.Pbgra32); + var dv = new DrawingVisual(); + using (DrawingContext dc = dv.RenderOpen()) + { + dc.DrawRectangle(new VisualBrush(element), null, new Rect(0, 0, renderWidth, renderHeight)); + } + bmp.Render(dv); + return bmp; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void SaveToPng(BitmapSource source, string fileName) + { + var encoder = new PngBitmapEncoder(); + encoder.Frames.Add(BitmapFrame.Create(source)); + + using (FileStream stream = File.Create(fileName)) + { + encoder.Save(stream); + } + } + + // This can be cached. It's not going to change under reasonable circumstances. + private static int s_bitDepth; // = 0; + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static int _GetBitDepth() + { + if (s_bitDepth == 0) + { + using (SafeDC dc = SafeDC.GetDesktop()) + { + s_bitDepth = NativeMethods.GetDeviceCaps(dc, DeviceCap.BITSPIXEL) * NativeMethods.GetDeviceCaps(dc, DeviceCap.PLANES); + } + } + return s_bitDepth; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static BitmapFrame GetBestMatch(IList frames, int width, int height) + { + return _GetBestMatch(frames, _GetBitDepth(), width, height); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static int _MatchImage(BitmapFrame frame, int bitDepth, int width, int height, int bpp) + { + int score = 2 * _WeightedAbs(bpp, bitDepth, false) + + _WeightedAbs(frame.PixelWidth, width, true) + + _WeightedAbs(frame.PixelHeight, height, true); + + return score; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static int _WeightedAbs(int valueHave, int valueWant, bool fPunish) + { + int diff = (valueHave - valueWant); + + if (diff < 0) + { + diff = (fPunish ? -2 : -1) * diff; + } + + return diff; + } + + /// From a list of BitmapFrames find the one that best matches the requested dimensions. + /// The methods used here are copied from Win32 sources. We want to be consistent with + /// system behaviors. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + private static BitmapFrame _GetBestMatch(IList frames, int bitDepth, int width, int height) + { + int bestScore = int.MaxValue; + int bestBpp = 0; + int bestIndex = 0; + + bool isBitmapIconDecoder = frames[0].Decoder is IconBitmapDecoder; + + for (int i = 0; i < frames.Count && bestScore != 0; ++i) + { + int currentIconBitDepth = isBitmapIconDecoder ? frames[i].Thumbnail.Format.BitsPerPixel : frames[i].Format.BitsPerPixel; + + if (currentIconBitDepth == 0) + { + currentIconBitDepth = 8; + } + + int score = _MatchImage(frames[i], bitDepth, width, height, currentIconBitDepth); + if (score < bestScore) + { + bestIndex = i; + bestBpp = currentIconBitDepth; + bestScore = score; + } + else if (score == bestScore) + { + // Tie breaker: choose the higher color depth. If that fails, choose first one. + if (bestBpp < currentIconBitDepth) + { + bestIndex = i; + bestBpp = currentIconBitDepth; + } + } + } + + return frames[bestIndex]; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int RGB(Color c) + { + return c.B | (c.G << 8) | (c.R << 16); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static int AlphaRGB(Color c) + { + return c.B | (c.G << 8) | (c.R << 16) | (c.A << 24); + } + + /// Convert a native integer that represent a color with an alpha channel into a Color struct. + /// The integer that represents the color. Its bits are of the format 0xAARRGGBB. + /// A Color representation of the parameter. + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static Color ColorFromArgbDword(uint color) + { + return Color.FromArgb( + (byte)((color & 0xFF000000) >> 24), + (byte)((color & 0x00FF0000) >> 16), + (byte)((color & 0x0000FF00) >> 8), + (byte)((color & 0x000000FF) >> 0)); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool AreImageSourcesEqual(ImageSource left, ImageSource right) + { + if (null == left) + { + return right == null; + } + if (null == right) + { + return false; + } + + BitmapSource leftBmp = GenerateBitmapSource(left); + BitmapSource rightBmp = GenerateBitmapSource(right); + + byte[] leftPixels = GetBytesFromBitmapSource(leftBmp); + byte[] rightPixels = GetBytesFromBitmapSource(rightBmp); + + if (leftPixels.Length != rightPixels.Length) + { + return false; + } + + return MemCmp(leftPixels, rightPixels, leftPixels.Length); + } + + // Caller is responsible for destroying the HICON + // Caller is responsible to ensure that GDI+ has been initialized. + [SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times")] + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static IntPtr GenerateHICON(ImageSource image, Size dimensions) + { + if (image == null) + { + return IntPtr.Zero; + } + + // If we're getting this from a ".ico" resource, then it comes through as a BitmapFrame. + // We can use leverage this as a shortcut to get the right 16x16 representation + // because DrawImage doesn't do that for us. + var bf = image as BitmapFrame; + if (bf != null) + { + bf = GetBestMatch(bf.Decoder.Frames, (int)dimensions.Width, (int)dimensions.Height); + } + else + { + // Constrain the dimensions based on the aspect ratio. + var drawingDimensions = new Rect(0, 0, dimensions.Width, dimensions.Height); + + // There's no reason to assume that the requested image dimensions are square. + double renderRatio = dimensions.Width / dimensions.Height; + double aspectRatio = image.Width / image.Height; + + // If it's smaller than the requested size, then place it in the middle and pad the image. + if (image.Width <= dimensions.Width && image.Height <= dimensions.Height) + { + drawingDimensions = new Rect((dimensions.Width - image.Width) / 2, (dimensions.Height - image.Height) / 2, image.Width, image.Height); + } + else if (renderRatio > aspectRatio) + { + double scaledRenderWidth = (image.Width / image.Height) * dimensions.Width; + drawingDimensions = new Rect((dimensions.Width - scaledRenderWidth) / 2, 0, scaledRenderWidth, dimensions.Height); + } + else if (renderRatio < aspectRatio) + { + double scaledRenderHeight = (image.Height / image.Width) * dimensions.Height; + drawingDimensions = new Rect(0, (dimensions.Height - scaledRenderHeight) / 2, dimensions.Width, scaledRenderHeight); + } + + var dv = new DrawingVisual(); + DrawingContext dc = dv.RenderOpen(); + dc.DrawImage(image, drawingDimensions); + dc.Close(); + + var bmp = new RenderTargetBitmap((int)dimensions.Width, (int)dimensions.Height, 96, 96, PixelFormats.Pbgra32); + bmp.Render(dv); + bf = BitmapFrame.Create(bmp); + } + + // Using GDI+ to convert to an HICON. + // I'd rather not duplicate their code. + using (MemoryStream memstm = new MemoryStream()) + { + BitmapEncoder enc = new PngBitmapEncoder(); + enc.Frames.Add(bf); + enc.Save(memstm); + + using (var istm = new ManagedIStream(memstm)) + { + // We are not bubbling out GDI+ errors when creating the native image fails. + IntPtr bitmap = IntPtr.Zero; + try + { + Status gpStatus = NativeMethods.GdipCreateBitmapFromStream(istm, out bitmap); + if (Status.Ok != gpStatus) + { + return IntPtr.Zero; + } + + IntPtr hicon; + gpStatus = NativeMethods.GdipCreateHICONFromBitmap(bitmap, out hicon); + if (Status.Ok != gpStatus) + { + return IntPtr.Zero; + } + + // Caller is responsible for freeing this. + return hicon; + } + finally + { + Utility.SafeDisposeImage(ref bitmap); + } + } + } + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void AddDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener) + { + if (component == null) + { + return; + } + Assert.IsNotNull(property); + Assert.IsNotNull(listener); + + DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType()); + dpd.AddValueChanged(component, listener); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static void RemoveDependencyPropertyChangeListener(object component, DependencyProperty property, EventHandler listener) + { + if (component == null) + { + return; + } + Assert.IsNotNull(property); + Assert.IsNotNull(listener); + + DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(property, component.GetType()); + dpd.RemoveValueChanged(component, listener); + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsNonNegative(this Thickness thickness) + { + if (!thickness.Top.IsFiniteAndNonNegative()) + { + return false; + } + + if (!thickness.Left.IsFiniteAndNonNegative()) + { + return false; + } + + if (!thickness.Bottom.IsFiniteAndNonNegative()) + { + return false; + } + + if (!thickness.Right.IsFiniteAndNonNegative()) + { + return false; + } + + return true; + } + + [SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + public static bool IsValid(this CornerRadius cornerRadius) + { + if (!cornerRadius.TopLeft.IsFiniteAndNonNegative()) + { + return false; + } + + if (!cornerRadius.TopRight.IsFiniteAndNonNegative()) + { + return false; + } + + if (!cornerRadius.BottomLeft.IsFiniteAndNonNegative()) + { + return false; + } + + if (!cornerRadius.BottomRight.IsFiniteAndNonNegative()) + { + return false; + } + + return true; + } + } +} diff --git a/Microsoft.Windows.Shell/standard.net/Wpf/WindowExtensions.cs b/Microsoft.Windows.Shell/standard.net/Wpf/WindowExtensions.cs new file mode 100644 index 0000000..d0fb5b2 --- /dev/null +++ b/Microsoft.Windows.Shell/standard.net/Wpf/WindowExtensions.cs @@ -0,0 +1,137 @@ + +namespace Standard +{ + using System; + using System.ComponentModel; + using System.Windows; + using System.Windows.Interop; + using System.Windows.Media; + + /// + /// Attached properties for WPF Windows. + /// + internal sealed class WindowExtensions + { + private IntPtr _hwnd = IntPtr.Zero; + private Window _window = null; + + private event Action WindowSourceInitialized; + + private WindowExtensions(Window window) + { + Assert.IsNotNull(window); + _window = window; + _hwnd = new WindowInteropHelper(window).Handle; + + if (_hwnd == IntPtr.Zero) + { + _window.SourceInitialized += _OnWindowSourceInitialized; + } + } + + private void _OnWindowSourceInitialized(object sender, EventArgs e) + { + Assert.AreEqual(sender, _window); + + _window.SourceInitialized -= _OnWindowSourceInitialized; + + _hwnd = new WindowInteropHelper(_window).Handle; + Assert.IsNotDefault(_hwnd); + + Action handler = WindowSourceInitialized; + if (handler != null) + { + handler(); + } + } + + private static WindowExtensions _EnsureAttachedExtensions(Window window) + { + Assert.IsNotNull(window); + + var ext = (WindowExtensions)window.GetValue(WindowExtensionsProperty); + if (ext == null) + { + ext = new WindowExtensions(window); + window.SetValue(WindowExtensionsProperty, ext); + } + + return ext; + } + + private static readonly DependencyProperty WindowExtensionsProperty = DependencyProperty.RegisterAttached( + "WindowExtensions", + typeof(WindowExtensions), + typeof(WindowExtensions), + new PropertyMetadata(null)); + + // Not bothering with CLR attached property getter/setter since this is a private dependency property. + + + public static readonly DependencyProperty HwndBackgroundBrushProperty = DependencyProperty.RegisterAttached( + "HwndBackgroundBrush", + typeof(SolidColorBrush), + typeof(WindowExtensions), + new PropertyMetadata( + Brushes.Pink, + (d,e) => _OnHwndBackgroundBrushChanged(d))); + + public static SolidColorBrush GetHwndBackgroundBrush(FrameworkElement window) + { + Verify.IsNotNull(window, "window"); + return (SolidColorBrush)window.GetValue(HwndBackgroundBrushProperty); + } + + public static void SetHwndBackgroundBrush(FrameworkElement window, SolidColorBrush value) + { + if (!(window is Window)) + { + return; + } + Verify.IsNotNull(window, "window"); + window.SetValue(HwndBackgroundBrushProperty, value); + } + + private static void _OnHwndBackgroundBrushChanged(DependencyObject d) + { + if (DesignerProperties.GetIsInDesignMode(d)) + { + return; + } + + var window = d as Window; + Verify.IsNotNull(window, "window"); + + WindowExtensions ext = _EnsureAttachedExtensions(window); + + if (ext._hwnd == IntPtr.Zero) + { + ext.WindowSourceInitialized += () => _OnHwndBackgroundBrushChanged(window); + return; + } + + SolidColorBrush backgroundBrush = (SolidColorBrush)window.GetValue(HwndBackgroundBrushProperty); + //if (backgroundBrush == null) + //{ + // Nothing to change. + // return; + //} + + Color backgroundColor = backgroundBrush.Color; + + // Not really handling errors here, but they shouldn't matter... Might leak an HBRUSH. + + IntPtr hBrush = NativeMethods.CreateSolidBrush(Utility.RGB(backgroundColor)); + + // Note that setting this doesn't necessarily repaint the window right away. + // Since the WPF content should cover the HWND background this doesn't matter. + // The new background will get repainted when the window is resized. + IntPtr hBrushOld = NativeMethods.SetClassLongPtr(ext._hwnd, GCLP.HBRBACKGROUND, hBrush); + + if (IntPtr.Zero != hBrushOld) + { + NativeMethods.DeleteObject(hBrushOld); + } + } + } +} From b6ff90ce5191fdd1e7860a30c1b1de2d999f6778 Mon Sep 17 00:00:00 2001 From: cplotts Date: Fri, 11 Mar 2016 14:17:30 -0600 Subject: [PATCH 20/21] Wrapping GetCurrentThemeName in a try/catch as we were seeing an odd exception. --- Microsoft.Windows.Shell/SystemParameters2.cs | 48 ++++++++++++-------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/Microsoft.Windows.Shell/SystemParameters2.cs b/Microsoft.Windows.Shell/SystemParameters2.cs index f230163..11e4383 100644 --- a/Microsoft.Windows.Shell/SystemParameters2.cs +++ b/Microsoft.Windows.Shell/SystemParameters2.cs @@ -213,24 +213,36 @@ private void _UpdateHighContrast(IntPtr wParam, IntPtr lParam) _InitializeHighContrast(); } - private void _InitializeThemeInfo() - { - if (!NativeMethods.IsThemeActive()) - { - UxThemeName = "Classic"; - UxThemeColor = ""; - return; - } - - string name; - string color; - string size; - NativeMethods.GetCurrentThemeName(out name, out color, out size); - - // Consider whether this is the most useful way to expose this... - UxThemeName = System.IO.Path.GetFileNameWithoutExtension(name); - UxThemeColor = color; - } + private void _InitializeThemeInfo() + { + if (!NativeMethods.IsThemeActive()) + { + UxThemeName = "Classic"; + UxThemeColor = ""; + return; + } + + try + { + // wrap GetCurrentThemeName in a try/catch as we were seeing an exception + // even though the theme service seemed to be active (UxTheme IsThemeActive) + // see http://stackoverflow.com/questions/8893854/wpf-application-ribbon-crash as an example. + + string name; + string color; + string size; + NativeMethods.GetCurrentThemeName(out name, out color, out size); + + // Consider whether this is the most useful way to expose this... + UxThemeName = System.IO.Path.GetFileNameWithoutExtension(name); + UxThemeColor = color; + } + catch (Exception) + { + UxThemeName = "Classic"; + UxThemeColor = ""; + } + } private void _UpdateThemeInfo(IntPtr wParam, IntPtr lParam) { From 4601b590839e548b9eac54ad37f9e9f4e00479ff Mon Sep 17 00:00:00 2001 From: cplotts Date: Fri, 11 Mar 2016 14:49:43 -0600 Subject: [PATCH 21/21] When in Rome, do spaces. --- Microsoft.Windows.Shell/SystemParameters2.cs | 60 ++++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Microsoft.Windows.Shell/SystemParameters2.cs b/Microsoft.Windows.Shell/SystemParameters2.cs index 11e4383..5a0adc7 100644 --- a/Microsoft.Windows.Shell/SystemParameters2.cs +++ b/Microsoft.Windows.Shell/SystemParameters2.cs @@ -213,36 +213,36 @@ private void _UpdateHighContrast(IntPtr wParam, IntPtr lParam) _InitializeHighContrast(); } - private void _InitializeThemeInfo() - { - if (!NativeMethods.IsThemeActive()) - { - UxThemeName = "Classic"; - UxThemeColor = ""; - return; - } - - try - { - // wrap GetCurrentThemeName in a try/catch as we were seeing an exception - // even though the theme service seemed to be active (UxTheme IsThemeActive) - // see http://stackoverflow.com/questions/8893854/wpf-application-ribbon-crash as an example. - - string name; - string color; - string size; - NativeMethods.GetCurrentThemeName(out name, out color, out size); - - // Consider whether this is the most useful way to expose this... - UxThemeName = System.IO.Path.GetFileNameWithoutExtension(name); - UxThemeColor = color; - } - catch (Exception) - { - UxThemeName = "Classic"; - UxThemeColor = ""; - } - } + private void _InitializeThemeInfo() + { + if (!NativeMethods.IsThemeActive()) + { + UxThemeName = "Classic"; + UxThemeColor = ""; + return; + } + + try + { + // wrap GetCurrentThemeName in a try/catch as we were seeing an exception + // even though the theme service seemed to be active (UxTheme IsThemeActive) + // see http://stackoverflow.com/questions/8893854/wpf-application-ribbon-crash as an example. + + string name; + string color; + string size; + NativeMethods.GetCurrentThemeName(out name, out color, out size); + + // Consider whether this is the most useful way to expose this... + UxThemeName = System.IO.Path.GetFileNameWithoutExtension(name); + UxThemeColor = color; + } + catch (Exception) + { + UxThemeName = "Classic"; + UxThemeColor = ""; + } + } private void _UpdateThemeInfo(IntPtr wParam, IntPtr lParam) {

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 AO#lD@ literal 0 HcmV?d00001 diff --git a/TaskbarSample/Images/CircleRed.png b/TaskbarSample/Images/CircleRed.png new file mode 100644 index 0000000000000000000000000000000000000000..3b11aa869cab0e9649b5b16d6381d3a736f65ff9 GIT binary patch literal 143116 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 literal 0 HcmV?d00001 diff --git a/TaskbarSample/Images/CircleYellow.png b/TaskbarSample/Images/CircleYellow.png new file mode 100644 index 0000000000000000000000000000000000000000..47d08f0f7ba11e37faadd6c882cec17ab495002d GIT binary patch literal 116381 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 literal 0 HcmV?d00001 diff --git a/TaskbarSample/Images/Cut.png b/TaskbarSample/Images/Cut.png new file mode 100644 index 0000000000000000000000000000000000000000..51449ba37ccda6146a010fbb004ae788a7cf008f GIT binary patch literal 628 zcmV-)0*n2LP)z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ->PbXFRCwBylFe%qQ541R%a_JftF3j6=+dQ_<{#*; z3kz-v1wn#}D-jnWZWP=FZHlY75#5^liC77UNMoUk7E7cl)Ka3qrKYyvfhZn`gpltt0Ix*sG z{obBhT3M~Tlnr653jm;@0gg+*B7`Oum%oq6iW;>H+-a+1Cp2KU)qbq#>V&T0v97KN z>e`i{dLsLocW>q9JDP=!u7O1Ij7W}T-vt5C-W^%1>pB?wMH1z@;j(q!3lK=n!AY({UO#lFTB>(_`g8%^e{{R4h=>PzA zFaQARU;qF*m;eA5Z<1fdMgRZ;P)S5VRCwB?lTAoeVHAd+JL(uNB`Hg2RYYPDSX7G& z35m=Sgci9fQi{lkh@cjc5J4#Y5VTW>j21}}LNOsF2(~bapoLMQiKdP^dgspfd+&TL z)X2(OcvgqQ;o+PY9?v<)N-Fnn!``l&&X|z2FL~YbvHVV3*SqBa-qT07F9OYrgY-l{ zHFbx`LohQv$NjqriZ_%I&&wyY7ND~6%B@$6`!S%o>Tn6w)$6IMT0>63TH?7OP1m|U z1+!Dc<8daw^iaEdl)CL53=Rw=e!U-RWv;;MVzcEg(on2<>N#DXCZ z-*IXJJ(oo3`IFn8^#WjxVNZD}QfbcBALn50N%yj&)yp;35=ns + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + None + + + + + + Show in taskbar? + + + + + + + + + + + + + + + Show Recent + Show Frequent + Defer Apply + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TaskbarSample/MainWindow.xaml.cs b/TaskbarSample/MainWindow.xaml.cs new file mode 100644 index 0000000..fe1174d --- /dev/null +++ b/TaskbarSample/MainWindow.xaml.cs @@ -0,0 +1,141 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace TaskbarSample +{ + using System; + using System.Windows; + using Microsoft.Windows.Shell; + + public partial class MainWindow : Window + { + public MainWindow() + { + InitializeComponent(); + } + + private bool DeferApply + { + get + { + return _deferApply.IsChecked ?? false; + } + } + + private void ThumbButtonInfo_Click(object sender, EventArgs e) + { + } + + private void JumpTask_AddToRecent(object sender, RoutedEventArgs e) + { + JumpTask jt = GenerateJumpTask(); + JumpList.AddToRecentCategory(jt); + } + + private void JumpTask_AddToCategory(object sender, RoutedEventArgs e) + { + JumpTask jt = GenerateJumpTask(); + var jl = JumpList.GetJumpList(Application.Current); + jl.JumpItems.Add(jt); + if (!DeferApply) + { + jl.Apply(); + } + } + + private void JumpPath_AddToRecent(object sender, RoutedEventArgs e) + { + JumpPath jp = GenerateJumpPath(); + JumpList.AddToRecentCategory(jp); + } + + private void JumpPath_AddToCategory(object sender, RoutedEventArgs e) + { + JumpPath jp = GenerateJumpPath(); + var jl = JumpList.GetJumpList(Application.Current); + jl.JumpItems.Add(jp); + if (!DeferApply) + { + jl.Apply(); + } + } + + private void JumpList_Clear(object sender, RoutedEventArgs e) + { + var jl = JumpList.GetJumpList(Application.Current); + jl.JumpItems.Clear(); + if (!DeferApply) + { + jl.Apply(); + } + } + + private void JumpList_Apply(object sender, RoutedEventArgs e) + { + var jl = JumpList.GetJumpList(Application.Current); + jl.Apply(); + } + + private void UpdateKnownCategories(object sender, RoutedEventArgs e) + { + bool showRecent = _showRecentButton.IsChecked ?? false; + bool showFrequent = _showFrequentButton.IsChecked ?? false; + var jl = JumpList.GetJumpList(Application.Current); + jl.ShowRecentCategory = showRecent; + jl.ShowFrequentCategory = showFrequent; + + if (!DeferApply) + { + jl.Apply(); + } + } + + private JumpPath GenerateJumpPath() + { + return new JumpPath + { + Path = _jumpPathPathBox.Text, + CustomCategory = _jumpPathCategoryBox.Text + }; + } + + private JumpTask GenerateJumpTask() + { + var jt = new JumpTask + { + ApplicationPath = _jumpTaskAppPathBox.Text, + IconResourcePath = _jumpTaskIconResourcePathBox.Text, + Arguments = _jumpTaskArgsBox.Text, + Title = _jumpTaskTitleBox.Text, + Description = _jumpTaskDescriptionBox.Text, + WorkingDirectory = _jumpTaskWorkingDirBox.Text, + CustomCategory = _jumpTaskCategoryBox.Text, + }; + + int i; + if (int.TryParse(_jumpTaskIconResourceIndexBox.Text, out i)) + { + jt.IconResourceIndex = i; + } + + return jt; + } + + private void ClearJumpTaskInput() + { + _jumpTaskAppPathBox.Text = ""; + _jumpTaskIconResourcePathBox.Text = ""; + _jumpTaskArgsBox.Text = ""; + _jumpTaskTitleBox.Text = ""; + _jumpTaskDescriptionBox.Text = ""; + _jumpTaskWorkingDirBox.Text = ""; + _jumpTaskCategoryBox.Text = ""; + } + + private void JumpTask_ClearInput(object sender, RoutedEventArgs e) + { + ClearJumpTaskInput(); + } + } +} diff --git a/TaskbarSample/Properties/AssemblyInfo.cs b/TaskbarSample/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..1640af6 --- /dev/null +++ b/TaskbarSample/Properties/AssemblyInfo.cs @@ -0,0 +1,26 @@ +using System; +using System.Diagnostics.CodeAnalysis; +using System.Reflection; +using System.Resources; +using System.Runtime.InteropServices; +using System.Windows; + +[assembly: AssemblyTitle("TaskbarSample")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("TaskbarSample")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] +[assembly: CLSCompliant(true)] + +[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.MainAssembly)] +[assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: SuppressMessage("Microsoft.Design", "CA2210:AssembliesShouldHaveValidStrongNames")] diff --git a/TaskbarSample/TaskbarSample.csproj b/TaskbarSample/TaskbarSample.csproj new file mode 100644 index 0000000..9bb9a97 --- /dev/null +++ b/TaskbarSample/TaskbarSample.csproj @@ -0,0 +1,162 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {F7D0B052-2123-4DFD-B844-C545A1082514} + WinExe + Properties + TaskbarSample + TaskbarSample + v4.0 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + app.ico + false + + + + + + + + + + + 3.5 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true + Client + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + AllRules.ruleset + false + + + + + + + + + + + + + MSBuild:Compile + Designer + MSBuild:Compile + Designer + + + MSBuild:Compile + Designer + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + Code + + + + + + + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB} + Microsoft.Windows.Shell + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 2.0 %28x86%29 + false + + + False + .NET Framework 3.0 %28x86%29 + false + + + False + .NET Framework 3.5 + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + \ No newline at end of file diff --git a/TaskbarSample/app.config b/TaskbarSample/app.config new file mode 100644 index 0000000..6ff5afb --- /dev/null +++ b/TaskbarSample/app.config @@ -0,0 +1,3 @@ + + + diff --git a/TaskbarSample/app.ico b/TaskbarSample/app.ico new file mode 100644 index 0000000000000000000000000000000000000000..e8c7615cf93d912e05f498c79f70df437f0dccf7 GIT binary patch literal 98182 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 MWk$*mD^n={2eb0k&Hw-a literal 0 HcmV?d00001 diff --git a/WindowChromeSample/App.xaml b/WindowChromeSample/App.xaml new file mode 100644 index 0000000..5e772c7 --- /dev/null +++ b/WindowChromeSample/App.xaml @@ -0,0 +1,4 @@ + \ No newline at end of file diff --git a/WindowChromeSample/CaptionButtonRectToMarginConverter.cs b/WindowChromeSample/CaptionButtonRectToMarginConverter.cs new file mode 100644 index 0000000..e2d4f5d --- /dev/null +++ b/WindowChromeSample/CaptionButtonRectToMarginConverter.cs @@ -0,0 +1,25 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace WindowChromeSample +{ + using System; + using System.Windows; + using System.Windows.Data; + + public class CaptionButtonRectToMarginConverter : IValueConverter + { + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + var captionLocation = (Rect)value; + + return new Thickness(0, captionLocation.Top, -captionLocation.Right, 0); + } + + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + throw new NotSupportedException(); + } + } +} diff --git a/WindowChromeSample/Properties/AssemblyInfo.cs b/WindowChromeSample/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..eb15e1b --- /dev/null +++ b/WindowChromeSample/Properties/AssemblyInfo.cs @@ -0,0 +1,24 @@ +using System.Reflection; +using System.Resources; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("WindowChromeSample")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("WindowChromeSample")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2010")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +[assembly: ComVisible(false)] + +[assembly: ThemeInfo(ResourceDictionaryLocation.SourceAssembly, ResourceDictionaryLocation.SourceAssembly)] + +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/WindowChromeSample/SelectableChromeWindow.xaml b/WindowChromeSample/SelectableChromeWindow.xaml new file mode 100644 index 0000000..7b3fac1 --- /dev/null +++ b/WindowChromeSample/SelectableChromeWindow.xaml @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WindowChromeSample/SelectableChromeWindow.xaml.cs b/WindowChromeSample/SelectableChromeWindow.xaml.cs new file mode 100644 index 0000000..60c6167 --- /dev/null +++ b/WindowChromeSample/SelectableChromeWindow.xaml.cs @@ -0,0 +1,40 @@ +/**************************************************************************\ + Copyright Microsoft Corporation. All Rights Reserved. +\**************************************************************************/ + +namespace WindowChromeSample +{ + using System.Windows; + using System.Windows.Input; + using Microsoft.Windows.Shell; + + public partial class SelectableChromeWindow + { + public SelectableChromeWindow() + { + InitializeComponent(); + } + + private void _OnStandardChromeClicked(object sender, RoutedEventArgs e) + { + this.Style = null; + } + + private void _OnGradientChromeClicked(object sender, RoutedEventArgs e) + { + var style = (Style)Resources["GradientStyle"]; + this.Style = style; + } + + private void _OnGlassyChromeClicked(object sender, RoutedEventArgs e) + { + var style = (Style)Resources["GlassStyle"]; + this.Style = style; + } + + private void _OnSystemCommandCloseWindow(object sender, ExecutedRoutedEventArgs e) + { + SystemCommands.CloseWindow((Window)e.Parameter); + } + } +} diff --git a/WindowChromeSample/WindowChromeSample.csproj b/WindowChromeSample/WindowChromeSample.csproj new file mode 100644 index 0000000..0a96f21 --- /dev/null +++ b/WindowChromeSample/WindowChromeSample.csproj @@ -0,0 +1,176 @@ + + + + Debug + AnyCPU + 9.0.30729 + 2.0 + {7E654166-1387-43D9-956C-6B473C514545} + WinExe + Properties + WindowChromeSample + WindowChromeSample + v4.0 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + + + + + + + + + + + 3.5 + + false + Client + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + AllRules.ruleset + false + false + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + AllRules.ruleset + false + + + true + bin\x86\Debug\ + DEBUG;TRACE + full + x86 + bin\Debug\WindowChromeSample.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + false + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + true + false + + + bin\x86\Release\ + TRACE + true + pdbonly + x86 + bin\Release\WindowChromeSample.exe.CodeAnalysisLog.xml + true + GlobalSuppressions.cs + prompt + AllRules.ruleset + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets + true + ;C:\Program Files (x86)\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules + true + false + + + app.ico + + + + + + 3.0 + + + 3.0 + + + 3.0 + + + + + MSBuild:Compile + Designer + MSBuild:Compile + Designer + + + + SelectableChromeWindow.xaml + + + Designer + MSBuild:Compile + + + + + Code + + + + + + + {55D5297C-F1DF-4B76-A3C1-D82CC294EEBB} + Microsoft.Windows.Shell + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + true + + + False + Windows Installer 3.1 + true + + + + + + + + \ No newline at end of file diff --git a/WindowChromeSample/app.config b/WindowChromeSample/app.config new file mode 100644 index 0000000..f76deb9 --- /dev/null +++ b/WindowChromeSample/app.config @@ -0,0 +1,3 @@ + + + diff --git a/WindowChromeSample/app.ico b/WindowChromeSample/app.ico new file mode 100644 index 0000000000000000000000000000000000000000..e8c7615cf93d912e05f498c79f70df437f0dccf7 GIT binary patch literal 98182 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 MWk$*mD^n={2eb0k&Hw-a literal 0 HcmV?d00001 From cc4096d9cd88938ffab11d1e2d5a1e3e1bb7776e Mon Sep 17 00:00:00 2001 From: Joe Castro Date: Mon, 18 Feb 2013 20:07:57 -0800 Subject: [PATCH 03/21] Updating to match Fishbowl changes. --- .../Microsoft.Windows.Shell.csproj | 5 +- Microsoft.Windows.Shell/Standard/ComGuids.cs | 71 +- Microsoft.Windows.Shell/Standard/Debug.cs | 55 +- .../Standard/DoubleUtil.cs | 38 +- .../Standard/Enumerable2.cs | 288 ++++++ .../Standard/ErrorCodes.cs | 135 ++- .../Standard/FileWalker.cs | 114 +++ .../Standard/MergeableCollection.cs | 628 +++++++++++++ .../Standard/MessageWindow.cs | 12 +- .../Standard/NativeMethods.cs | 877 +++++++++++------- .../Standard/NotifyingList.cs | 187 ++++ .../Standard/ShellProvider.cs | 352 ++++++- .../Standard/SmallString.cs | 253 +++++ Microsoft.Windows.Shell/Standard/SmallUri.cs | 151 +++ .../Standard/Standard.csproj | 162 ++++ .../Standard/StreamHelper.cs | 378 +++++++- Microsoft.Windows.Shell/Standard/Utilities.cs | 450 ++++----- Microsoft.Windows.Shell/Standard/Verify.cs | 37 +- .../Standard/WicProvider.cs | 648 +++++++++++++ .../Standard/WindowExtensions.cs | 137 +++ .../Standard/Wpf/CornerRadiusAnimation.cs | 541 +++++++++++ .../Standard/Wpf/CornerRadiusAnimationBase.cs | 191 ++++ .../Standard/{ => Wpf}/DpiHelper.cs | 14 +- .../Standard/Wpf/GlassHelper.cs | 283 ++++++ .../Standard/Wpf/MshtmlProvider.cs | 407 ++++++++ .../Standard/Wpf/SplashScreen.cs | 344 +++++++ .../Standard/Wpf/Utilities.Wpf.cs | 411 ++++++++ Microsoft.Windows.Shell/WindowChrome.cs | 125 ++- Microsoft.Windows.Shell/WindowChromeWorker.cs | 382 ++++---- 29 files changed, 6811 insertions(+), 865 deletions(-) create mode 100644 Microsoft.Windows.Shell/Standard/Enumerable2.cs create mode 100644 Microsoft.Windows.Shell/Standard/FileWalker.cs create mode 100644 Microsoft.Windows.Shell/Standard/MergeableCollection.cs create mode 100644 Microsoft.Windows.Shell/Standard/NotifyingList.cs create mode 100644 Microsoft.Windows.Shell/Standard/SmallString.cs create mode 100644 Microsoft.Windows.Shell/Standard/SmallUri.cs create mode 100644 Microsoft.Windows.Shell/Standard/Standard.csproj create mode 100644 Microsoft.Windows.Shell/Standard/WicProvider.cs create mode 100644 Microsoft.Windows.Shell/Standard/WindowExtensions.cs create mode 100644 Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimation.cs create mode 100644 Microsoft.Windows.Shell/Standard/Wpf/CornerRadiusAnimationBase.cs rename Microsoft.Windows.Shell/Standard/{ => Wpf}/DpiHelper.cs (86%) create mode 100644 Microsoft.Windows.Shell/Standard/Wpf/GlassHelper.cs create mode 100644 Microsoft.Windows.Shell/Standard/Wpf/MshtmlProvider.cs create mode 100644 Microsoft.Windows.Shell/Standard/Wpf/SplashScreen.cs create mode 100644 Microsoft.Windows.Shell/Standard/Wpf/Utilities.Wpf.cs diff --git a/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj b/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj index dc2cde5..7869ff3 100644 --- a/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj +++ b/Microsoft.Windows.Shell/Microsoft.Windows.Shell.csproj @@ -118,7 +118,6 @@ - @@ -126,6 +125,10 @@ + + Code + + diff --git a/Microsoft.Windows.Shell/Standard/ComGuids.cs b/Microsoft.Windows.Shell/Standard/ComGuids.cs index 7a3b522..6c830cc 100644 --- a/Microsoft.Windows.Shell/Standard/ComGuids.cs +++ b/Microsoft.Windows.Shell/Standard/ComGuids.cs @@ -1,15 +1,34 @@ -/**************************************************************************\ - Copyright Microsoft Corporation. All Rights Reserved. -\**************************************************************************/ - -namespace Standard +namespace Standard { internal static partial class IID { + ///