зеркало из https://github.com/microsoft/TeamMate.git
Clean build to prepare for github build (#24)
* Fix build * * Remove MSBuildTasks dependencies * * Remove x86 build force directive * * Fix ForceToForeground not to use interop * * Remove attach screenshot * * Fix build error * * Remove Shell32 calls and all consumers * * Remove attach screen recording Co-authored-by: Marcus Markiewicz <marcusm@microsoft.com>
This commit is contained in:
Родитель
6597a3e890
Коммит
4d6f0a4ff0
Двоичные данные
Source/Build/Libraries/MSBuildTasks.dll
Двоичные данные
Source/Build/Libraries/MSBuildTasks.dll
Двоичный файл не отображается.
|
@ -44,6 +44,4 @@ Copyright (C) Microsoft Corporation. All rights reserved.
|
|||
<OfficeExternalPath>$(ExternalPath)\Office\14.0</OfficeExternalPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<UsingTask TaskName="MSBuildTasks.KillTask" AssemblyFile="$(BuildScripts)\Libraries\MSBuildTasks.dll" />
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -78,7 +78,6 @@
|
|||
<Compile Include="Native\PropertyKey.cs" />
|
||||
<Compile Include="Native\Propsys.cs" />
|
||||
<Compile Include="Native\PropVariant.cs" />
|
||||
<Compile Include="Native\Shell32.cs" />
|
||||
<Compile Include="Native\ComStreamAdapter.cs" />
|
||||
<Compile Include="Native\StreamAdapter.cs" />
|
||||
<Compile Include="Native\Structs.cs" />
|
||||
|
@ -138,7 +137,6 @@
|
|||
<Compile Include="Windows\Controls\ImageViewer.xaml.cs">
|
||||
<DependentUpon>ImageViewer.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\Controls\Preview\IFilePreviewPlugin.cs" />
|
||||
<Compile Include="Windows\Controls\SplitViewButton.cs" />
|
||||
<Compile Include="Windows\Controls\Symbol.cs" />
|
||||
<Compile Include="Windows\Controls\SymbolIcon.cs" />
|
||||
|
@ -160,8 +158,6 @@
|
|||
<Compile Include="Validation\PropertyValidationRuleBuilder.cs" />
|
||||
<Compile Include="Validation\Validator.cs" />
|
||||
<Compile Include="Web\HttpUtility.cs" />
|
||||
<Compile Include="Win32\FileTypeInfo.cs" />
|
||||
<Compile Include="Win32\FileTypeRegistry.cs" />
|
||||
<Compile Include="Win32\ProtocolUtilities.cs" />
|
||||
<Compile Include="Win32\RegistryViewUtilities.cs" />
|
||||
<Compile Include="Win32\UnsafeFileExtensions.cs" />
|
||||
|
@ -184,23 +180,6 @@
|
|||
<Compile Include="Windows\Controls\HintTextAdorner.cs" />
|
||||
<Compile Include="Windows\Controls\MetroAnimations.cs" />
|
||||
<Compile Include="Windows\Controls\RibbonWindow.cs" />
|
||||
<Compile Include="Windows\Controls\Preview\FilePreviewControl.xaml.cs">
|
||||
<DependentUpon>FilePreviewControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\Controls\Preview\IFilePreviewControl.cs" />
|
||||
<Compile Include="Windows\Controls\Preview\ImagePreviewControl.xaml.cs">
|
||||
<DependentUpon>ImagePreviewControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\Controls\Preview\LoadEventArgs.cs" />
|
||||
<Compile Include="Windows\Controls\Preview\NativePreviewControl.xaml.cs">
|
||||
<DependentUpon>NativePreviewControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\Controls\Preview\VideoPreviewControl.xaml.cs">
|
||||
<DependentUpon>VideoPreviewControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\Controls\Preview\WebPreviewControl.xaml.cs">
|
||||
<DependentUpon>WebPreviewControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\Controls\ProgressDialog.xaml.cs">
|
||||
<DependentUpon>ProgressDialog.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -242,12 +221,6 @@
|
|||
<Compile Include="Windows\MVVM\ViewAttribute.cs" />
|
||||
<Compile Include="Windows\MVVM\ViewCatalog.cs" />
|
||||
<Compile Include="Windows\Transfer\FileGroupDataObject.cs" />
|
||||
<Compile Include="Windows\Forms\NativePreviewControl.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Windows\Forms\NativePreviewControl.designer.cs">
|
||||
<DependentUpon>NativePreviewControl.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Windows\Forms\TemporaryGlobalCursor.cs" />
|
||||
<Compile Include="Windows\Input\RelayCommand.cs" />
|
||||
<Compile Include="Windows\Input\RoutedCommandBase.cs" />
|
||||
|
@ -257,19 +230,11 @@
|
|||
<Compile Include="Windows\Interop\ApplicationHotKeys.cs" />
|
||||
<Compile Include="Windows\Interop\InteropUtilities.cs" />
|
||||
<Compile Include="Windows\LogicalTreeUtilities.cs" />
|
||||
<Compile Include="Windows\Media\Capture\BoundsSelectionWindow.cs" />
|
||||
<Compile Include="Windows\Media\Capture\ScreenCapture.cs" />
|
||||
<Compile Include="Windows\Media\Imaging\BitmapUtilities.cs" />
|
||||
<Compile Include="Windows\Media\VisualTreeUtilities.cs" />
|
||||
<Compile Include="Windows\MVVM\View.cs" />
|
||||
<Compile Include="Windows\MVVM\ViewModelBase.cs" />
|
||||
<Compile Include="Windows\Shell\ApplicationInstance.cs" />
|
||||
<Compile Include="Windows\Shell\ShellFileInfo.cs" />
|
||||
<Compile Include="Windows\Shell\ShellFileInfoCache.cs" />
|
||||
<Compile Include="Windows\Shell\ShellUtilities.cs" />
|
||||
<Compile Include="Windows\Shell\SystemImageCache.cs" />
|
||||
<Compile Include="Windows\Shell\SystemImageInfo.cs" />
|
||||
<Compile Include="Windows\Shell\SystemImageList.cs" />
|
||||
<Compile Include="Windows\Shell\WindowInfo.cs" />
|
||||
<Compile Include="Windows\SystemIcons.cs" />
|
||||
<Compile Include="Windows\TemporaryCursorManager.cs" />
|
||||
|
@ -289,9 +254,6 @@
|
|||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>FoundationResources.Designer.cs</LastGenOutput>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Windows\Forms\NativePreviewControl.resx">
|
||||
<DependentUpon>NativePreviewControl.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Resources\ResourceStrings.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>ResourceStrings.Designer.cs</LastGenOutput>
|
||||
|
@ -330,26 +292,6 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\Controls\Preview\FilePreviewControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\Controls\Preview\ImagePreviewControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\Controls\Preview\NativePreviewControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\Controls\Preview\VideoPreviewControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\Controls\Preview\WebPreviewControl.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Windows\Controls\ProgressDialog.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
@ -384,17 +326,6 @@
|
|||
<Content Include="Resources\Cursors\OpenHand.cur" />
|
||||
<Resource Include="Resources\Icons\Empty.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<COMReference Include="Shell32">
|
||||
<Guid>{50A7E9B0-70EF-11D1-B75A-00A0C90564FE}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\Fonts\segmdl2.ttf">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Native
|
||||
{
|
||||
/// <summary>
|
||||
/// Exposes PInvoke method wrappers for functions in shell32.dll.
|
||||
/// </summary>
|
||||
public static partial class NativeMethods
|
||||
{
|
||||
[DllImport("shell32.dll", EntryPoint = "ExtractIconA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
|
||||
public static extern IntPtr ExtractIcon(IntPtr hInst, string lpszExeFileName, int nIconIndex);
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern uint ExtractIconEx(string szFileName, int nIconIndex, IntPtr[] phiconLarge, IntPtr[] phiconSmall, uint nIcons);
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Auto)]
|
||||
public static extern IntPtr SHGetFileInfo(string pszPath, uint dwFileAttributes, ref SHFILEINFO psfi, uint cbFileInfo, uint uFlags);
|
||||
|
||||
/// <summary>
|
||||
/// SHGetImageList is not exported correctly in XP. See KB316931
|
||||
/// http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q316931
|
||||
/// Apparently (and hopefully) ordinal 727 isn't going to change.
|
||||
/// </summary>
|
||||
[DllImport("shell32.dll", EntryPoint = "#727")]
|
||||
public extern static int SHGetImageList(int iImageList, ref Guid riid, ref IImageList ppv);
|
||||
|
||||
[DllImport("shell32.dll", EntryPoint = "#727")]
|
||||
public extern static int SHGetImageListHandle(int iImageList, ref Guid riid, ref IntPtr handle);
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
|
||||
public static extern void SHCreateItemFromParsingName(
|
||||
[In][MarshalAs(UnmanagedType.LPWStr)] string pszPath,
|
||||
[In] IntPtr pbc,
|
||||
[In][MarshalAs(UnmanagedType.LPStruct)] Guid riid,
|
||||
[Out][MarshalAs(UnmanagedType.Interface, IidParameterIndex = 2)] out IShellItem ppv);
|
||||
}
|
||||
}
|
|
@ -1,885 +0,0 @@
|
|||
using Microsoft.Tools.TeamMate.Foundation.Diagnostics;
|
||||
using Microsoft.Tools.TeamMate.Foundation.Native;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Win32
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides information that describes a file type, based on file extension, according to the
|
||||
/// information in the system registry.
|
||||
/// </summary>
|
||||
public class FileTypeInfo
|
||||
{
|
||||
// See implementation information in
|
||||
// http://msdn.microsoft.com/en-us/library/windows/desktop/cc144067(v=vs.85).aspx
|
||||
|
||||
private string description;
|
||||
private string defaultOpenExe;
|
||||
private bool selfOpens;
|
||||
private string fullPathToDefaultOpenExe;
|
||||
private string defaultOpenExeDescription;
|
||||
private Guid? previewHandlerId;
|
||||
private string previewHandlerDescription;
|
||||
private bool hasThumbnailProvider;
|
||||
private bool hasCustomIcon;
|
||||
|
||||
private Parts loadedParts;
|
||||
|
||||
private static Lazy<FileTypeInfo> lazyDefaultFile = new Lazy<FileTypeInfo>(() => FromExtension(String.Empty));
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default file information (no extension).
|
||||
/// </summary>
|
||||
public static FileTypeInfo DefaultFile
|
||||
{
|
||||
get { return lazyDefaultFile.Value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance for a given extension by querying the registry for file information,
|
||||
/// lazily loading information for the file type as needed from the registry.
|
||||
/// </summary>
|
||||
/// <param name="extension">The extension.</param>
|
||||
/// <returns>The created type.</returns>
|
||||
/// <remarks>
|
||||
/// Prefer to use a FileTypeRegistry instace which will cache information for a given extension.
|
||||
/// </remarks>
|
||||
public static FileTypeInfo FromExtension(string extension)
|
||||
{
|
||||
Assert.ParamIsNotNull(extension, "extension");
|
||||
|
||||
FileTypeInfo info = new FileTypeInfo(extension);
|
||||
|
||||
if (!String.IsNullOrEmpty(extension))
|
||||
{
|
||||
using (RegistryKey classKey = Registry.ClassesRoot.OpenSubKey(extension))
|
||||
{
|
||||
if (classKey != null)
|
||||
{
|
||||
info.DefaultHandler = classKey.GetValue(null) as string;
|
||||
info.PerceivedType = classKey.GetValue("PerceivedType") as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance.
|
||||
/// </summary>
|
||||
/// <param name="extension">The extension.</param>
|
||||
private FileTypeInfo(string extension)
|
||||
{
|
||||
Assert.ParamIsNotNull(extension, "extension");
|
||||
|
||||
this.Extension = extension.ToLower();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures all of the file type information has been fully loaded from the registry.
|
||||
/// </summary>
|
||||
public void EnsureFullyLoaded()
|
||||
{
|
||||
EnsureLoaded(Parts.All);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file extension.
|
||||
/// </summary>
|
||||
public string Extension { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default handler string for the registered program that can open the file,
|
||||
/// or <c>null</c> if not set.
|
||||
/// </summary>
|
||||
public string DefaultHandler { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the perceived type name of this file type, or <c>null</c> if not defined.
|
||||
/// </summary>
|
||||
public string PerceivedType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this file type is perceived as an image, based on the PerceivedType.
|
||||
/// </summary>
|
||||
public bool IsPerceivedAsImage
|
||||
{
|
||||
get { return PerceivedTypeIs("image"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this file type is perceived as a video file, based on the PerceivedType.
|
||||
/// </summary>
|
||||
public bool IsPerceivedAsVideo
|
||||
{
|
||||
get { return PerceivedTypeIs("video"); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the perceived type is a given value.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns><c>true</c> if the perceived type matches the value; otherwise, <c>false</c></returns>
|
||||
private bool PerceivedTypeIs(string value)
|
||||
{
|
||||
return String.Equals(PerceivedType, value, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description, or <c>null</c> if not available.
|
||||
/// </summary>
|
||||
public string Description
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureLoaded(Parts.Description);
|
||||
return this.description;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to the default executable associated to open this file. This could be a full path,
|
||||
/// or just an exe filename to be found under the PATH environment variable. Returns <c>null</c> if no
|
||||
/// executable is associated with this file type.
|
||||
/// </summary>
|
||||
public string DefaultOpenExe
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureLoaded(Parts.DefaultOpenExe);
|
||||
return this.defaultOpenExe;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the full path to default executable associated to open this file. Returns <c>null</c> if
|
||||
/// no executable is associated with this file type, or, in the case of a relative executable name,
|
||||
/// if the executable coudl not be found in the current PATH.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The full path to default open executable.
|
||||
/// </value>
|
||||
public string FullPathToDefaultOpenExe
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureLoaded(Parts.FullPathToDefaultOpenExe);
|
||||
return this.fullPathToDefaultOpenExe;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description for the default executable associated to open this file, or <c>null</c>
|
||||
/// if not available.
|
||||
/// </summary>
|
||||
public string DefaultOpenExeDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureLoaded(Parts.DefaultOpenExeDescription);
|
||||
return this.defaultOpenExeDescription;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the file self opens or not (e.g. .exe or .ps1 files self open
|
||||
/// themselves).
|
||||
/// </summary>
|
||||
public bool SelfOpens
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureLoaded(Parts.DefaultOpenExe);
|
||||
return this.selfOpens;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the preview handler identifier if available, or <c>null</c> if not defined.
|
||||
/// </summary>
|
||||
public Guid? PreviewHandlerId
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureLoaded(Parts.PreviewHandler);
|
||||
return this.previewHandlerId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the preview handler description, or <c>null</c> if not defined.
|
||||
/// </summary>
|
||||
public string PreviewHandlerDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureLoaded(Parts.PreviewHandler);
|
||||
return this.previewHandlerDescription;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this file type has a preview handler.
|
||||
/// </summary>
|
||||
public bool HasPreviewHandler
|
||||
{
|
||||
get { return PreviewHandlerId != null; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this file type has a thumbnail provider.
|
||||
/// </summary>
|
||||
public bool HasThumbnailProvider
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureLoaded(Parts.ThumbnailProvider);
|
||||
return this.hasThumbnailProvider;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this file type is potentially unsafe to open. This
|
||||
/// should be used to prompt/warn the user if attempting to open this file type.
|
||||
/// </summary>
|
||||
public bool IsPotentiallyUnsafeToOpen
|
||||
{
|
||||
get
|
||||
{
|
||||
return SelfOpens || UnsafeFileExtensions.IsUnsafeFileExtension(Extension);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this file type has a custom icon.
|
||||
/// </summary>
|
||||
public bool HasCustomIcon
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureLoaded(Parts.IconHandler);
|
||||
return this.hasCustomIcon;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts this file type to a file filter expression that can be used in file open dialog
|
||||
/// properties.
|
||||
/// </summary>
|
||||
public string ToFileFilter()
|
||||
{
|
||||
if (!String.IsNullOrEmpty(Extension))
|
||||
{
|
||||
return String.Format("{0} (*{1})|*{1}", Description, Extension);
|
||||
}
|
||||
else
|
||||
{
|
||||
return "All files (*.*)|*.*";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that one or more parts of this file type info have been loaded from the registry.
|
||||
/// </summary>
|
||||
/// <param name="parts">The parts to load.</param>
|
||||
private void EnsureLoaded(Parts parts)
|
||||
{
|
||||
Parts missingParts = (parts & ~loadedParts);
|
||||
|
||||
if (missingParts == Parts.None)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
loadedParts |= missingParts;
|
||||
|
||||
if ((missingParts & Parts.Description) == Parts.Description)
|
||||
{
|
||||
this.description = GetTypeName(Extension);
|
||||
}
|
||||
|
||||
if ((missingParts & Parts.DefaultOpenExe) == Parts.DefaultOpenExe)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(DefaultHandler))
|
||||
{
|
||||
bool selfOpens;
|
||||
this.defaultOpenExe = GetExePathFromDefaultCommand(DefaultHandler, out selfOpens);
|
||||
this.selfOpens = selfOpens;
|
||||
}
|
||||
}
|
||||
|
||||
if ((missingParts & Parts.FullPathToDefaultOpenExe) == Parts.FullPathToDefaultOpenExe)
|
||||
{
|
||||
if (!String.IsNullOrEmpty(DefaultOpenExe))
|
||||
{
|
||||
this.fullPathToDefaultOpenExe = GetFullPathToExe(DefaultOpenExe);
|
||||
}
|
||||
}
|
||||
|
||||
if ((missingParts & Parts.DefaultOpenExeDescription) == Parts.DefaultOpenExeDescription)
|
||||
{
|
||||
// Laugh, but you could register a file on another box... We won't spend time on those...
|
||||
if (!String.IsNullOrEmpty(FullPathToDefaultOpenExe) && !FullPathToDefaultOpenExe.StartsWith(@"\\"))
|
||||
{
|
||||
this.defaultOpenExeDescription = GetExeDescription(FullPathToDefaultOpenExe);
|
||||
}
|
||||
}
|
||||
|
||||
if ((missingParts & Parts.PreviewHandler) == Parts.PreviewHandler)
|
||||
{
|
||||
this.previewHandlerId = this.GetPreviewHandlerId();
|
||||
if (this.previewHandlerId != null)
|
||||
{
|
||||
this.previewHandlerDescription = GetPreviewHandlerDescription(this.previewHandlerId.Value);
|
||||
}
|
||||
}
|
||||
|
||||
if ((missingParts & Parts.ThumbnailProvider) == Parts.ThumbnailProvider)
|
||||
{
|
||||
this.hasThumbnailProvider = this.GetHasThumbnailProvider();
|
||||
}
|
||||
|
||||
if ((missingParts & Parts.IconHandler) == Parts.IconHandler)
|
||||
{
|
||||
this.hasCustomIcon = this.GetHasCustomIcon();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the registered name for the given extension.
|
||||
/// </summary>
|
||||
/// <param name="extension">The extension.</param>
|
||||
private static string GetTypeName(string extension)
|
||||
{
|
||||
string result = ShGetFileInfoTypeName(extension);
|
||||
if (String.IsNullOrEmpty(result))
|
||||
{
|
||||
// Extension not registered, just return the default name...
|
||||
result = ShGetFileInfoTypeName(null);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invokes the shell function to the get the registered file type name for the given extension.
|
||||
/// </summary>
|
||||
/// <param name="extension">The extension.</param>
|
||||
private static string ShGetFileInfoTypeName(string extension)
|
||||
{
|
||||
if (String.IsNullOrEmpty(extension))
|
||||
{
|
||||
// SHGetFileInfo does not like null or empty, so just use a dummy file extension instead
|
||||
extension = "DummyFileName";
|
||||
}
|
||||
|
||||
SHFILEINFO info = new SHFILEINFO();
|
||||
FILE_ATTRIBUTE attr = FILE_ATTRIBUTE.FILE_ATTRIBUTE_NORMAL;
|
||||
SHGFI flags = SHGFI.SHGFI_TYPENAME | SHGFI.SHGFI_USEFILEATTRIBUTES;
|
||||
NativeMethods.SHGetFileInfo(extension, (uint)attr, ref info, SHFILEINFO.Size, (uint)flags);
|
||||
return info.szTypeName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the executable path (absolute or relative) for the default command associated with a file type.
|
||||
/// </summary>
|
||||
/// <param name="className">Name of the class associated as the default handler.</param>
|
||||
/// <param name="selfOpens">An output parameter that indicates if the file type self opens itself or not..</param>
|
||||
/// <returns>The executable path, or <c>null</c> if not defined.</returns>
|
||||
private static string GetExePathFromDefaultCommand(string className, out bool selfOpens)
|
||||
{
|
||||
selfOpens = false;
|
||||
string command = null;
|
||||
|
||||
// http://msdn.microsoft.com/en-us/library/bb165967.aspx
|
||||
// The default verb is the action that is executed when a user double-clicks a file in Windows Explorer.
|
||||
// The default verb is the verb specified as the default value for the HKEY_CLASSES_ROOT\progid\Shell key.
|
||||
// If no value is specified, the default verb is the first verb specified in the HKEY_CLASSES_ROOT\progid\Shell key list.
|
||||
|
||||
string shellPath = String.Format(@"{0}\Shell", className);
|
||||
using (RegistryKey shellKey = Registry.ClassesRoot.OpenSubKey(shellPath))
|
||||
{
|
||||
if (shellKey != null)
|
||||
{
|
||||
string defaultVerb = shellKey.GetValue(null) as string;
|
||||
if (String.IsNullOrEmpty(defaultVerb))
|
||||
{
|
||||
defaultVerb = shellKey.GetSubKeyNames().FirstOrDefault();
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(defaultVerb))
|
||||
{
|
||||
string verbPath = String.Format(@"{0}\Command", defaultVerb);
|
||||
using (RegistryKey openCommandKey = shellKey.OpenSubKey(verbPath))
|
||||
{
|
||||
if (openCommandKey != null)
|
||||
{
|
||||
command = openCommandKey.GetValue(null) as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (!String.IsNullOrEmpty(command)) ? ExtractExeFromCommand(command, out selfOpens) : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the executable path from a registered verb command.
|
||||
/// </summary>
|
||||
/// <param name="command">The command value from the registry.</param>
|
||||
/// <param name="selfOpens">An output parameter that indicates if the file type self opens itself or not..</param>
|
||||
/// <returns>The executable path, or <c>null</c> if not defined.</returns>
|
||||
private static string ExtractExeFromCommand(string command, out bool selfOpens)
|
||||
{
|
||||
selfOpens = false;
|
||||
|
||||
string exe = null;
|
||||
|
||||
bool strippedQuotes = false;
|
||||
|
||||
int indexOfQuote = command.IndexOf('"');
|
||||
if (indexOfQuote == 0)
|
||||
{
|
||||
// Somme exe files have quotes to deal with spaces in filenames
|
||||
strippedQuotes = true;
|
||||
int nextQuote = command.IndexOf('"', 1);
|
||||
if (nextQuote > 0)
|
||||
{
|
||||
command = command.Substring(1, nextQuote - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This seems like a broken entry (no ending quote?), we'll still try and make it better...
|
||||
command = command.Substring(1).Trim();
|
||||
}
|
||||
}
|
||||
else if (indexOfQuote > 0)
|
||||
{
|
||||
// This is a case where the command didn't start with a quote, but a quote typically
|
||||
// means the start of a parameter (sometimes the first parameter).
|
||||
command = command.Substring(0, indexOfQuote).TrimEnd();
|
||||
}
|
||||
|
||||
// Some files run "themselves" (e.g. .exe, .bat, etc)
|
||||
selfOpens = command.StartsWith("%1");
|
||||
if (!selfOpens)
|
||||
{
|
||||
exe = command;
|
||||
|
||||
if (!strippedQuotes)
|
||||
{
|
||||
// At this point, we have a path without quotes... However, there might still be parameters being
|
||||
// passed to the EXE. Here, we try to figure that out.
|
||||
int indexOfSpace = command.IndexOf(' ');
|
||||
if (indexOfSpace > 0)
|
||||
{
|
||||
// Could be e.g.:
|
||||
// C:\Program Files (x86)\QuickTime\QuickTimePlayer.exe
|
||||
// C:\Windows\system32\NOTEPAD.EXE %1
|
||||
// C:\Windows\system32\rasphone.exe -f
|
||||
// C:\Windows\system32\rundll32.exe cryptext.dll,CryptExtOpenPKCS7 %1
|
||||
|
||||
// Find the first occurrence of ".exe " (with a space);
|
||||
int firstIndexOfExeAndSpace = command.IndexOf(".exe ", StringComparison.OrdinalIgnoreCase);
|
||||
if (firstIndexOfExeAndSpace > 0)
|
||||
{
|
||||
exe = command.Substring(0, firstIndexOfExeAndSpace + 4);
|
||||
}
|
||||
else if (command.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
exe = command;
|
||||
}
|
||||
else
|
||||
{
|
||||
// E.g. very weird cases...
|
||||
// C:\Windows\system32\perfmon
|
||||
string firstPart = command.Substring(0, indexOfSpace);
|
||||
|
||||
if (String.IsNullOrEmpty(TryGetExtension(firstPart)))
|
||||
{
|
||||
// Some commands are naughty and do not put an extension on them, fix them up (needed to find file)
|
||||
firstPart += ".exe";
|
||||
}
|
||||
|
||||
exe = firstPart;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return exe;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the extension of what might be a file path.
|
||||
/// </summary>
|
||||
/// <param name="maybeAFile">Potentially a file path.</param>
|
||||
/// <returns>The extension, or <c>null</c> if it was not a valid file path.</returns>
|
||||
private static string TryGetExtension(string maybeAFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Path.GetExtension(maybeAFile);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description of an executable file.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The path to the executable.</param>
|
||||
/// <returns>The description, or the file name if one was not defined.</returns>
|
||||
private static string GetExeDescription(string filePath)
|
||||
{
|
||||
string description = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(filePath);
|
||||
description = fvi.FileDescription;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Warn(e);
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(description))
|
||||
{
|
||||
description = Path.GetFileName(filePath);
|
||||
}
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the absolute full path to an executable, attempting to resolve the file path
|
||||
/// under the PATH environment variable if it was not a rooted path.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The executable.</param>
|
||||
/// <returns>The full path, or <c>null</c> if it could not be resolved.</returns>
|
||||
private static string GetFullPathToExe(string filePath)
|
||||
{
|
||||
if (!Path.IsPathRooted(filePath))
|
||||
{
|
||||
foreach (var path in GetEnvironmentPath())
|
||||
{
|
||||
string fullPath = Path.Combine(path, filePath);
|
||||
if (Path.IsPathRooted(filePath) && File.Exists(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return filePath;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Opens the preferred registry sub key, in order of precendence, for the current file extension
|
||||
/// and subkey path.
|
||||
/// </summary>
|
||||
/// <param name="keyName">The sub key name to find.</param>
|
||||
/// <returns>The first matching existing registry key, in order of precedence, or <c>null</c> if not found.</returns>
|
||||
/// <remarks>
|
||||
/// See the precedence rules in http://msdn.microsoft.com/en-us/library/windows/apps/bb776871(v=vs.85).aspx.
|
||||
/// </remarks>
|
||||
private RegistryKey OpenPreferredSubKey(string keyName)
|
||||
{
|
||||
//
|
||||
RegistryKey subKey = null;
|
||||
|
||||
if (!String.IsNullOrEmpty(Extension))
|
||||
{
|
||||
subKey = Registry.ClassesRoot.OpenSubKey(Extension + @"\" + keyName);
|
||||
|
||||
if (subKey == null && DefaultHandler != null)
|
||||
{
|
||||
subKey = Registry.ClassesRoot.OpenSubKey(DefaultHandler + @"\" + keyName);
|
||||
}
|
||||
|
||||
if (subKey == null)
|
||||
{
|
||||
subKey = Registry.ClassesRoot.OpenSubKey(@"SystemFileAssociations\" + Extension + @"\" + keyName);
|
||||
}
|
||||
|
||||
if (subKey == null && !String.IsNullOrEmpty(PerceivedType))
|
||||
{
|
||||
subKey = Registry.ClassesRoot.OpenSubKey(@"SystemFileAssociations\" + PerceivedType + @"\" + keyName);
|
||||
}
|
||||
}
|
||||
|
||||
return subKey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the preview handler identifier, or <c>null</c> if not available.
|
||||
/// </summary>
|
||||
private Guid? GetPreviewHandlerId()
|
||||
{
|
||||
return GetShellExtensionId("{8895b1c6-b41f-4c1c-a562-0d564250836f}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolen that determines if the file type has a thumbnail provider.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private bool GetHasThumbnailProvider()
|
||||
{
|
||||
return GetShellExtensionId("{E357FCCD-A995-4576-B01F-234630154E96}") != null
|
||||
|| GetShellExtensionId("{BB2E617C-0920-11d1-9A0B-00C04FC2D6C1}") != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a boolean that determines if the file type has a custom icon.
|
||||
/// </summary>
|
||||
private bool GetHasCustomIcon()
|
||||
{
|
||||
bool hasCustomIcon = false;
|
||||
|
||||
using (RegistryKey defaultIconKey = OpenPreferredSubKey("DefaultIcon"))
|
||||
{
|
||||
if (defaultIconKey != null)
|
||||
{
|
||||
string value = defaultIconKey.GetValue(null) as string;
|
||||
hasCustomIcon = (value != null && value == "%1");
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasCustomIcon)
|
||||
{
|
||||
hasCustomIcon = (GetShellExtensionId("IconHandler") != null);
|
||||
}
|
||||
|
||||
return hasCustomIcon;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the id of the given shell extension for the file type.
|
||||
/// </summary>
|
||||
/// <param name="extensionId">The extension identifier.</param>
|
||||
/// <returns>The corresponding guid, or <c>null</c> if none found.</returns>
|
||||
private Guid? GetShellExtensionId(string extensionId)
|
||||
{
|
||||
Guid? result = null;
|
||||
|
||||
string path = @"shellex\" + extensionId;
|
||||
|
||||
using (RegistryKey shellExtensionKey = OpenPreferredSubKey(path))
|
||||
{
|
||||
if (shellExtensionKey != null)
|
||||
{
|
||||
string id = shellExtensionKey.GetValue(null) as string;
|
||||
if (id != null)
|
||||
{
|
||||
Guid parsed;
|
||||
if (Guid.TryParse(id, out parsed))
|
||||
{
|
||||
result = parsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description for a preview handler.
|
||||
/// </summary>
|
||||
/// <param name="id">The previe handler class id.</param>
|
||||
/// <returns>The description, or <c>null</c> if not available.</returns>
|
||||
private string GetPreviewHandlerDescription(Guid id)
|
||||
{
|
||||
string displayName = null;
|
||||
|
||||
string path = String.Format(@"CLSID\{{{0}}}", id);
|
||||
using (var key = Registry.ClassesRoot.OpenSubKey(path))
|
||||
{
|
||||
if (key != null)
|
||||
{
|
||||
// Attempt to extract the display name first from a native resource
|
||||
string displayNameValue = key.GetValue("DisplayName") as string;
|
||||
if (displayNameValue != null)
|
||||
{
|
||||
displayName = ExtractResourceStringFromRegistryValue(displayNameValue);
|
||||
}
|
||||
|
||||
// If there was no display name, fall back to the class name
|
||||
if (displayName == null)
|
||||
{
|
||||
// Failed, fall back to class description
|
||||
displayName = key.GetValue(null) as string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return displayName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts a resource string from registry value, resolving the resource string from a
|
||||
/// file if appropriate.
|
||||
/// </summary>
|
||||
/// <param name="resourceSpec">The resource specification. This could be a resource string reference or a plain string.</param>
|
||||
/// <returns>The resolved resource string.</returns>
|
||||
private static string ExtractResourceStringFromRegistryValue(string resourceSpec)
|
||||
{
|
||||
Assert.ParamIsNotNull(resourceSpec, "resourceSpec");
|
||||
|
||||
// Spec @ http://msdn.microsoft.com/en-us/library/windows/desktop/dd374120(v=vs.85).aspx
|
||||
// E.g. @%CommonProgramFiles%\System\wab32res.dll,-4650
|
||||
|
||||
string result = null;
|
||||
|
||||
if (resourceSpec.StartsWith("@"))
|
||||
{
|
||||
int indexOfSemiColon = resourceSpec.IndexOf(';');
|
||||
if (indexOfSemiColon >= 0)
|
||||
{
|
||||
// Remove comment...
|
||||
resourceSpec = resourceSpec.Substring(0, indexOfSemiColon);
|
||||
}
|
||||
|
||||
string[] split = resourceSpec.Split(',');
|
||||
if (split.Length == 2)
|
||||
{
|
||||
string path = split[0];
|
||||
string idString = split[1];
|
||||
|
||||
if (path.StartsWith("@") && idString.StartsWith("-"))
|
||||
{
|
||||
path = path.Substring(1);
|
||||
idString = idString.Substring(1);
|
||||
|
||||
if (path.Length > 0 && idString.Length > 0)
|
||||
{
|
||||
int id;
|
||||
if (Int32.TryParse(idString, out id))
|
||||
{
|
||||
path = Environment.ExpandEnvironmentVariables(path);
|
||||
result = ExtractResourceString(path, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The input registry string was not a reference to a native resource, return the string as-is.
|
||||
result = resourceSpec;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the resource string from a given file path and resource id.
|
||||
/// </summary>
|
||||
/// <param name="path">The file path.</param>
|
||||
/// <param name="id">The resource identifier.</param>
|
||||
/// <returns>The extracted string, or <c>null</c> if the string could not be extracted.</returns>
|
||||
private static string ExtractResourceString(string path, int id)
|
||||
{
|
||||
string result = null;
|
||||
|
||||
if (File.Exists(path) && id >= 0)
|
||||
{
|
||||
IntPtr hInstance = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
hInstance = NativeMethods.LoadLibrary(path);
|
||||
if (hInstance != IntPtr.Zero)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder(1024);
|
||||
int returnValue = NativeMethods.LoadString(hInstance, (uint)id, sb, sb.Capacity);
|
||||
if (returnValue > 0)
|
||||
{
|
||||
result = sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (hInstance != IntPtr.Zero)
|
||||
{
|
||||
NativeMethods.FreeLibrary(hInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all of the components of the Path environment variable.
|
||||
/// </summary>
|
||||
private static string[] GetEnvironmentPath()
|
||||
{
|
||||
return Environment.GetEnvironmentVariable("Path").Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hash code for this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
|
||||
/// </returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Extension.GetHashCode();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the specified <see cref="System.Object" />, is equal to this instance.
|
||||
/// </summary>
|
||||
/// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
FileTypeInfo other = obj as FileTypeInfo;
|
||||
if (other != null)
|
||||
{
|
||||
return StringComparer.OrdinalIgnoreCase.Equals(Extension, other.Extension);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An enumeration of flags that describes the parts that can be lazy loaded for the FileTypeInfo object.
|
||||
/// </summary>
|
||||
[Flags]
|
||||
private enum Parts
|
||||
{
|
||||
None = 0,
|
||||
Description = 1,
|
||||
DefaultOpenExe = 2,
|
||||
FullPathToDefaultOpenExe = 4,
|
||||
DefaultOpenExeDescription = 8,
|
||||
PreviewHandler = 16,
|
||||
ThumbnailProvider = 32,
|
||||
IconHandler = 64,
|
||||
|
||||
All = Description | DefaultOpenExe | FullPathToDefaultOpenExe | DefaultOpenExeDescription | PreviewHandler | ThumbnailProvider | IconHandler
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
using Microsoft.Tools.TeamMate.Foundation.Diagnostics;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Win32
|
||||
{
|
||||
/// <summary>
|
||||
/// A registry that provides and caches information about file types.
|
||||
/// </summary>
|
||||
public class FileTypeRegistry
|
||||
{
|
||||
private Dictionary<string, FileTypeInfo> cache = new Dictionary<string, FileTypeInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private static Lazy<FileTypeRegistry> lazySingleton = new Lazy<FileTypeRegistry>(() => new FileTypeRegistry());
|
||||
|
||||
/// <summary>
|
||||
/// Gets a global shared file type registry.
|
||||
/// </summary>
|
||||
public static FileTypeRegistry Instance
|
||||
{
|
||||
get { return lazySingleton.Value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file type information for a given extension.
|
||||
/// </summary>
|
||||
/// <param name="extension">The extension.</param>
|
||||
/// <returns>The file type information.</returns>
|
||||
public FileTypeInfo GetInfo(string extension)
|
||||
{
|
||||
Assert.ParamIsNotNull(extension, "extension");
|
||||
|
||||
FileTypeInfo info;
|
||||
if (!cache.TryGetValue(extension, out info))
|
||||
{
|
||||
info = FileTypeInfo.FromExtension(extension);
|
||||
cache[extension] = info;
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file type information for a given file path, by extracting the extension
|
||||
/// for the file path.
|
||||
/// </summary>
|
||||
/// <param name="path">The path.</param>
|
||||
/// <returns>The file type information.</returns>
|
||||
public FileTypeInfo GetInfoFromPath(string path)
|
||||
{
|
||||
Assert.ParamIsNotNull(path, "path");
|
||||
|
||||
return GetInfo(Path.GetExtension(path));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears all of the cached file type information.
|
||||
/// </summary>
|
||||
public void ClearCache()
|
||||
{
|
||||
cache.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes an file type entry from the cache if it exists.
|
||||
/// </summary>
|
||||
/// <param name="extension">The extension.</param>
|
||||
public void RemoveFromCache(string extension)
|
||||
{
|
||||
cache.Remove(extension);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all registered extensions in the system (from the registry).
|
||||
/// </summary>
|
||||
public static ICollection<string> AllRegisteredExtensions
|
||||
{
|
||||
get
|
||||
{
|
||||
return Registry.ClassesRoot.GetSubKeyNames().Where(sk => sk.StartsWith(".")).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
<UserControl x:Class="Microsoft.Tools.TeamMate.Foundation.Windows.Controls.Preview.FilePreviewControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:fwc="clr-namespace:Microsoft.Tools.TeamMate.Foundation.Windows.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="500">
|
||||
<Grid>
|
||||
<Grid Name="previewControlContainer" />
|
||||
|
||||
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Name="noPreviewContainer">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" FontWeight="Bold" Foreground="Red" Name="errorTextBlock"
|
||||
HorizontalAlignment="Center"
|
||||
TextWrapping="Wrap">An error occurred attempting to preview this file.</TextBlock>
|
||||
|
||||
<TextBlock Grid.Row="1" HorizontalAlignment="Center" TextWrapping="Wrap" Name="unavailableBlock">
|
||||
Preview is not available for this file.
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Grid.Row="2" Name="externalProgramBlock" Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,24,0,0">
|
||||
<Image Name="programImage" Stretch="None" MaxWidth="32" MaxHeight="32" Margin="0,0,12,0" VerticalAlignment="Center"/>
|
||||
<TextBlock TextWrapping="Wrap" VerticalAlignment="Center" FontSize="20">
|
||||
<Hyperlink FontSize="20" Name="openExternallyHyperlink">Open in <Run Name="programName"/></Hyperlink>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Row="3" Name="previewUnavailablePluginBlock" TextWrapping="Wrap" VerticalAlignment="Center" FontSize="20" HorizontalAlignment="Center" Margin="0,24,0,0">
|
||||
<Hyperlink FontSize="20" Name="previewUnavailablePluginHyperlink"><Run Name="previewUnavailablePluginText"></Run></Hyperlink>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -1,418 +0,0 @@
|
|||
using Microsoft.Tools.TeamMate.Foundation.Diagnostics;
|
||||
using Microsoft.Tools.TeamMate.Foundation.Win32;
|
||||
using Microsoft.Tools.TeamMate.Foundation.Windows.Shell;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Controls.Preview
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for FilePreviewControl.xaml
|
||||
/// </summary>
|
||||
public partial class FilePreviewControl : UserControl
|
||||
{
|
||||
private IFilePreviewControl activeControl;
|
||||
private IList<IFilePreviewControl> registeredHandlers = new List<IFilePreviewControl>();
|
||||
|
||||
// Order matters...
|
||||
private static readonly Type[] DefaultPreviewerControlTypes = {
|
||||
typeof(ImagePreviewControl), typeof(WebPreviewControl), typeof(VideoPreviewControl), typeof(NativePreviewControl)
|
||||
};
|
||||
|
||||
private FileSystemWatcher fileSystemWatcher;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="FilePreviewControl"/> class.
|
||||
/// </summary>
|
||||
public FilePreviewControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
HideAll();
|
||||
|
||||
this.Unloaded += HandleUnloaded;
|
||||
openExternallyHyperlink.Click += HandleOpenExternallyHyperlinkClick;
|
||||
previewUnavailablePluginHyperlink.Click += HandlePreviewUnavailableHyperlinkClick;
|
||||
|
||||
RegisterDefaultPreviewerControls();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the preview plugin configured for this control.
|
||||
/// </summary>
|
||||
public IFilePreviewPlugin PreviewPlugin { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Registers the specified preview control.
|
||||
/// </summary>
|
||||
/// <param name="previewControl">The preview control.</param>
|
||||
public void Register(IFilePreviewControl previewControl)
|
||||
{
|
||||
Assert.ParamIsNotNull(previewControl, "previewControl");
|
||||
|
||||
registeredHandlers.Add(previewControl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unregisters the specified preview control.
|
||||
/// </summary>
|
||||
/// <param name="previewControl">The preview control.</param>
|
||||
public void Unregister(IFilePreviewControl previewControl)
|
||||
{
|
||||
Assert.ParamIsNotNull(previewControl, "previewControl");
|
||||
|
||||
registeredHandlers.Remove(previewControl);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can preview the specified file.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The file path.</param>
|
||||
/// <returns><c>true</c> if this control can preview that file type. Otherwise, <c>false</c>.</returns>
|
||||
public bool CanPreview(string filePath)
|
||||
{
|
||||
Assert.ParamIsNotNull(filePath, "filePath");
|
||||
|
||||
return FindPreviewControl(filePath) != null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Registers the default previewer controls.
|
||||
/// </summary>
|
||||
private void RegisterDefaultPreviewerControls()
|
||||
{
|
||||
foreach (var previewType in DefaultPreviewerControlTypes)
|
||||
{
|
||||
try
|
||||
{
|
||||
IFilePreviewControl previewControl = Activator.CreateInstance(previewType) as IFilePreviewControl;
|
||||
if (previewControl != null)
|
||||
{
|
||||
Register(previewControl);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.ErrorAndBreak(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Releases the active preview control, if one is currently active.
|
||||
/// </summary>
|
||||
private void ReleaseActivePreviewControl()
|
||||
{
|
||||
if (activeControl != null)
|
||||
{
|
||||
HideAll();
|
||||
|
||||
previewControlContainer.Children.Clear();
|
||||
activeControl.LoadCompleted -= HandlePreviewControlLoaded;
|
||||
activeControl.Clear();
|
||||
activeControl = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the configured preview file path exists.
|
||||
/// </summary>
|
||||
private bool FileExists { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the file path has an associated external program to open it.
|
||||
/// </summary>
|
||||
private bool HasExternalProgram { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The file path property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty FilePathProperty = DependencyProperty.Register(
|
||||
"FilePath", typeof(string), typeof(FilePreviewControl), new PropertyMetadata(OnFilePathChanged)
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the path of the file to be previewed.
|
||||
/// </summary>
|
||||
public string FilePath
|
||||
{
|
||||
get { return (string)GetValue(FilePathProperty); }
|
||||
set { SetValue(FilePathProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when file path changed.
|
||||
/// </summary>
|
||||
private static void OnFilePathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var control = (FilePreviewControl)d;
|
||||
control.InvalidatePreview();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invalidates the preview.
|
||||
/// </summary>
|
||||
private void InvalidatePreview()
|
||||
{
|
||||
DisposeFileSystemWatcher();
|
||||
|
||||
this.FileExists = (!String.IsNullOrEmpty(FilePath) && File.Exists(FilePath));
|
||||
|
||||
bool hasExternalProgram = false;
|
||||
FilePreviewControlState state = FilePreviewControlState.Unavailable;
|
||||
string pluginText = null;
|
||||
|
||||
// TODO: Hitting Previous/Next quickly in the preview panel ends up showing an empty preview at times.
|
||||
// I think it has to do with us not properly cancelling a previous preview request, which messes things up...
|
||||
ReleaseActivePreviewControl();
|
||||
|
||||
if (this.FileExists)
|
||||
{
|
||||
IFilePreviewControl control = FindPreviewControl(FilePath);
|
||||
if (control != null)
|
||||
{
|
||||
activeControl = control;
|
||||
|
||||
activeControl.LoadCompleted += HandlePreviewControlLoaded;
|
||||
previewControlContainer.Children.Add(activeControl.Host);
|
||||
activeControl.BeginLoad(FilePath);
|
||||
state = FilePreviewControlState.Initializing;
|
||||
|
||||
if (IsFileSystemWatcherEnabled)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.fileSystemWatcher = new FileSystemWatcher(Path.GetDirectoryName(FilePath));
|
||||
this.fileSystemWatcher.Filter = Path.GetFileName(FilePath);
|
||||
this.fileSystemWatcher.Changed += HandleFileChanged;
|
||||
this.fileSystemWatcher.EnableRaisingEvents = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.WarnAndBreak(e, "Failed to register file system watcher for {0}", FilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileTypeInfo typeInfo = FileTypeRegistry.Instance.GetInfoFromPath(FilePath);
|
||||
if (typeInfo != null && !String.IsNullOrEmpty(typeInfo.DefaultOpenExeDescription)
|
||||
&& typeInfo.FullPathToDefaultOpenExe != null && File.Exists(typeInfo.FullPathToDefaultOpenExe))
|
||||
{
|
||||
hasExternalProgram = true;
|
||||
|
||||
bool isThumbnail;
|
||||
var systemImage = SystemImageCache.Instance.GetSystemImage(typeInfo.FullPathToDefaultOpenExe);
|
||||
ImageSource image = systemImage.GetPreferredImage(SystemImageSizes.LargeSize, out isThumbnail);
|
||||
programImage.Source = image;
|
||||
programName.Text = typeInfo.DefaultOpenExeDescription;
|
||||
}
|
||||
|
||||
if (PreviewPlugin != null)
|
||||
{
|
||||
pluginText = PreviewPlugin.GetPluginText(FilePath);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasExternalProgram)
|
||||
{
|
||||
programImage.Source = null;
|
||||
programName.Text = null;
|
||||
}
|
||||
|
||||
previewUnavailablePluginText.Text = pluginText;
|
||||
|
||||
this.HasExternalProgram = hasExternalProgram;
|
||||
|
||||
InvalidateVisibility(state);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The is file system watcher enabled property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsFileSystemWatcherEnabledProperty = DependencyProperty.Register(
|
||||
"IsFileSystemWatcherEnabled", typeof(bool), typeof(FilePreviewControl)
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the preview control uses a file system watcher to update
|
||||
/// itself if the currently previewed file has changed.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if [is file system watcher enabled]; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsFileSystemWatcherEnabled
|
||||
{
|
||||
get { return (bool)GetValue(IsFileSystemWatcherEnabledProperty); }
|
||||
set { SetValue(IsFileSystemWatcherEnabledProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes the file system watcher.
|
||||
/// </summary>
|
||||
private void DisposeFileSystemWatcher()
|
||||
{
|
||||
if (this.fileSystemWatcher != null)
|
||||
{
|
||||
this.fileSystemWatcher.Dispose();
|
||||
this.fileSystemWatcher = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds the preview control that supports previewing the given file.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The file path.</param>
|
||||
/// <returns>The compatible preview control, or <c>null</c> if none can preview that file.</returns>
|
||||
private IFilePreviewControl FindPreviewControl(string filePath)
|
||||
{
|
||||
return registeredHandlers.FirstOrDefault(handler => handler.CanPreview(filePath));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Invalidates the visibility of elements.
|
||||
/// </summary>
|
||||
/// <param name="state">The state.</param>
|
||||
private void InvalidateVisibility(FilePreviewControlState state)
|
||||
{
|
||||
previewControlContainer.Visibility = (state == FilePreviewControlState.Viewing || state == FilePreviewControlState.Initializing) ? Visibility.Visible : Visibility.Hidden;
|
||||
noPreviewContainer.Visibility = (previewControlContainer.Visibility != Visibility.Visible) ? Visibility.Visible : Visibility.Hidden;
|
||||
|
||||
errorTextBlock.Visibility = (state == FilePreviewControlState.Error) ? Visibility.Visible : Visibility.Collapsed;
|
||||
unavailableBlock.Visibility = (state == FilePreviewControlState.Unavailable) ? Visibility.Visible : Visibility.Collapsed;
|
||||
externalProgramBlock.Visibility = (HasExternalProgram) ? Visibility.Visible : Visibility.Collapsed;
|
||||
previewUnavailablePluginBlock.Visibility = (!HasExternalProgram && !String.IsNullOrEmpty(previewUnavailablePluginText.Text)) ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hides all elements.
|
||||
/// </summary>
|
||||
private void HideAll()
|
||||
{
|
||||
previewControlContainer.Visibility = Visibility.Collapsed;
|
||||
noPreviewContainer.Visibility = Visibility.Collapsed;
|
||||
errorTextBlock.Visibility = Visibility.Collapsed;
|
||||
unavailableBlock.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prompts the user on whether a file should be opened.
|
||||
/// </summary>
|
||||
/// <param name="fileName">Name of the file.</param>
|
||||
/// <returns><c>true</c> if the file was safe to open or the user chose to open the file; otherwise, <c>false</c>.</returns>
|
||||
private static bool PromptShouldOpen(string fileName)
|
||||
{
|
||||
// TODO: Duplicated with AttachmentViewModel
|
||||
bool launch = true;
|
||||
|
||||
if (FileTypeRegistry.Instance.GetInfoFromPath(fileName).IsPotentiallyUnsafeToOpen)
|
||||
{
|
||||
string name = System.IO.Path.GetFileName(fileName);
|
||||
string message = String.Format("The file {0} could be harmful to your computer and data. Don't open it unless you trust the person who created the file.\n\nDo you want to proceed?", name);
|
||||
var result = MessageBox.Show(message, "Warning", MessageBoxButton.YesNo, MessageBoxImage.Warning, MessageBoxResult.No);
|
||||
launch = (result == MessageBoxResult.Yes);
|
||||
}
|
||||
|
||||
return launch;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the unloaded event.
|
||||
/// </summary>
|
||||
private void HandleUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// TODO: Need a simetrical Loaded event handler, otherwise this can leave the control in a bad state when the session
|
||||
// locks for a long time
|
||||
DisposeFileSystemWatcher();
|
||||
ReleaseActivePreviewControl();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the preview control loaded event.
|
||||
/// </summary>
|
||||
private void HandlePreviewControlLoaded(object sender, LoadEventArgs e)
|
||||
{
|
||||
this.Dispatcher.BeginInvoke((Action)delegate()
|
||||
{
|
||||
if (e.Success)
|
||||
{
|
||||
InvalidateVisibility(FilePreviewControlState.Viewing);
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: Consume error if it makes sense...
|
||||
InvalidateVisibility(FilePreviewControlState.Error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the open externally hyperlink click.
|
||||
/// </summary>
|
||||
private void HandleOpenExternallyHyperlinkClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
bool shouldOpen = (!String.IsNullOrEmpty(FilePath) && PromptShouldOpen(FilePath));
|
||||
|
||||
if (shouldOpen)
|
||||
{
|
||||
if (File.Exists(FilePath))
|
||||
{
|
||||
Process.Start(FilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
UserFeedback.ShowError(String.Format("File {0} was not found.", FilePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the preview unavailable hyperlink click.
|
||||
/// </summary>
|
||||
private async void HandlePreviewUnavailableHyperlinkClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
try
|
||||
{
|
||||
string currentFilePath = FilePath;
|
||||
if (PreviewPlugin != null && !String.IsNullOrEmpty(currentFilePath))
|
||||
{
|
||||
bool invalidatePreview = await PreviewPlugin.PrepareForPreviewAsync(currentFilePath);
|
||||
if (invalidatePreview && IsLoaded && currentFilePath == FilePath)
|
||||
{
|
||||
InvalidatePreview();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UserFeedback.ShowError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Handles the file changed.
|
||||
/// </summary>
|
||||
private void HandleFileChanged(object sender, FileSystemEventArgs e)
|
||||
{
|
||||
// The previwed file has changed, invalidate it
|
||||
this.Dispatcher.BeginInvoke((Action)InvalidatePreview);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The state of the file preview control.
|
||||
/// </summary>
|
||||
private enum FilePreviewControlState
|
||||
{
|
||||
Initializing,
|
||||
Viewing,
|
||||
Unavailable,
|
||||
Error
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
using System;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Controls.Preview
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for a file preview control that can previwe a given file type.
|
||||
/// </summary>
|
||||
public interface IFilePreviewControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the UI element used to display the preview of the file.
|
||||
/// </summary>
|
||||
FrameworkElement Host { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can preview the specified file.
|
||||
/// </summary>
|
||||
/// <param name="filename">The filename.</param>
|
||||
/// <returns><c>true</c> if this instance supports previewing that file. Otherwise, <c>false</c>.</returns>
|
||||
bool CanPreview(string filename);
|
||||
|
||||
/// <summary>
|
||||
/// Begins loading the preview for the given file..
|
||||
/// </summary>
|
||||
/// <param name="filename">The filename.</param>
|
||||
void BeginLoad(string filename);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the currently previewed file and releases any associated resources.
|
||||
/// </summary>
|
||||
void Clear();
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when file loading has completed (successfully or not).
|
||||
/// </summary>
|
||||
event EventHandler<LoadEventArgs> LoadCompleted;
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Controls.Preview
|
||||
{
|
||||
/// <summary>
|
||||
/// A plugin interface that can help install previewer pre-requisites on demand.
|
||||
/// </summary>
|
||||
public interface IFilePreviewPlugin
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the plugin text to be displayed when a file cannot be previewed but
|
||||
/// an element can be downloaded to enable preview.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The file path to be previewd.</param>
|
||||
/// <returns>The plug in text, or <c>null</c> if the file cannot be previewed.</returns>
|
||||
string GetPluginText(string filePath);
|
||||
|
||||
/// <summary>
|
||||
/// Prepares the system for previewing an item by prompting for a download or install.
|
||||
/// </summary>
|
||||
/// <param name="filePath">The file path.</param>
|
||||
/// <returns><c>true</c> if the file can be previewed and the user was prompted,
|
||||
/// otherwise <c>false</c>.</returns>
|
||||
Task<bool> PrepareForPreviewAsync(string filePath);
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
<UserControl x:Class="Microsoft.Tools.TeamMate.Foundation.Windows.Controls.Preview.ImagePreviewControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:fwc="clr-namespace:Microsoft.Tools.TeamMate.Foundation.Windows.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
x:Name="self"
|
||||
Background="White"
|
||||
d:DesignHeight="300"
|
||||
d:DesignWidth="300"
|
||||
mc:Ignorable="d">
|
||||
<fwc:ImageViewer x:Name="imageViewer" />
|
||||
</UserControl>
|
|
@ -1,74 +0,0 @@
|
|||
using Microsoft.Tools.TeamMate.Foundation.Windows.Media.Imaging;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Controls.Preview
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ImagePreviewControl.xaml
|
||||
/// </summary>
|
||||
public partial class ImagePreviewControl : UserControl, IFilePreviewControl
|
||||
{
|
||||
public event EventHandler<LoadEventArgs> LoadCompleted;
|
||||
|
||||
public ImagePreviewControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the UI element used to display the preview of the file.
|
||||
/// </summary>
|
||||
public FrameworkElement Host
|
||||
{
|
||||
get { return this; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can preview the specified file.
|
||||
/// </summary>
|
||||
/// <param name="filename">The filename.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance supports previewing that file. Otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool CanPreview(string filename)
|
||||
{
|
||||
return BitmapUtilities.IsSupportedImageFile(filename);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begins loading the preview for the given file..
|
||||
/// </summary>
|
||||
/// <param name="filename">The filename.</param>
|
||||
public async void BeginLoad(string filename)
|
||||
{
|
||||
Exception error = null;
|
||||
|
||||
try
|
||||
{
|
||||
var imageSource = await Task.Run(() => BitmapUtilities.LoadImage(filename));
|
||||
this.imageViewer.Source = imageSource;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
error = e;
|
||||
}
|
||||
|
||||
if (LoadCompleted != null)
|
||||
{
|
||||
var args = (error != null) ? new LoadEventArgs(error) : new LoadEventArgs();
|
||||
LoadCompleted(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the currently previewed file and releases any associated resources.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
this.imageViewer.Source = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// The event arguments for a preview load event.
|
||||
/// </summary>
|
||||
public class LoadEventArgs : EventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LoadEventArgs"/> class.
|
||||
/// </summary>
|
||||
public LoadEventArgs()
|
||||
{
|
||||
this.Success = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LoadEventArgs"/> class with an error.
|
||||
/// </summary>
|
||||
/// <param name="error">The error.</param>
|
||||
public LoadEventArgs(Exception error)
|
||||
{
|
||||
this.Error = error;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the load was successfull or not.
|
||||
/// </summary>
|
||||
public bool Success { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets an exception that occurred during loading, if loading failed.
|
||||
/// </summary>
|
||||
public Exception Error { get; private set; }
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
<UserControl x:Class="Microsoft.Tools.TeamMate.Foundation.Windows.Controls.Preview.NativePreviewControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:fwc="clr-namespace:Microsoft.Tools.TeamMate.Foundation.Windows.Controls"
|
||||
xmlns:fw="clr-namespace:Microsoft.Tools.TeamMate.Foundation.Windows"
|
||||
mc:Ignorable="d"
|
||||
x:Name="self"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<Grid>
|
||||
<WindowsFormsHost Name="host" Visibility="{Binding ElementName=self, Path=IsStarting, Converter={x:Static fw:Converters.InverseVisibility}}" />
|
||||
|
||||
<Grid Name="progressPanel" Margin="0,3,0,0" Visibility="{Binding ElementName=self, Path=IsStarting, Converter={x:Static fw:Converters.Visibility}}">
|
||||
<fwc:ProgressIndicator VerticalAlignment="Top" Foreground="#A0A0A0"/>
|
||||
<TextBlock Margin="0,6,0,0" HorizontalAlignment="Left" FontWeight="Bold">
|
||||
<Run Text="Starting "/>
|
||||
<Run Text="{Binding ElementName=self, Path=PreviewHandlerDescription}"/>
|
||||
<Run Text="..."/>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -1,141 +0,0 @@
|
|||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
using WinformsNativePreviewControl = Microsoft.Tools.TeamMate.Foundation.Windows.Forms.NativePreviewControl;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Controls.Preview
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for NativePreviewControl.xaml
|
||||
/// </summary>
|
||||
public partial class NativePreviewControl : UserControl, IFilePreviewControl
|
||||
{
|
||||
private WinformsNativePreviewControl nativeControl;
|
||||
|
||||
public event EventHandler<LoadEventArgs> LoadCompleted;
|
||||
|
||||
/// <summary>
|
||||
/// The is starting property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty IsStartingProperty = DependencyProperty.Register(
|
||||
"IsStarting", typeof(bool), typeof(NativePreviewControl)
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether preview is starting for this control.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if [is starting]; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsStarting
|
||||
{
|
||||
get { return (bool)GetValue(IsStartingProperty); }
|
||||
set { SetValue(IsStartingProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The preview handler description property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PreviewHandlerDescriptionProperty = DependencyProperty.Register(
|
||||
"PreviewHandlerDescription", typeof(string), typeof(NativePreviewControl)
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the preview handler description.
|
||||
/// </summary>
|
||||
public string PreviewHandlerDescription
|
||||
{
|
||||
get { return (string)GetValue(PreviewHandlerDescriptionProperty); }
|
||||
set { SetValue(PreviewHandlerDescriptionProperty, value); }
|
||||
}
|
||||
|
||||
public NativePreviewControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.nativeControl = new WinformsNativePreviewControl();
|
||||
this.nativeControl.LoadFinished += HandleLoadCompleted;
|
||||
|
||||
this.Unloaded += HandleUnloaded;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the UI element used to display the preview of the file.
|
||||
/// </summary>
|
||||
public FrameworkElement Host
|
||||
{
|
||||
get { return this; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can preview the specified file.
|
||||
/// </summary>
|
||||
/// <param name="filename">The filename.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance supports previewing that file. Otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool CanPreview(string filename)
|
||||
{
|
||||
return WinformsNativePreviewControl.CanPreview(filename);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begins loading the preview for the given file..
|
||||
/// </summary>
|
||||
/// <param name="filename">The filename.</param>
|
||||
public void BeginLoad(string filename)
|
||||
{
|
||||
this.PreviewHandlerDescription = WinformsNativePreviewControl.GetPreviewHandlerDescription(filename);
|
||||
this.IsStarting = true;
|
||||
this.nativeControl.FilePath = filename;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the currently previewed file and releases any associated resources.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
this.nativeControl.FilePath = null;
|
||||
this.PreviewHandlerDescription = null;
|
||||
this.IsStarting = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the load completed.
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender.</param>
|
||||
/// <param name="e">The <see cref="Forms.LoadEventArgs"/> instance containing the event data.</param>
|
||||
private void HandleLoadCompleted(object sender, Forms.LoadEventArgs e)
|
||||
{
|
||||
this.host.Child = nativeControl;
|
||||
this.IsStarting = false;
|
||||
|
||||
if (LoadCompleted != null)
|
||||
{
|
||||
// TODO: Mark load completed here too... Pass the right args
|
||||
var newEvent = (e.Error != null) ? new LoadEventArgs(e.Error) : new LoadEventArgs();
|
||||
LoadCompleted(this, newEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the unloaded.
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender.</param>
|
||||
/// <param name="e">The <see cref="RoutedEventArgs"/> instance containing the event data.</param>
|
||||
private void HandleUnloaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.host.Child = null;
|
||||
|
||||
if (this.nativeControl != null)
|
||||
{
|
||||
// TODO: IMPORTANT. Find another clean scenario for getting rid of the native control. In the WPF Preview Container,
|
||||
// we add/remove the control from its container, which calls unload.
|
||||
// this.nativeControl.LoadFinished -= nativeControl_LoadCompleted);
|
||||
// this.nativeControl.Dispose();
|
||||
// this.nativeControl = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
<UserControl x:Class="Microsoft.Tools.TeamMate.Foundation.Windows.Controls.Preview.VideoPreviewControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:fwc="clr-namespace:Microsoft.Tools.TeamMate.Foundation.Windows.Controls"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<Grid>
|
||||
<fwc:VideoPlayer x:Name="videoPlayer"/>
|
||||
</Grid>
|
||||
</UserControl>
|
|
@ -1,95 +0,0 @@
|
|||
using Microsoft.Tools.TeamMate.Foundation.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Controls.Preview
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for VideoPreviewControl.xaml
|
||||
/// </summary>
|
||||
public partial class VideoPreviewControl : UserControl, IFilePreviewControl
|
||||
{
|
||||
private static readonly string[] PossiblySupportedFiles = {
|
||||
".avi", ".mov", ".mp4", ".mpeg", ".wmv", ".xesc"
|
||||
};
|
||||
|
||||
private static ICollection<string> SupportedFiles = null;
|
||||
|
||||
public event EventHandler<LoadEventArgs> LoadCompleted;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="VideoPreviewControl"/> class.
|
||||
/// </summary>
|
||||
public VideoPreviewControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the UI element used to display the preview of the file.
|
||||
/// </summary>
|
||||
public FrameworkElement Host
|
||||
{
|
||||
get { return this; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can preview the specified file.
|
||||
/// </summary>
|
||||
/// <param name="filename">The filename.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance supports previewing that file. Otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool CanPreview(string filename)
|
||||
{
|
||||
ICollection<string> localSupportedFiles = SupportedFiles;
|
||||
|
||||
if (localSupportedFiles == null)
|
||||
{
|
||||
localSupportedFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
foreach (var extension in PossiblySupportedFiles)
|
||||
{
|
||||
var fileTypeInfo = FileTypeRegistry.Instance.GetInfo(extension);
|
||||
if (fileTypeInfo.IsPerceivedAsVideo)
|
||||
{
|
||||
localSupportedFiles.Add(extension);
|
||||
}
|
||||
}
|
||||
|
||||
SupportedFiles = localSupportedFiles;
|
||||
}
|
||||
|
||||
return localSupportedFiles.Contains(Path.GetExtension(filename));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begins loading the preview for the given file..
|
||||
/// </summary>
|
||||
/// <param name="filename">The filename.</param>
|
||||
public void BeginLoad(string filename)
|
||||
{
|
||||
videoPlayer.Source = new Uri(filename);
|
||||
LoadCompleted?.Invoke(this, new LoadEventArgs());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the currently previewed file and releases any associated resources.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
videoPlayer.Source = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the supported file cache.
|
||||
/// </summary>
|
||||
public static void ClearSupportedFileCache()
|
||||
{
|
||||
SupportedFiles = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
<UserControl x:Class="Microsoft.Tools.TeamMate.Foundation.Windows.Controls.Preview.WebPreviewControl"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="300" d:DesignWidth="300">
|
||||
<WebBrowser Name="webBrowser"/>
|
||||
</UserControl>
|
|
@ -1,76 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Navigation;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Controls.Preview
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for WebPreviewControl.xaml
|
||||
/// </summary>
|
||||
public partial class WebPreviewControl : UserControl, IFilePreviewControl
|
||||
{
|
||||
private static readonly ICollection<string> SupportedFiles = new HashSet<string>(new string[] {
|
||||
".xml", ".txt"
|
||||
}, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public event EventHandler<LoadEventArgs> LoadCompleted;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WebPreviewControl"/> class.
|
||||
/// </summary>
|
||||
public WebPreviewControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.webBrowser.Navigated += HandleNavigated;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the UI element used to display the preview of the file.
|
||||
/// </summary>
|
||||
public FrameworkElement Host
|
||||
{
|
||||
get { return this; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether this instance can preview the specified file.
|
||||
/// </summary>
|
||||
/// <param name="filename">The filename.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this instance supports previewing that file. Otherwise, <c>false</c>.
|
||||
/// </returns>
|
||||
public bool CanPreview(string filename)
|
||||
{
|
||||
return SupportedFiles.Contains(System.IO.Path.GetExtension(filename));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Begins loading the preview for the given file..
|
||||
/// </summary>
|
||||
/// <param name="filename">The filename.</param>
|
||||
public void BeginLoad(string filename)
|
||||
{
|
||||
// TODO: XML opening is showing up with the warning yellow bar at the top sometimes
|
||||
webBrowser.Navigate(filename);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears the currently previewed file and releases any associated resources.
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
webBrowser.Source = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles the borwser navigated event.
|
||||
/// </summary>
|
||||
private void HandleNavigated(object sender, NavigationEventArgs e)
|
||||
{
|
||||
LoadCompleted?.Invoke(this, new LoadEventArgs());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,318 +0,0 @@
|
|||
using Microsoft.Tools.TeamMate.Foundation.Diagnostics;
|
||||
using Microsoft.Tools.TeamMate.Foundation.Native;
|
||||
using Microsoft.Tools.TeamMate.Foundation.Win32;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Forms
|
||||
{
|
||||
/// <summary>
|
||||
/// A control that can display the preview for a given file.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Based on Stephen Toub's post: http://msdn.microsoft.com/en-us/magazine/cc163487.aspx
|
||||
/// </remarks>
|
||||
public partial class NativePreviewControl : UserControl
|
||||
{
|
||||
private IPreviewHandler previewHandler;
|
||||
private ComStreamAdapter lastOpenedStream;
|
||||
private string filePath;
|
||||
|
||||
public event EventHandler<LoadEventArgs> LoadFinished;
|
||||
|
||||
public NativePreviewControl()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The path of the file to be previewed. Set to <c>null</c> to reset the control.
|
||||
/// </summary>
|
||||
public string FilePath
|
||||
{
|
||||
get { return this.filePath; }
|
||||
|
||||
set
|
||||
{
|
||||
if (!String.Equals(filePath, value, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
this.filePath = value;
|
||||
|
||||
if (this.filePath != null)
|
||||
{
|
||||
if (!IsInDesignMode)
|
||||
{
|
||||
InvalidatePreview();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DisposeHandlerAndStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsInDesignMode
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.Site != null && this.Site.DesignMode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Determines if a given file can be previewed.
|
||||
/// </summary>
|
||||
/// <param name="filePath"></param>
|
||||
/// <returns></returns>
|
||||
public static bool CanPreview(string filePath)
|
||||
{
|
||||
Guid? id;
|
||||
string description;
|
||||
return TryGetPreviewHandler(filePath, out id, out description);
|
||||
}
|
||||
|
||||
public static string GetPreviewHandlerDescription(string filePath)
|
||||
{
|
||||
Guid? id;
|
||||
string description;
|
||||
TryGetPreviewHandler(filePath, out id, out description);
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
private static bool TryGetPreviewHandler(string filePath, out Guid? previewHandlerId, out string previewHandlerDescription)
|
||||
{
|
||||
previewHandlerId = null;
|
||||
previewHandlerDescription = null;
|
||||
|
||||
/*
|
||||
// KLUDGE: http://go4answers.webhost4life.com/Example/preview-handler-msg-files-not-working-80634.aspx
|
||||
// Outlook msg files do not preview well on 64-bit... So we kludge this to see what is going on.
|
||||
// See also http://social.msdn.microsoft.com/Forums/eu/outlookdev/thread/040d8f15-56d9-4707-a652-48f4e07e8db3
|
||||
// for a potential workaround.
|
||||
string extension = Path.GetExtension(filePath);
|
||||
if (String.Equals(extension, ".msg", StringComparison.OrdinalIgnoreCase) &&
|
||||
Environment.Is64BitOperatingSystem)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
FileTypeInfo info = FileTypeRegistry.Instance.GetInfoFromPath(filePath);
|
||||
if (info != null)
|
||||
{
|
||||
previewHandlerId = info.PreviewHandlerId;
|
||||
previewHandlerDescription = info.PreviewHandlerDescription;
|
||||
}
|
||||
}
|
||||
|
||||
return (previewHandlerId != null);
|
||||
}
|
||||
|
||||
private void InvalidatePreview()
|
||||
{
|
||||
IntPtr myHandle = this.Handle;
|
||||
|
||||
// TODO: Avoid queuing multiple requests
|
||||
|
||||
// TODO: Temporarily moved this out of a worker thread... THere are cleanup exceptions being caused by that I think, we need to see
|
||||
// what the deal is... Ideally, I want to move this back to its worker thread...
|
||||
bool initialized = false;
|
||||
Exception error = null;
|
||||
|
||||
try
|
||||
{
|
||||
initialized = FindAndSetupPreviewHandler(myHandle);
|
||||
if (!initialized)
|
||||
{
|
||||
throw new Exception("Preview is not available for this file.");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
error = e;
|
||||
}
|
||||
|
||||
if (LoadFinished != null)
|
||||
{
|
||||
this.BeginInvoke((Action)delegate()
|
||||
{
|
||||
if (LoadFinished != null)
|
||||
{
|
||||
LoadEventArgs eventArgs = (error != null) ? new LoadEventArgs(error) : new LoadEventArgs();
|
||||
LoadFinished(this, eventArgs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private bool FindAndSetupPreviewHandler(IntPtr targetHandle)
|
||||
{
|
||||
bool initialized = false;
|
||||
|
||||
try
|
||||
{
|
||||
DisposeHandlerAndStream();
|
||||
|
||||
Guid? handlerId;
|
||||
string description;
|
||||
|
||||
if (TryGetPreviewHandler(filePath, out handlerId, out description))
|
||||
{
|
||||
Type comType = Type.GetTypeFromCLSID(handlerId.Value);
|
||||
|
||||
// TODO: If I iterate quickly through preview handlers, I sometimes get this normal.dotm message for word.
|
||||
// Office preview handlers spawn office processes with the -Embedding flag.
|
||||
// http://www.pcreview.co.uk/forums/word-has-encountered-problem-t3949879.html
|
||||
// http://social.technet.microsoft.com/Forums/en/itprovistasetup/thread/5b564970-23a7-40a5-b25e-bf3db08f060a
|
||||
// We might need to kill the process if appropriate? How can we tell when we should kill it?
|
||||
|
||||
// Create an instance of the preview handler
|
||||
object comObject = Activator.CreateInstance(comType);
|
||||
previewHandler = comObject as IPreviewHandler;
|
||||
|
||||
if (previewHandler != null)
|
||||
{
|
||||
IInitializeWithFile initializeWithFile = previewHandler as IInitializeWithFile;
|
||||
IInitializeWithStream initializeWithStream = previewHandler as IInitializeWithStream;
|
||||
IInitializeWithItem initializeWithItem = previewHandler as IInitializeWithItem;
|
||||
|
||||
if (initializeWithFile != null)
|
||||
{
|
||||
initializeWithFile.Initialize(filePath, 0);
|
||||
initialized = true;
|
||||
}
|
||||
else if (initializeWithStream != null)
|
||||
{
|
||||
ComStreamAdapter stream = new ComStreamAdapter(File.OpenRead(filePath));
|
||||
lastOpenedStream = stream;
|
||||
initializeWithStream.Initialize(stream, 0);
|
||||
initialized = true;
|
||||
}
|
||||
else if (initializeWithItem != null)
|
||||
{
|
||||
// Added this to support e.g. preview of .msg files and others... There are problems though, not quite working:
|
||||
// http://www.brad-smith.info/blog/archives/183
|
||||
// http://social.msdn.microsoft.com/Forums/en/outlookdev/thread/040d8f15-56d9-4707-a652-48f4e07e8db3
|
||||
// http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/91e4ee2d-344d-4bb9-9798-5a8194b523a1
|
||||
// http://int.social.msdn.microsoft.com/Forums/en/outlookdev/thread/c38a53f5-36d0-4261-9186-e276ad12ac0d
|
||||
IShellItem shellItem;
|
||||
NativeMethods.SHCreateItemFromParsingName(filePath, IntPtr.Zero, Marshal.GenerateGuidForType(typeof(IShellItem)), out shellItem);
|
||||
initializeWithItem.Initialize(shellItem, 0);
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
if (initialized)
|
||||
{
|
||||
RECT rect = SizeAsRect;
|
||||
previewHandler.SetWindow(targetHandle, ref rect);
|
||||
previewHandler.DoPreview();
|
||||
}
|
||||
else
|
||||
{
|
||||
DisposeHandlerAndStream();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
DisposeHandlerAndStream();
|
||||
throw;
|
||||
}
|
||||
|
||||
return initialized;
|
||||
}
|
||||
|
||||
private RECT SizeAsRect
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RECT(0, 0, this.Width, this.Height);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnResize(object sender, EventArgs e)
|
||||
{
|
||||
if (previewHandler != null)
|
||||
{
|
||||
RECT rect = SizeAsRect;
|
||||
|
||||
try
|
||||
{
|
||||
previewHandler.SetRect(ref rect);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.ErrorAndBreak(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DisposeHandlerAndStream()
|
||||
{
|
||||
if (previewHandler != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
previewHandler.Unload();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.ErrorAndBreak(ex);
|
||||
}
|
||||
|
||||
previewHandler = null;
|
||||
}
|
||||
|
||||
if (lastOpenedStream != null)
|
||||
{
|
||||
lastOpenedStream.Dispose();
|
||||
lastOpenedStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
DisposeHandlerAndStream();
|
||||
|
||||
if (components != null)
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
|
||||
public class LoadEventArgs : EventArgs
|
||||
{
|
||||
public LoadEventArgs()
|
||||
{
|
||||
this.Success = true;
|
||||
}
|
||||
|
||||
public LoadEventArgs(Exception error)
|
||||
{
|
||||
this.Error = error;
|
||||
}
|
||||
|
||||
public bool Success { get; private set; }
|
||||
public Exception Error { get; private set; }
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Forms
|
||||
{
|
||||
partial class NativePreviewControl
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// FilePreviewControl
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BorderStyle = System.Windows.Forms.BorderStyle.None;
|
||||
// this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
|
||||
this.Name = "FilePreviewControl";
|
||||
this.Size = new System.Drawing.Size(148, 148);
|
||||
this.Resize += new System.EventHandler(this.OnResize);
|
||||
this.ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
|
@ -1,218 +0,0 @@
|
|||
using Microsoft.Tools.TeamMate.Foundation.Windows.Shell;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Media.Capture
|
||||
{
|
||||
public class BoundsSelectionWindow : Window
|
||||
{
|
||||
private const double WindowOpacity = 0.65;
|
||||
private SolidColorBrush semiTransparentColor = new SolidColorBrush(Color.FromArgb((int)(255 * WindowOpacity), 255, 255, 255));
|
||||
private SolidColorBrush almostTransparentColor = new SolidColorBrush(Color.FromArgb(1, 255, 255, 255));
|
||||
|
||||
private bool isDragging;
|
||||
private bool hasSecondPoint;
|
||||
private Point mouseDown;
|
||||
private Point otherEnd;
|
||||
|
||||
private bool isClosing;
|
||||
|
||||
private Int32Rect? capturedBounds;
|
||||
|
||||
public BoundsSelectionWindow()
|
||||
{
|
||||
ShowInTaskbar = false;
|
||||
ShowActivated = true;
|
||||
Topmost = true;
|
||||
WindowStartupLocation = WindowStartupLocation.Manual;
|
||||
WindowStyle = WindowStyle.None;
|
||||
AllowsTransparency = true;
|
||||
Background = Brushes.Transparent;
|
||||
ResizeMode = ResizeMode.NoResize;
|
||||
Left = SystemParameters.VirtualScreenLeft;
|
||||
Top = SystemParameters.VirtualScreenTop;
|
||||
Width = SystemParameters.VirtualScreenWidth;
|
||||
Height = SystemParameters.VirtualScreenHeight;
|
||||
Cursor = Cursors.Cross;
|
||||
|
||||
this.Loaded += HandleLoaded;
|
||||
}
|
||||
|
||||
private bool minimizedAll;
|
||||
private BitmapSource screenBitmap;
|
||||
|
||||
public bool SelectBounds(BitmapSource screenBitmap, out Int32Rect bounds)
|
||||
{
|
||||
this.capturedBounds = null;
|
||||
this.minimizedAll = false;
|
||||
this.screenBitmap = screenBitmap;
|
||||
|
||||
if(ShellUtilities.IsInMetroMode())
|
||||
{
|
||||
// KLUDGE: MinimizeAll does not minimize Metro windows, use ToggleDesktop by design
|
||||
ShellUtilities.ToggleDesktop();
|
||||
this.minimizedAll = true;
|
||||
}
|
||||
|
||||
ShowDialog();
|
||||
|
||||
this.screenBitmap = null;
|
||||
|
||||
if (capturedBounds != null)
|
||||
{
|
||||
bounds = capturedBounds.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
bounds = new Int32Rect();
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SelectBounds(out Int32Rect bounds)
|
||||
{
|
||||
return SelectBounds(null, out bounds);
|
||||
}
|
||||
|
||||
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseLeftButtonDown(e);
|
||||
|
||||
isDragging = true;
|
||||
hasSecondPoint = false;
|
||||
mouseDown = e.GetPosition(this);
|
||||
InvalidateVisual();
|
||||
}
|
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e)
|
||||
{
|
||||
base.OnMouseMove(e);
|
||||
|
||||
if (isDragging)
|
||||
{
|
||||
hasSecondPoint = true;
|
||||
otherEnd = e.GetPosition(this);
|
||||
InvalidateVisual();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
|
||||
{
|
||||
base.OnMouseLeftButtonUp(e);
|
||||
|
||||
if (isDragging)
|
||||
{
|
||||
isDragging = false;
|
||||
hasSecondPoint = false;
|
||||
|
||||
Point mouseUp = e.GetPosition(this);
|
||||
Rect bounds = new Rect(mouseDown, mouseUp);
|
||||
|
||||
int width = (int)bounds.Width;
|
||||
int height = (int)bounds.Height;
|
||||
|
||||
if (width > 0 && height > 0)
|
||||
{
|
||||
this.capturedBounds = new Int32Rect((int)bounds.X, (int)bounds.Y, width, height);
|
||||
}
|
||||
|
||||
TryClose();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext drawingContext)
|
||||
{
|
||||
Rect fullScreenBounds = new Rect(0, 0, Width, Height);
|
||||
|
||||
if(this.screenBitmap != null)
|
||||
{
|
||||
drawingContext.DrawImage(this.screenBitmap, fullScreenBounds);
|
||||
}
|
||||
|
||||
if (isDragging && hasSecondPoint && mouseDown.X != otherEnd.X && mouseDown.Y != otherEnd.Y)
|
||||
{
|
||||
Rect selectionBounds = new Rect(mouseDown, otherEnd);
|
||||
|
||||
CombinedGeometry cg = new CombinedGeometry(GeometryCombineMode.Exclude,
|
||||
new RectangleGeometry(fullScreenBounds), new RectangleGeometry(selectionBounds));
|
||||
|
||||
drawingContext.DrawGeometry(semiTransparentColor, null, cg);
|
||||
|
||||
// Need to draw an almost transparent rectangle over the selection, otherwise, mouse inputs get
|
||||
// sent to the window under the selected box
|
||||
drawingContext.DrawGeometry(almostTransparentColor, null, new RectangleGeometry(selectionBounds));
|
||||
|
||||
Pen pen = new Pen(Brushes.Black, ThicknessInPixels(1));
|
||||
double halfPenWidth = pen.Thickness / 2;
|
||||
|
||||
// Using guidelines will "snap the rectangle to device pixels"
|
||||
GuidelineSet guidelines = new GuidelineSet();
|
||||
guidelines.GuidelinesX.Add(selectionBounds.Left + halfPenWidth);
|
||||
guidelines.GuidelinesX.Add(selectionBounds.Right + halfPenWidth);
|
||||
guidelines.GuidelinesY.Add(selectionBounds.Top + halfPenWidth);
|
||||
guidelines.GuidelinesY.Add(selectionBounds.Bottom + halfPenWidth);
|
||||
|
||||
drawingContext.PushGuidelineSet(guidelines);
|
||||
drawingContext.DrawRectangle(null, pen, selectionBounds);
|
||||
drawingContext.Pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
drawingContext.DrawRectangle(semiTransparentColor, null, fullScreenBounds);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
isClosing = true;
|
||||
|
||||
if (minimizedAll)
|
||||
{
|
||||
ShellUtilities.UndoMinimizeAll();
|
||||
}
|
||||
|
||||
base.OnClosing(e);
|
||||
}
|
||||
|
||||
private void HandleLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// KLUDGE: This trick is necessary to ensure the windows has focus when shown.
|
||||
// This window is not the foreground window if we used the Shell ToggleDesktop trick.
|
||||
WindowUtilities.ForceToForeground(this);
|
||||
}
|
||||
|
||||
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
||||
{
|
||||
base.OnPreviewKeyDown(e);
|
||||
|
||||
if (e.Key == Key.Escape)
|
||||
{
|
||||
TryClose();
|
||||
e.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
|
||||
{
|
||||
base.OnLostKeyboardFocus(e);
|
||||
TryClose();
|
||||
}
|
||||
|
||||
private void TryClose()
|
||||
{
|
||||
if (!isClosing)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
private double ThicknessInPixels(int pixels)
|
||||
{
|
||||
Matrix matrix = PresentationSource.FromVisual(this).CompositionTarget.TransformToDevice;
|
||||
double dpiFactor = 1 / matrix.M11;
|
||||
return pixels * dpiFactor;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,284 +0,0 @@
|
|||
using Microsoft.Tools.TeamMate.Foundation.Native;
|
||||
using Microsoft.Tools.TeamMate.Foundation.Windows.Interop;
|
||||
using Microsoft.Tools.TeamMate.Foundation.Windows.Media.Imaging;
|
||||
using Microsoft.Tools.TeamMate.Foundation.Windows.Shell;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Media.Capture
|
||||
{
|
||||
public static class ScreenCapture
|
||||
{
|
||||
public static BitmapSource CaptureScreen()
|
||||
{
|
||||
Int32Rect region = new Int32Rect(0, 0, (int)SystemParameters.VirtualScreenWidth, (int)SystemParameters.VirtualScreenHeight);
|
||||
return CaptureRegion(region);
|
||||
}
|
||||
|
||||
public static bool SelectScreenBounds(out Int32Rect bounds)
|
||||
{
|
||||
return SelectScreenBounds(null, out bounds);
|
||||
}
|
||||
|
||||
private static bool SelectScreenBounds(BitmapSource screenBitmap, out Int32Rect bounds)
|
||||
{
|
||||
return new BoundsSelectionWindow().SelectBounds(screenBitmap, out bounds);
|
||||
}
|
||||
|
||||
public static BitmapSource CaptureRegionInteractively()
|
||||
{
|
||||
Int32Rect bounds;
|
||||
|
||||
BitmapSource screenBitmap = null;
|
||||
bool inMetroMode = ShellUtilities.IsInMetroMode();
|
||||
if (inMetroMode)
|
||||
{
|
||||
screenBitmap = CaptureScreen();
|
||||
}
|
||||
|
||||
if (SelectScreenBounds(screenBitmap, out bounds))
|
||||
{
|
||||
if (screenBitmap != null)
|
||||
{
|
||||
return new CroppedBitmap(screenBitmap, bounds);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CaptureRegion(bounds);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BitmapSource CaptureRegion(Int32Rect region)
|
||||
{
|
||||
// TODO: Validate that region is not bigger than virtual screen...
|
||||
|
||||
Bitmap bitmap = new Bitmap(region.Width, region.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
|
||||
System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap);
|
||||
|
||||
using (bitmap)
|
||||
using (graphics)
|
||||
{
|
||||
graphics.CopyFromScreen(region.X, region.Y, 0, 0, bitmap.Size);
|
||||
IntPtr hBitmap = bitmap.GetHbitmap();
|
||||
|
||||
try
|
||||
{
|
||||
return InteropUtilities.CreateBitmapSourceFromHBitmapAndDispose(hBitmap);
|
||||
}
|
||||
finally
|
||||
{
|
||||
NativeMethods.DeleteObject(hBitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static BitmapSource CaptureWindow(IntPtr hWnd)
|
||||
{
|
||||
return CaptureWindow(hWnd, false, null);
|
||||
}
|
||||
|
||||
public static BitmapSource CaptureWindow(IntPtr hWnd, System.Drawing.Size? maxPixelSize)
|
||||
{
|
||||
return CaptureWindow(hWnd, false, maxPixelSize);
|
||||
}
|
||||
|
||||
public static BitmapSource CaptureWindow(IntPtr hWnd, bool restoreMinimizedWindow)
|
||||
{
|
||||
return CaptureWindow(hWnd, restoreMinimizedWindow, null);
|
||||
}
|
||||
|
||||
public static BitmapSource CaptureWindow(IntPtr hWnd, bool restoreMinimizedWindow, System.Drawing.Size? maxPixelSize)
|
||||
{
|
||||
Bitmap bitmap = CaptureWindowBitmap(hWnd, restoreMinimizedWindow, maxPixelSize);
|
||||
return InteropUtilities.CreateBitmapSourceFromBitmap(bitmap);
|
||||
}
|
||||
|
||||
public static Bitmap CaptureWindowBitmap(IntPtr hWnd, bool restoreMinimizedWindow, System.Drawing.Size? maxPixelSize)
|
||||
{
|
||||
Bitmap bitmap = CaptureWindowBitmap(hWnd, restoreMinimizedWindow);
|
||||
|
||||
// Step 3: Finally, create a bitmap from the captured image
|
||||
if (maxPixelSize != null)
|
||||
{
|
||||
double scaleFactor = BitmapUtilities.GetScaleFactor(bitmap.Width, bitmap.Height, maxPixelSize.Value.Width, maxPixelSize.Value.Height);
|
||||
if (scaleFactor < 1)
|
||||
{
|
||||
Bitmap resizedBitmap = ResizeImage(bitmap, (int)Math.Round(bitmap.Width * scaleFactor), (int)Math.Round(bitmap.Height * scaleFactor));
|
||||
bitmap.Dispose();
|
||||
bitmap = resizedBitmap;
|
||||
}
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static Bitmap CaptureWindowBitmap(IntPtr hWnd, bool restoreMinimizedWindow)
|
||||
{
|
||||
bool minimizeWindowWhenDone = false;
|
||||
int oldExtStyle = 0;
|
||||
|
||||
IDisposable systemAnimationReenabler = null;
|
||||
|
||||
if (NativeMethods.IsIconic(hWnd) && restoreMinimizedWindow)
|
||||
{
|
||||
systemAnimationReenabler = ExtendedSystemParameters.DisableSystemAnimations();
|
||||
RestoreWindowBeforeCapture(hWnd, out oldExtStyle);
|
||||
minimizeWindowWhenDone = true;
|
||||
}
|
||||
|
||||
Bitmap bitmap;
|
||||
|
||||
try
|
||||
{
|
||||
bitmap = CaptureWindowBitmap(hWnd);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (minimizeWindowWhenDone)
|
||||
{
|
||||
MinimizeWindowAfterCapture(hWnd, oldExtStyle);
|
||||
|
||||
if (systemAnimationReenabler != null)
|
||||
{
|
||||
systemAnimationReenabler.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private static Bitmap CaptureWindowBitmap(IntPtr hWnd)
|
||||
{
|
||||
WindowInfo windowInfo = WindowInfo.FromHwnd(hWnd);
|
||||
RECT bounds = windowInfo.WindowBounds;
|
||||
|
||||
if (bounds.Width <= 0 || bounds.Height <= 0)
|
||||
{
|
||||
throw new InvalidOperationException(String.Format(
|
||||
"Cannot capture screen for window with handle {0}, the window has invalid bounds {1}", hWnd, bounds
|
||||
));
|
||||
}
|
||||
|
||||
Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
|
||||
|
||||
using (System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(bitmap))
|
||||
{
|
||||
// Step 1: Try to print the window on the bitmap
|
||||
IntPtr hdcBitmap = graphics.GetHdc();
|
||||
bool succeeded = NativeMethods.PrintWindow(hWnd, hdcBitmap, 0);
|
||||
graphics.ReleaseHdc(hdcBitmap);
|
||||
|
||||
if (!succeeded)
|
||||
{
|
||||
// Fill the rectangle with a solid grey color if we failed to print the window...
|
||||
using (System.Drawing.SolidBrush brush = new System.Drawing.SolidBrush(System.Drawing.Color.Gray))
|
||||
{
|
||||
graphics.FillRectangle(brush, new System.Drawing.Rectangle(System.Drawing.Point.Empty, bitmap.Size));
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: If the window is irregular, clip the region outside of the window with a transparent color
|
||||
IntPtr hRgn = NativeMethods.CreateRectRgn(0, 0, 0, 0);
|
||||
NativeMethods.GetWindowRgn(hWnd, hRgn);
|
||||
using (System.Drawing.Region region = System.Drawing.Region.FromHrgn(hRgn))
|
||||
{
|
||||
if (!region.IsEmpty(graphics))
|
||||
{
|
||||
graphics.ExcludeClip(region);
|
||||
graphics.Clear(System.Drawing.Color.Transparent);
|
||||
}
|
||||
}
|
||||
|
||||
NativeMethods.DeleteObject(hRgn);
|
||||
}
|
||||
|
||||
// HACK: The actual window bounds are greater than what is shown on screen (e.g. maximized windows
|
||||
// have an 8 pixel grey border around them). Crop any excess from the bitmap itself.
|
||||
bitmap = CropWindowExcess(bitmap, windowInfo);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private static Bitmap CropBitmap(Bitmap bmpImage, Rectangle cropArea)
|
||||
{
|
||||
return bmpImage.Clone(cropArea, bmpImage.PixelFormat);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resize the image to the specified width and height.
|
||||
/// </summary>
|
||||
/// <param name="image">The image to resize.</param>
|
||||
/// <param name="width">The width to resize to.</param>
|
||||
/// <param name="height">The height to resize to.</param>
|
||||
/// <returns>The resized image.</returns>
|
||||
public static Bitmap ResizeImage(System.Drawing.Image image, int width, int height)
|
||||
{
|
||||
Bitmap resizedBitmap = new Bitmap(width, height);
|
||||
|
||||
// set the resolutions the same to avoid cropping due to resolution differences
|
||||
resizedBitmap.SetResolution(image.HorizontalResolution, image.VerticalResolution);
|
||||
|
||||
using (Graphics graphics = Graphics.FromImage(resizedBitmap))
|
||||
{
|
||||
graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;
|
||||
graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
|
||||
graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
|
||||
|
||||
graphics.DrawImage(image, 0, 0, resizedBitmap.Width, resizedBitmap.Height);
|
||||
}
|
||||
|
||||
return resizedBitmap;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Crops any undesired excess in the captured window bounds to remove unwanted gray borders.
|
||||
/// GetWindowRect() returns excessive boundaries in cases where e.g. the window is maximized
|
||||
/// and so forth.
|
||||
/// </summary>
|
||||
private static Bitmap CropWindowExcess(Bitmap input, WindowInfo windowInfo)
|
||||
{
|
||||
if (windowInfo.IsMaximized)
|
||||
{
|
||||
if (windowInfo.WindowBorderWidth > 0 || windowInfo.WindowBorderHeight > 0)
|
||||
{
|
||||
int newX = windowInfo.WindowBorderWidth;
|
||||
int newY = windowInfo.WindowBorderHeight;
|
||||
int cropWidth = input.Width - windowInfo.WindowBorderWidth * 2;
|
||||
int cropHeight = input.Height - windowInfo.WindowBorderHeight * 2;
|
||||
|
||||
Rectangle cropArea = new Rectangle(newX, newY, cropWidth, cropHeight);
|
||||
Bitmap croppedBitmap = CropBitmap(input, cropArea);
|
||||
input.Dispose();
|
||||
return croppedBitmap;
|
||||
}
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
private static void RestoreWindowBeforeCapture(IntPtr hWnd, out int oldExtStyle)
|
||||
{
|
||||
oldExtStyle = NativeMethods.GetWindowLong(hWnd, GetWindowLong.GWL_EXSTYLE);
|
||||
NativeMethods.SetWindowLong(hWnd, GetWindowLong.GWL_EXSTYLE, oldExtStyle | (int)WindowStyles.WS_EX_LAYERED);
|
||||
NativeMethods.SetLayeredWindowAttributes(hWnd, 0, 1, NativeConstants.LWA_ALPHA);
|
||||
|
||||
NativeMethods.ShowWindow(hWnd, ShowWindow.SW_RESTORE);
|
||||
NativeMethods.SendMessage(hWnd, (uint)WindowsMessage.WM_PAINT, 0, 0);
|
||||
|
||||
// TODO: Need to wait some time until restored windows is nicely painted. Should this be a parameter too?
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
|
||||
private static void MinimizeWindowAfterCapture(IntPtr hWnd, int oldExtStyle)
|
||||
{
|
||||
NativeMethods.ShowWindow(hWnd, ShowWindow.SW_MINIMIZE);
|
||||
NativeMethods.SetWindowLong(hWnd, GetWindowLong.GWL_EXSTYLE, oldExtStyle);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,191 +0,0 @@
|
|||
using Microsoft.Tools.TeamMate.Foundation.Native;
|
||||
using Microsoft.Tools.TeamMate.Foundation.Windows.Interop;
|
||||
using Microsoft.Win32;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Shell
|
||||
{
|
||||
public class ShellFileInfo
|
||||
{
|
||||
private const string ExtensionPrefix = ".";
|
||||
|
||||
private ImageSource smallIcon;
|
||||
private ImageSource largeIcon;
|
||||
private string path;
|
||||
private string typeName;
|
||||
|
||||
protected ShellFileInfo(string path, string typeName, ImageSource smallIcon, ImageSource largeIcon)
|
||||
{
|
||||
this.path = path;
|
||||
this.typeName = typeName;
|
||||
this.smallIcon = smallIcon;
|
||||
this.largeIcon = largeIcon;
|
||||
}
|
||||
|
||||
public ImageSource SmallIcon
|
||||
{
|
||||
get { return this.smallIcon; }
|
||||
}
|
||||
|
||||
public ImageSource LargeIcon
|
||||
{
|
||||
get { return this.largeIcon; }
|
||||
}
|
||||
|
||||
public virtual string Extension
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.path.StartsWith(ExtensionPrefix)) ? this.path : System.IO.Path.GetExtension(this.path);
|
||||
}
|
||||
}
|
||||
|
||||
public string Path
|
||||
{
|
||||
get
|
||||
{
|
||||
return (this.path.StartsWith(ExtensionPrefix)) ? null : this.path;
|
||||
}
|
||||
}
|
||||
|
||||
public string TypeName
|
||||
{
|
||||
get { return this.typeName; }
|
||||
}
|
||||
|
||||
public static ShellFileInfo GetDefaultFileInfo()
|
||||
{
|
||||
return FromExtension(null, true);
|
||||
}
|
||||
|
||||
public static ShellFolderInfo GetDefaultFolderInfo()
|
||||
{
|
||||
return (ShellFolderInfo)GetShellFileInfo(null, true, true, true);
|
||||
}
|
||||
|
||||
public static ShellFileInfo FromExtension(string pathOrExtension, bool loadLargeIcon = false)
|
||||
{
|
||||
if (pathOrExtension != null)
|
||||
pathOrExtension = System.IO.Path.GetExtension(pathOrExtension);
|
||||
|
||||
return GetShellFileInfo(pathOrExtension, true, false, loadLargeIcon);
|
||||
}
|
||||
|
||||
public static ShellFileInfo FromFile(string path, bool loadLargeIcon = false)
|
||||
{
|
||||
return GetShellFileInfo(path, false, false, loadLargeIcon);
|
||||
}
|
||||
|
||||
public static ShellFolderInfo FromDirectory(string path, bool loadLargeIcon = false)
|
||||
{
|
||||
return (ShellFolderInfo) GetShellFileInfo(path, false, true, loadLargeIcon);
|
||||
}
|
||||
|
||||
public static string GetTypeName(string pathOrExtension)
|
||||
{
|
||||
SHFILEINFO info = GetFileInfo(pathOrExtension, FILE_ATTRIBUTE.FILE_ATTRIBUTE_NORMAL,
|
||||
SHGFI.SHGFI_TYPENAME | SHGFI.SHGFI_USEFILEATTRIBUTES);
|
||||
|
||||
return info.szTypeName;
|
||||
}
|
||||
|
||||
private static ShellFileInfo GetShellFileInfo(string pathOrExtension, bool useFileAttributes, bool isFolder, bool loadLargeIcon)
|
||||
{
|
||||
SHGFI flags = SHGFI.SHGFI_ICON;
|
||||
FILE_ATTRIBUTE fileAttribute = FILE_ATTRIBUTE.FILE_ATTRIBUTE_NORMAL;
|
||||
|
||||
if (useFileAttributes)
|
||||
{
|
||||
flags |= SHGFI.SHGFI_USEFILEATTRIBUTES;
|
||||
if (isFolder)
|
||||
fileAttribute = FILE_ATTRIBUTE.FILE_ATTRIBUTE_DIRECTORY;
|
||||
}
|
||||
|
||||
SHFILEINFO info = GetFileInfo(pathOrExtension, fileAttribute, flags | SHGFI.SHGFI_SMALLICON | SHGFI.SHGFI_TYPENAME);
|
||||
|
||||
string typeName = info.szTypeName;
|
||||
BitmapSource smallIcon = InteropUtilities.CreateBitmapSourceFromHIconAndDispose(info.hIcon);
|
||||
BitmapSource largeIcon = null;
|
||||
|
||||
if (loadLargeIcon)
|
||||
{
|
||||
info = GetFileInfo(pathOrExtension, fileAttribute, flags | SHGFI.SHGFI_LARGEICON);
|
||||
largeIcon = InteropUtilities.CreateBitmapSourceFromHIconAndDispose(info.hIcon);
|
||||
}
|
||||
|
||||
if (isFolder)
|
||||
{
|
||||
BitmapSource smallOpenIcon = null;
|
||||
BitmapSource largeOpenIcon = null;
|
||||
|
||||
info = GetFileInfo(pathOrExtension, fileAttribute, flags | SHGFI.SHGFI_OPENICON);
|
||||
smallOpenIcon = InteropUtilities.CreateBitmapSourceFromHIconAndDispose(info.hIcon);
|
||||
|
||||
if (loadLargeIcon)
|
||||
{
|
||||
// KLUDGE: Small and large icon the same...
|
||||
largeOpenIcon = smallOpenIcon;
|
||||
}
|
||||
|
||||
return new ShellFolderInfo(pathOrExtension, typeName, smallIcon, largeIcon, smallOpenIcon, largeOpenIcon);
|
||||
}
|
||||
|
||||
return new ShellFileInfo(pathOrExtension, typeName, smallIcon, largeIcon);
|
||||
}
|
||||
|
||||
private static SHFILEINFO GetFileInfo(string path, FILE_ATTRIBUTE attr, SHGFI flags)
|
||||
{
|
||||
SHFILEINFO info = new SHFILEINFO();
|
||||
|
||||
// Dummy filename if file has no extension...
|
||||
if ((flags & SHGFI.SHGFI_USEFILEATTRIBUTES) == SHGFI.SHGFI_USEFILEATTRIBUTES && String.IsNullOrEmpty(path))
|
||||
{
|
||||
path = "DummyFileName";
|
||||
}
|
||||
|
||||
NativeMethods.SHGetFileInfo(path, (uint)attr, ref info, SHFILEINFO.Size, (uint)flags);
|
||||
return info;
|
||||
}
|
||||
|
||||
public static ICollection<string> GetRegisteredFileExtensions()
|
||||
{
|
||||
// Find all the extension subkeys under HKEY_CLASSES_ROOT
|
||||
return Registry.ClassesRoot.GetSubKeyNames().Where(key => key.StartsWith(ExtensionPrefix)).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public class ShellFolderInfo : ShellFileInfo
|
||||
{
|
||||
private ImageSource smallOpenIcon;
|
||||
private ImageSource largeOpenIcon;
|
||||
|
||||
internal ShellFolderInfo(string path, string typeName, ImageSource smallIcon, ImageSource largeIcon, ImageSource smallOpenIcon, ImageSource largeOpenIcon)
|
||||
: base(path, typeName, smallIcon, largeIcon)
|
||||
{
|
||||
this.smallOpenIcon = smallOpenIcon;
|
||||
this.largeOpenIcon = largeOpenIcon;
|
||||
}
|
||||
|
||||
public ImageSource SmallOpenIcon
|
||||
{
|
||||
get { return this.smallOpenIcon; }
|
||||
}
|
||||
|
||||
public ImageSource LargeOpenIcon
|
||||
{
|
||||
get { return this.largeOpenIcon; }
|
||||
}
|
||||
|
||||
public override string Extension
|
||||
{
|
||||
get
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Shell
|
||||
{
|
||||
public class ShellFileInfoCache
|
||||
{
|
||||
private IDictionary<string, ShellFileInfo> extensionCache =
|
||||
new Dictionary<string, ShellFileInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private IDictionary<string, ShellFileInfo> fileCache =
|
||||
new Dictionary<string, ShellFileInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private IDictionary<string, ShellFolderInfo> folderCache =
|
||||
new Dictionary<string, ShellFolderInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private ShellFolderInfo defaultFolderInfo;
|
||||
private ShellFileInfo defaultFileInfo;
|
||||
private object cacheLock = new object();
|
||||
|
||||
public ShellFileInfoCache()
|
||||
{
|
||||
LoadLargeIcons = true;
|
||||
}
|
||||
|
||||
public bool LoadLargeIcons { get; set; }
|
||||
|
||||
public ShellFileInfo DefaultFileInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
if (defaultFileInfo == null)
|
||||
defaultFileInfo = ShellFileInfo.GetDefaultFileInfo();
|
||||
|
||||
return defaultFileInfo;
|
||||
}
|
||||
}
|
||||
|
||||
public ShellFolderInfo DefaultFolderInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
if (defaultFolderInfo == null)
|
||||
defaultFolderInfo = ShellFileInfo.GetDefaultFolderInfo();
|
||||
|
||||
return defaultFolderInfo;
|
||||
}
|
||||
}
|
||||
|
||||
public ShellFileInfo FromExtension(string pathOrExtension)
|
||||
{
|
||||
return GetOrCreate<ShellFileInfo>(pathOrExtension, extensionCache, (p) => ShellFileInfo.FromExtension(p, LoadLargeIcons));
|
||||
}
|
||||
|
||||
public ShellFileInfo FromFile(string path)
|
||||
{
|
||||
return GetOrCreate<ShellFileInfo>(path, fileCache, (p) => ShellFileInfo.FromFile(p, LoadLargeIcons));
|
||||
}
|
||||
|
||||
public ShellFolderInfo FromDirectory(string path)
|
||||
{
|
||||
return GetOrCreate<ShellFolderInfo>(path, folderCache, (p) => ShellFileInfo.FromDirectory(p, LoadLargeIcons));
|
||||
}
|
||||
|
||||
private T GetOrCreate<T>(string path, IDictionary<string,T> cache, Func<string, T> constructor)
|
||||
{
|
||||
T output;
|
||||
bool exists;
|
||||
|
||||
lock (cacheLock)
|
||||
{
|
||||
exists = cache.TryGetValue(path, out output);
|
||||
}
|
||||
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
output = constructor(path);
|
||||
if (output != null)
|
||||
{
|
||||
lock (cacheLock)
|
||||
{
|
||||
cache[path] = output;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
lock (cacheLock)
|
||||
{
|
||||
extensionCache.Clear();
|
||||
fileCache.Clear();
|
||||
folderCache.Clear();
|
||||
defaultFileInfo = null;
|
||||
defaultFolderInfo = null;
|
||||
}
|
||||
}
|
||||
|
||||
public ICollection<string> CachedExtensions
|
||||
{
|
||||
get { return extensionCache.Keys; }
|
||||
}
|
||||
|
||||
public ICollection<string> CachedFiles
|
||||
{
|
||||
get { return fileCache.Keys; }
|
||||
}
|
||||
|
||||
public ICollection<string> CachedFolders
|
||||
{
|
||||
get { return folderCache.Keys; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,158 +0,0 @@
|
|||
using Microsoft.Tools.TeamMate.Foundation.Native;
|
||||
using Microsoft.Tools.TeamMate.Foundation.Win32;
|
||||
using Microsoft.Tools.TeamMate.Foundation.Windows.Interop;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Shell
|
||||
{
|
||||
public static class ShellUtilities
|
||||
{
|
||||
private static readonly SIZE WellKnownThumbnailSize = new SIZE(256, 256);
|
||||
|
||||
public static BitmapSource ExtractIcon(string filename, int index = 0)
|
||||
{
|
||||
IntPtr hIcon = NativeMethods.ExtractIcon(Process.GetCurrentProcess().Handle, Environment.ExpandEnvironmentVariables(filename), index);
|
||||
return InteropUtilities.CreateBitmapSourceFromHIconAndDispose(hIcon);
|
||||
}
|
||||
|
||||
public static BitmapSource GetThumbnail(string filename)
|
||||
{
|
||||
IntPtr hbitmap = GetThumbnailHBitmap(filename);
|
||||
return InteropUtilities.CreateBitmapSourceFromHBitmapAndDispose(hbitmap);
|
||||
}
|
||||
|
||||
[DebuggerStepThrough]
|
||||
private static IntPtr GetThumbnailHBitmap(string filename)
|
||||
{
|
||||
IntPtr hbitmap = IntPtr.Zero;
|
||||
|
||||
try
|
||||
{
|
||||
FileTypeInfo info = FileTypeRegistry.Instance.GetInfoFromPath(filename);
|
||||
if (info != null && info.HasThumbnailProvider)
|
||||
{
|
||||
IShellItem ppsi;
|
||||
Guid shellItemGuid = Marshal.GenerateGuidForType(typeof(IShellItem));
|
||||
NativeMethods.SHCreateItemFromParsingName(filename, IntPtr.Zero, shellItemGuid, out ppsi);
|
||||
IShellItemImageFactory factory = ppsi as IShellItemImageFactory;
|
||||
|
||||
if (factory != null)
|
||||
{
|
||||
factory.GetImage(WellKnownThumbnailSize, SIIGBF.SIIGBF_BIGGERSIZEOK | SIIGBF.SIIGBF_THUMBNAILONLY, out hbitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// This is expected if the target file does not produce thumbnails... We'll just return a null pointer
|
||||
}
|
||||
|
||||
return hbitmap;
|
||||
}
|
||||
|
||||
public static void ForceToForeground(IntPtr hWnd)
|
||||
{
|
||||
IntPtr foregroundWindow = NativeMethods.GetForegroundWindow();
|
||||
|
||||
// See http://www.codeproject.com/Tips/76427/How-to-bring-window-to-top-with-SetForegroundWindo
|
||||
if (foregroundWindow != hWnd)
|
||||
{
|
||||
const int VK_MENU = 0x12;
|
||||
const int KEYEVENTF_EXTENDEDKEY = 1;
|
||||
const int KEYEVENTF_KEYUP = 2;
|
||||
|
||||
//to unlock SetForegroundWindow we need to imitate pressing [Alt] key
|
||||
bool pressed = false;
|
||||
if ((NativeMethods.GetAsyncKeyState(VK_MENU) & 0x8000) == 0)
|
||||
{
|
||||
pressed = true;
|
||||
NativeMethods.keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY, 0);
|
||||
}
|
||||
|
||||
NativeMethods.SetForegroundWindow(hWnd);
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
NativeMethods.keybd_event(VK_MENU, 0, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void AllowCaptureForeground(Action action)
|
||||
{
|
||||
// See http://www.shloemi.com/2012/09/solved-setforegroundwindow-win32-api-not-always-works/
|
||||
uint foregroundProcessId;
|
||||
int currentProcessId = Process.GetCurrentProcess().Id;
|
||||
uint foreThread = NativeMethods.GetWindowThreadProcessId(NativeMethods.GetForegroundWindow(), out foregroundProcessId);
|
||||
if (foregroundProcessId == Process.GetCurrentProcess().Id)
|
||||
{
|
||||
action();
|
||||
}
|
||||
else
|
||||
{
|
||||
var appThread = NativeMethods.GetCurrentThreadId();
|
||||
bool threadsAttached = NativeMethods.AttachThreadInput(foreThread, appThread, true);
|
||||
NativeMethods.AllowSetForegroundWindow(currentProcessId);
|
||||
|
||||
try
|
||||
{
|
||||
action();
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (threadsAttached)
|
||||
{
|
||||
NativeMethods.AttachThreadInput(foreThread, appThread, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsInMetroMode()
|
||||
{
|
||||
bool inMetroMode = false;
|
||||
|
||||
if (Environment.OSVersion.IsWindows8OrGreater())
|
||||
{
|
||||
IAppVisibility appVisibility = new IAppVisibility();
|
||||
inMetroMode = appVisibility.IsLauncherVisible();
|
||||
|
||||
if (!inMetroMode)
|
||||
{
|
||||
NativeMethods.EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, delegate(IntPtr hMonitor, IntPtr hdcMonitor, ref RECT lprcMonitor, IntPtr dwData)
|
||||
{
|
||||
MONITOR_APP_VISIBILITY visibility = appVisibility.GetAppVisibilityOnMonitor(hMonitor);
|
||||
inMetroMode = (visibility == MONITOR_APP_VISIBILITY.MAV_APP_VISIBLE);
|
||||
|
||||
return !inMetroMode;
|
||||
}, IntPtr.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
return inMetroMode;
|
||||
}
|
||||
|
||||
public static void ToggleDesktop()
|
||||
{
|
||||
GetShell().ToggleDesktop();
|
||||
}
|
||||
|
||||
public static void MinimizeAll()
|
||||
{
|
||||
GetShell().MinimizeAll();
|
||||
}
|
||||
|
||||
public static void UndoMinimizeAll()
|
||||
{
|
||||
GetShell().UndoMinimizeALL();
|
||||
}
|
||||
|
||||
private static Shell32.Shell GetShell()
|
||||
{
|
||||
return new Shell32.Shell();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
using Microsoft.Tools.TeamMate.Foundation.Native;
|
||||
using Microsoft.Tools.TeamMate.Foundation.Win32;
|
||||
using Microsoft.Tools.TeamMate.Foundation.Windows.Interop;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Shell
|
||||
{
|
||||
public class SystemImageCache
|
||||
{
|
||||
private static SystemImageCache singleton;
|
||||
|
||||
private SystemImageList small, large, extraLarge, jumbo;
|
||||
|
||||
private Dictionary<string, SystemImageInfo> extensionBasedCache = new Dictionary<string, SystemImageInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public static SystemImageCache Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (singleton == null)
|
||||
{
|
||||
singleton = new SystemImageCache();
|
||||
}
|
||||
|
||||
return singleton;
|
||||
}
|
||||
}
|
||||
|
||||
internal SystemImageList GetImageList(SystemImageSize imageSize)
|
||||
{
|
||||
switch (imageSize)
|
||||
{
|
||||
case SystemImageSize.Small: return GetImageList(SHIL.SHIL_SMALL, ref small);
|
||||
case SystemImageSize.Large: return GetImageList(SHIL.SHIL_LARGE, ref large);
|
||||
case SystemImageSize.ExtraLarge: return GetImageList(SHIL.SHIL_EXTRALARGE, ref extraLarge);
|
||||
case SystemImageSize.Jumbo: return GetImageList(SHIL.SHIL_JUMBO, ref jumbo);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException("Unsupported image list for image size: " + imageSize);
|
||||
}
|
||||
}
|
||||
|
||||
private SystemImageList GetImageList(SHIL imageSize, ref SystemImageList result)
|
||||
{
|
||||
if (result == null)
|
||||
{
|
||||
result = new SystemImageList(imageSize);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public SystemImageInfo GetSystemImage(string pathOrExtension)
|
||||
{
|
||||
string extension = Path.GetExtension(pathOrExtension);
|
||||
bool inputIsPath = (extension.Length != pathOrExtension.Length);
|
||||
|
||||
bool isShared = true;
|
||||
bool hasCustomThumbnail = false;
|
||||
|
||||
if (inputIsPath)
|
||||
{
|
||||
string path = pathOrExtension;
|
||||
|
||||
if (!Path.IsPathRooted(path))
|
||||
{
|
||||
throw new ArgumentException("Input path must be an extension or an absolute path");
|
||||
}
|
||||
|
||||
// Optimized variables and logic to do file system checks once and in order of effectiveness
|
||||
FileTypeInfo info = FileTypeRegistry.Instance.GetInfo(extension);
|
||||
|
||||
bool hasCustomIcon = (info != null && info.HasCustomIcon);
|
||||
bool hasThumbnailProvider = (info != null && info.HasThumbnailProvider);
|
||||
bool fileExists = (hasCustomIcon || hasThumbnailProvider) ? File.Exists(path) : false;
|
||||
|
||||
if (fileExists && hasCustomIcon)
|
||||
{
|
||||
// NOT SHARED: Each image type for this file might be unique
|
||||
isShared = false;
|
||||
}
|
||||
else if (fileExists && hasThumbnailProvider)
|
||||
{
|
||||
// Icons are shared, but the image can render as a thumbnail
|
||||
hasCustomThumbnail = true;
|
||||
}
|
||||
else if (Directory.Exists(path))
|
||||
{
|
||||
// NOT SHARED: It is a folder, and folders might have unique icons
|
||||
isShared = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isShared)
|
||||
{
|
||||
return new SystemImageInfo(pathOrExtension, this);
|
||||
}
|
||||
else if (hasCustomThumbnail)
|
||||
{
|
||||
SystemImageInfo iconDelegate = GetSharedImage(extension);
|
||||
return new SystemImageInfo(pathOrExtension, this, iconDelegate);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetSharedImage(extension);
|
||||
}
|
||||
}
|
||||
|
||||
private SystemImageInfo GetSharedImage(string extension)
|
||||
{
|
||||
SystemImageInfo info;
|
||||
if (!extensionBasedCache.TryGetValue(extension, out info))
|
||||
{
|
||||
info = new SystemImageInfo(extension, this);
|
||||
extensionBasedCache[extension] = info;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
public void RemoveFromCache(string extension)
|
||||
{
|
||||
extensionBasedCache.Remove(extension);
|
||||
}
|
||||
|
||||
public ImageSource LoadImage(string pathOrExtension, SystemImageSize size)
|
||||
{
|
||||
string extension = Path.GetExtension(pathOrExtension);
|
||||
bool inputIsPath = (extension.Length != pathOrExtension.Length);
|
||||
|
||||
if (size != SystemImageSize.Thumbnail)
|
||||
{
|
||||
SystemImageList imageList = GetImageList(size);
|
||||
|
||||
int iconIndex = 0;
|
||||
|
||||
if (!String.IsNullOrEmpty(pathOrExtension))
|
||||
{
|
||||
bool forceLoadFromDisk = inputIsPath;
|
||||
// TODO: Do in background thread when forceLoadFromDisk? That avoids blocking the UI
|
||||
iconIndex = imageList.IconIndex(pathOrExtension, forceLoadFromDisk);
|
||||
}
|
||||
|
||||
if (iconIndex >= 0)
|
||||
{
|
||||
IntPtr iconHandle = imageList.IconHandle(iconIndex);
|
||||
if (iconHandle != IntPtr.Zero)
|
||||
{
|
||||
return InteropUtilities.CreateBitmapSourceFromHIcon(iconHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (inputIsPath)
|
||||
{
|
||||
return ShellUtilities.GetThumbnail(pathOrExtension);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,160 +0,0 @@
|
|||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Shell
|
||||
{
|
||||
public class SystemImageInfo
|
||||
{
|
||||
private SystemImageCache parentCache;
|
||||
private SystemImageInfo iconDelegate;
|
||||
private ImageSource smallImage, largeImage, extraLargeImage, jumboImage, thumbnail;
|
||||
private string pathOrExtension;
|
||||
|
||||
internal SystemImageInfo(string pathOrExtension, SystemImageCache parentCache, SystemImageInfo iconDelegate = null)
|
||||
{
|
||||
this.pathOrExtension = pathOrExtension;
|
||||
this.parentCache = parentCache;
|
||||
this.iconDelegate = iconDelegate;
|
||||
}
|
||||
|
||||
public ImageSource GetPreferredImage(Size size, out bool isThumbnail)
|
||||
{
|
||||
isThumbnail = false;
|
||||
ImageSource result = null;
|
||||
|
||||
if (result == null && IsBiggerThan(size, SystemImageSizes.ExtraLargeSize))
|
||||
{
|
||||
// TODO: Sometimes, some images that don't have a Jumbo image for example, are returning
|
||||
// a "calculated" jumbo from e.g. the small icon. This looks bad. Find a way of skipping jumbo if
|
||||
// there is truly no jumbo... (e.g. .mbf file)
|
||||
if (Thumbnail != null)
|
||||
{
|
||||
isThumbnail = true;
|
||||
result = Thumbnail;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = JumboImage;
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null && IsBiggerThan(size, SystemImageSizes.LargeSize))
|
||||
{
|
||||
result = ExtraLargeImage;
|
||||
}
|
||||
|
||||
if (result == null && IsBiggerThan(size, SystemImageSizes.SmallSize))
|
||||
{
|
||||
result = LargeImage;
|
||||
}
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
result = SmallImage;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public ImageSource SmallImage
|
||||
{
|
||||
get { return GetImage(SystemImageSize.Small, ref smallImage); }
|
||||
}
|
||||
|
||||
public ImageSource LargeImage
|
||||
{
|
||||
get { return GetImage(SystemImageSize.Large, ref largeImage); }
|
||||
}
|
||||
|
||||
public ImageSource ExtraLargeImage
|
||||
{
|
||||
get { return GetImage(SystemImageSize.ExtraLarge, ref extraLargeImage); }
|
||||
}
|
||||
|
||||
public ImageSource JumboImage
|
||||
{
|
||||
get { return GetImage(SystemImageSize.Jumbo, ref jumboImage); }
|
||||
}
|
||||
|
||||
public ImageSource Thumbnail
|
||||
{
|
||||
get { return GetImage(SystemImageSize.Thumbnail, ref thumbnail); }
|
||||
}
|
||||
|
||||
private ImageSource GetImage(SystemImageSize size, ref ImageSource image)
|
||||
{
|
||||
if (image != null)
|
||||
{
|
||||
return image;
|
||||
}
|
||||
|
||||
if (iconDelegate != null)
|
||||
{
|
||||
switch (size)
|
||||
{
|
||||
case SystemImageSize.Small: return iconDelegate.SmallImage;
|
||||
case SystemImageSize.Large: return iconDelegate.LargeImage;
|
||||
case SystemImageSize.ExtraLarge: return iconDelegate.ExtraLargeImage;
|
||||
case SystemImageSize.Jumbo: return iconDelegate.JumboImage;
|
||||
}
|
||||
}
|
||||
|
||||
if (image == null)
|
||||
{
|
||||
image = parentCache.LoadImage(pathOrExtension, size);
|
||||
}
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
private static bool IsBiggerThan(Size size, Size biggerThan)
|
||||
{
|
||||
return size.Width > biggerThan.Width || size.Height > biggerThan.Height;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See http://msdn.microsoft.com/en-us/library/windows/desktop/bb762185(v=vs.85).aspx for more info
|
||||
/// </remarks>
|
||||
public enum SystemImageSize
|
||||
{
|
||||
/// <summary>
|
||||
/// These images are the Shell standard small icon size of 16x16, but the size can be customized by the user.
|
||||
/// </summary>
|
||||
Small,
|
||||
|
||||
/// <summary>
|
||||
/// The image size is normally 32x32 pixels. However, if the Use large icons option is selected from the Effects
|
||||
/// section of the Appearance tab in Display Properties, the image is 48x48 pixels.
|
||||
/// </summary>
|
||||
Large,
|
||||
|
||||
/// <summary>
|
||||
/// These images are the Shell standard extra-large icon size. This is typically 48x48, but the size can be customized by the user.
|
||||
/// </summary>
|
||||
ExtraLarge,
|
||||
|
||||
/// <summary>
|
||||
/// Windows Vista and later. The image is normally 256x256 pixels.
|
||||
/// </summary>
|
||||
Jumbo,
|
||||
|
||||
/// <summary>
|
||||
/// The readable thumbnail
|
||||
/// </summary>
|
||||
Thumbnail
|
||||
}
|
||||
|
||||
public static class SystemImageSizes
|
||||
{
|
||||
// TODO: Ideally, these should be dynamic properties, as some of the sizes are variable and can be customized by the user
|
||||
public static readonly Size SmallSize = new Size(16, 16);
|
||||
public static readonly Size LargeSize = new Size(32, 32);
|
||||
public static readonly Size ExtraLargeSize = new Size(48, 48);
|
||||
public static readonly Size JumboSize = new Size(256, 256);
|
||||
public static readonly Size ThumbnailSize = new Size(256, 256);
|
||||
}
|
||||
}
|
|
@ -1,221 +0,0 @@
|
|||
using Microsoft.Tools.TeamMate.Foundation.Native;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Foundation.Windows.Shell
|
||||
{
|
||||
internal class SystemImageList
|
||||
{
|
||||
private IntPtr hIml;
|
||||
private IImageList iImageList;
|
||||
private bool disposed;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a SystemImageList with the specified size
|
||||
/// </summary>
|
||||
/// <param name="size">Size of System ImageList</param>
|
||||
public SystemImageList(SHIL size)
|
||||
{
|
||||
this.ImageListSize = size;
|
||||
Create();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hImageList handle
|
||||
/// </summary>
|
||||
public IntPtr Handle
|
||||
{
|
||||
get
|
||||
{
|
||||
return this.hIml;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the size of System Image List to retrieve.
|
||||
/// </summary>
|
||||
public SHIL ImageListSize
|
||||
{
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the size of the Image List Icons.
|
||||
/// </summary>
|
||||
public Size Size
|
||||
{
|
||||
get
|
||||
{
|
||||
int cx = 0;
|
||||
int cy = 0;
|
||||
|
||||
if (iImageList == null)
|
||||
{
|
||||
NativeMethods.ImageList_GetIconSize(hIml, ref cx, ref cy);
|
||||
}
|
||||
else
|
||||
{
|
||||
iImageList.GetIconSize(ref cx, ref cy);
|
||||
}
|
||||
|
||||
return new Size(cx, cy);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a GDI+ copy of the icon from the ImageList
|
||||
/// at the specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">The index to get the icon for</param>
|
||||
/// <returns>The specified icon</returns>
|
||||
public Icon Icon(int index)
|
||||
{
|
||||
IntPtr hIcon = IconHandle(index);
|
||||
return (hIcon != IntPtr.Zero)? System.Drawing.Icon.FromHandle(hIcon) : null;
|
||||
}
|
||||
|
||||
public IntPtr IconHandle(int index)
|
||||
{
|
||||
IntPtr hIcon = IntPtr.Zero;
|
||||
if (iImageList == null)
|
||||
{
|
||||
hIcon = NativeMethods.ImageList_GetIcon(hIml, index, (int)IMAGELISTDRAWFLAGS.ILD_TRANSPARENT);
|
||||
}
|
||||
else
|
||||
{
|
||||
iImageList.GetIcon(index, (int)IMAGELISTDRAWFLAGS.ILD_TRANSPARENT, ref hIcon);
|
||||
}
|
||||
return hIcon;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the index of the icon for the specified file
|
||||
/// </summary>
|
||||
/// <param name="fileName">Filename to get icon for</param>
|
||||
/// <param name="forceLoadFromDisk">If True, then hit the disk to get the icon,
|
||||
/// otherwise only hit the disk if no cached icon is available.</param>
|
||||
/// <param name="iconState">Flags specifying the state of the icon
|
||||
/// returned.</param>
|
||||
/// <returns>Index of the icon</returns>
|
||||
public int IconIndex(string fileName, bool forceLoadFromDisk = false, SHGFI iconState = SHGFI.SHGFI_LARGEICON)
|
||||
{
|
||||
SHGFI dwFlags = SHGFI.SHGFI_SYSICONINDEX;
|
||||
FILE_ATTRIBUTE dwAttr;
|
||||
if (ImageListSize == SHIL.SHIL_SMALL)
|
||||
{
|
||||
dwFlags |= SHGFI.SHGFI_SMALLICON;
|
||||
}
|
||||
|
||||
// We can choose whether to access the disk or not. If you don't
|
||||
// hit the disk, you may get the wrong icon if the icon is
|
||||
// not cached. Also only works for files.
|
||||
if (!forceLoadFromDisk)
|
||||
{
|
||||
dwFlags |= SHGFI.SHGFI_USEFILEATTRIBUTES;
|
||||
dwAttr = FILE_ATTRIBUTE.FILE_ATTRIBUTE_NORMAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
dwAttr = 0;
|
||||
}
|
||||
|
||||
// sFileSpec can be any file. You can specify a
|
||||
// file that does not exist and still get the
|
||||
// icon, for example sFileSpec = "C:\PANTS.DOC"
|
||||
SHFILEINFO shfi = new SHFILEINFO();
|
||||
IntPtr retVal = NativeMethods.SHGetFileInfo(fileName, (uint)dwAttr, ref shfi, SHFILEINFO.Size, ((uint)(dwFlags) | (uint)iconState));
|
||||
|
||||
if (retVal.Equals(IntPtr.Zero))
|
||||
{
|
||||
System.Diagnostics.Debug.Assert((!retVal.Equals(IntPtr.Zero)), "Failed to get icon index");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return shfi.iIcon;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the SystemImageList
|
||||
/// </summary>
|
||||
private void Create()
|
||||
{
|
||||
// forget last image list if any:
|
||||
hIml = IntPtr.Zero;
|
||||
|
||||
bool supportsIImageList = Environment.OSVersion.IsWindowsXPOrGreater();
|
||||
|
||||
if (supportsIImageList)
|
||||
{
|
||||
// Get the System IImageList object from the Shell:
|
||||
Guid iidImageList = Marshal.GenerateGuidForType(typeof(IImageList));
|
||||
int ret = NativeMethods.SHGetImageList((int)ImageListSize, ref iidImageList, ref iImageList);
|
||||
|
||||
// the image list handle is the IUnknown pointer, but
|
||||
// using Marshal.GetIUnknownForObject doesn't return
|
||||
// the right value. It really doesn't hurt to make
|
||||
// a second call to get the handle:
|
||||
NativeMethods.SHGetImageListHandle((int)ImageListSize, ref iidImageList, ref hIml);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Prepare flags:
|
||||
SHGFI dwFlags = SHGFI.SHGFI_USEFILEATTRIBUTES | SHGFI.SHGFI_SYSICONINDEX;
|
||||
if (ImageListSize == SHIL.SHIL_SMALL)
|
||||
{
|
||||
dwFlags |= SHGFI.SHGFI_SMALLICON;
|
||||
}
|
||||
|
||||
// Get image list
|
||||
SHFILEINFO shfi = new SHFILEINFO();
|
||||
|
||||
// Call SHGetFileInfo to get the image list handle
|
||||
// using an arbitrary file:
|
||||
hIml = NativeMethods.SHGetFileInfo(".txt", (uint)FILE_ATTRIBUTE.FILE_ATTRIBUTE_NORMAL, ref shfi, SHFILEINFO.Size, (uint)dwFlags);
|
||||
System.Diagnostics.Debug.Assert((hIml != IntPtr.Zero), "Failed to create Image List");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears up any resources associated with the SystemImageList
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clears up any resources associated with the SystemImageList
|
||||
/// when disposing is true.
|
||||
/// </summary>
|
||||
/// <param name="disposing">Whether the object is being disposed</param>
|
||||
public virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposed)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
if (iImageList != null)
|
||||
{
|
||||
Marshal.ReleaseComObject(iImageList);
|
||||
}
|
||||
|
||||
iImageList = null;
|
||||
}
|
||||
}
|
||||
|
||||
disposed = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finalise for SysImageList
|
||||
/// </summary>
|
||||
~SystemImageList()
|
||||
{
|
||||
Dispose(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -106,8 +106,7 @@ namespace Microsoft.Tools.TeamMate.Foundation.Windows
|
|||
|
||||
public static void ForceToForeground(Window window)
|
||||
{
|
||||
IntPtr hWnd = window.GetHandle();
|
||||
ShellUtilities.ForceToForeground(hWnd);
|
||||
window.Activate();
|
||||
}
|
||||
|
||||
public static int GetIndexOfScreenContaining(Window window)
|
||||
|
|
|
@ -39,10 +39,6 @@ namespace Microsoft.Tools.TeamMate.Sandbox.Wpf
|
|||
|
||||
|
||||
|
||||
// Int32Rect bounds;
|
||||
// ScreenCapture.SelectScreenBounds(out bounds);
|
||||
|
||||
|
||||
Window window;
|
||||
// window = new CodeFlowReviews();
|
||||
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
<Window x:Class="Microsoft.Tools.TeamMate.Sandbox.Wpf.Preview.PreviewWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:fwcp="clr-namespace:Microsoft.Tools.TeamMate.Foundation.Windows.Controls.Preview;assembly=Microsoft.Tools.TeamMate.Foundation"
|
||||
Title="PreviewWindow" Height="500" Width="500" WindowState="Maximized">
|
||||
<fwcp:FilePreviewControl Name="previewControl"/>
|
||||
</Window>
|
|
@ -1,21 +0,0 @@
|
|||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Tools.TeamMate.Sandbox.Wpf.Preview
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for PreviewWindow.xaml
|
||||
/// </summary>
|
||||
public partial class PreviewWindow : Window
|
||||
{
|
||||
public PreviewWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
this.Loaded += PreviewWindow_Loaded;
|
||||
}
|
||||
|
||||
void PreviewWindow_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
previewControl.FilePath = @"zipfile.zip";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<!-- Force building to x86 at all times due to dependencies on x86 assemblies (TeamMate.exe, Expression) -->
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
</PropertyGroup>
|
||||
|
@ -191,9 +189,6 @@
|
|||
<Compile Include="NotificationToast.xaml.cs">
|
||||
<DependentUpon>NotificationToast.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Preview\PreviewWindow.xaml.cs">
|
||||
<DependentUpon>PreviewWindow.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="ProfileImageView.xaml.cs">
|
||||
<DependentUpon>ProfileImageView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -315,10 +310,6 @@
|
|||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Preview\PreviewWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="ProfileImageView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
@ -622,8 +613,6 @@
|
|||
<Resource Include="Resources\Icons\Office15\JotInsertAudioRecordingShort.32x32x32.png" />
|
||||
<Resource Include="Resources\Icons\Office15\JotInsertVideoRecordingShort.16x16x32.png" />
|
||||
<Resource Include="Resources\Icons\Office15\JotInsertVideoRecordingShort.32x32x32.png" />
|
||||
<Resource Include="Resources\Icons\Office15\JotScreenCapture.16x16x32.png" />
|
||||
<Resource Include="Resources\Icons\Office15\JotScreenCapture.32x32x32.png" />
|
||||
<Resource Include="Resources\Icons\Office15\LevelingOptions.16x16x32.png" />
|
||||
<Resource Include="Resources\Icons\Office15\LevelingOptions.32x32x32.png" />
|
||||
<Resource Include="Resources\Icons\Office15\LevelingOptions.48x48x32.png" />
|
||||
|
@ -822,7 +811,4 @@
|
|||
<Resource Include="Resources\Icons\Other\ErrorExclamation_12x12x32_Modified.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(BuildScripts)\Microsoft.Tools.TeamMate.targets" />
|
||||
<Target Name="BeforeBuild">
|
||||
<KillTask ProcessName="$(TargetName)" ContinueOnError="true" />
|
||||
</Target>
|
||||
</Project>
|
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 315 B |
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 457 B |
|
@ -26,9 +26,6 @@
|
|||
|
||||
<ImageSource x:Key="MinimizeGlyphIcon">/Resources/Icons/Other/MinimizeGlyph.png</ImageSource>
|
||||
|
||||
<ImageSource x:Key="ScreenRecorderIcon">/Resources/Icons/Office15/JotInsertVideoRecordingShort.32x32x32.png</ImageSource>
|
||||
|
||||
|
||||
<ImageSource x:Key="WhiteCloseGlyphIcon">/Resources/Icons/Other/CloseGlyph.png</ImageSource>
|
||||
<ImageSource x:Key="CloseGlyphIcon">/Resources/Icons/Office15/ClosePaneGlyph.16x16x32.png</ImageSource>
|
||||
|
||||
|
|
|
@ -186,29 +186,6 @@
|
|||
</fwi:UICommand.InputGestures>
|
||||
</fwi:UICommand>
|
||||
|
||||
|
||||
<fwi:UICommand x:Key="AttachScreenshotCommand"
|
||||
Description="Attach a picture of part of the screen, or any program that is not minimized to the taskbar."
|
||||
LargeImage="/Resources/Icons/Office15/JotScreenCapture.32x32x32.png"
|
||||
ScreenTipTitle="Attach Screenshot"
|
||||
SmallImage="/Resources/Icons/Office15/JotScreenCapture.16x16x32.png"
|
||||
Text="Screenshot">
|
||||
<fwi:UICommand.InputGestures>
|
||||
<KeyGesture>F6</KeyGesture>
|
||||
</fwi:UICommand.InputGestures>
|
||||
</fwi:UICommand>
|
||||
|
||||
<fwi:UICommand x:Key="AttachScreenRecordingCommand"
|
||||
Description="Attach an interactive video recording of part of the screen, or any program that is not minimized to the taskbar."
|
||||
LargeImage="/Resources/Icons/Office15/JotInsertVideoRecordingShort.32x32x32.png"
|
||||
ScreenTipTitle="Attach Screen Recording"
|
||||
SmallImage="/Resources/Icons/Office15/JotInsertVideoRecordingShort.16x16x32.png"
|
||||
Text="Screen Recording">
|
||||
<fwi:UICommand.InputGestures>
|
||||
<KeyGesture>F7</KeyGesture>
|
||||
</fwi:UICommand.InputGestures>
|
||||
</fwi:UICommand>
|
||||
|
||||
<fwi:UICommand x:Key="AddLinkCommand"
|
||||
Description="Add a link to the work item."
|
||||
LargeImage="/Resources/Icons/Office15/LinkTasks.32x32x32.png"
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<!-- Force building to x86 at all times due to dependencies on x86 assemblies (Expression) -->
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<NuGetPackageImportStamp>
|
||||
</NuGetPackageImportStamp>
|
||||
<PublishUrl>publish\Debug\</PublishUrl>
|
||||
|
@ -768,8 +766,6 @@
|
|||
<Resource Include="Resources\Icons\Office15\JotInsertAudioRecordingShort.32x32x32.png" />
|
||||
<Resource Include="Resources\Icons\Office15\JotInsertVideoRecordingShort.16x16x32.png" />
|
||||
<Resource Include="Resources\Icons\Office15\JotInsertVideoRecordingShort.32x32x32.png" />
|
||||
<Resource Include="Resources\Icons\Office15\JotScreenCapture.16x16x32.png" />
|
||||
<Resource Include="Resources\Icons\Office15\JotScreenCapture.32x32x32.png" />
|
||||
<Resource Include="Resources\Icons\Office15\LevelingOptions.16x16x32.png" />
|
||||
<Resource Include="Resources\Icons\Office15\LevelingOptions.32x32x32.png" />
|
||||
<Resource Include="Resources\Icons\Office15\LevelingOptions.48x48x32.png" />
|
||||
|
@ -1110,11 +1106,9 @@
|
|||
<Resource Include="Resources\Icons\Other\Yammer.32x32x32.png" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(BuildScripts)\Microsoft.Tools.TeamMate.targets" />
|
||||
<Target Name="BeforeBuild">
|
||||
<KillTask ProcessName="$(TargetName)" ContinueOnError="true" />
|
||||
</Target>
|
||||
<Target Name="AfterPublish" />
|
||||
<Target Name="Upload" />
|
||||
<Target Name="BeforeBuild"/>
|
||||
<Target Name="AfterPublish"/>
|
||||
<Target Name="Upload"/>
|
||||
<PropertyGroup>
|
||||
<CleanDependsOn>
|
||||
$(CleanDependsOn);
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Windows" />
|
||||
<Reference Include="Windows.Data" />
|
||||
<Reference Include="Windows.Foundation" />
|
||||
<Reference Include="Windows.UI" />
|
||||
|
|
Загрузка…
Ссылка в новой задаче