Seed the repro from https://garage-02.visualstudio.com/_git/TeamMate with last commit being d7884798a72f7772f3a09618ff5d118be3433610

This commit is contained in:
Marcus Markiewicz 2021-06-25 15:05:28 -04:00
Родитель 8c53aa2beb
Коммит 759aa882ec
1435 изменённых файлов: 105628 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<solution>
<add key="disableSourceControlIntegration" value="true" />
</solution>
<config>
<add key="repositoryPath" value="..\packages" />
</config>
</configuration>

4
Source/Build/Build.bat Normal file
Просмотреть файл

@ -0,0 +1,4 @@
@echo off
setlocal
powershell.exe -command ". %~dp0\%~n0.ps1" %1 %2 %3 %4 %5 %6 %7 %8 %9

237
Source/Build/Build.ps1 Normal file
Просмотреть файл

@ -0,0 +1,237 @@
<#
.SYNOPSIS
A script for building and publishing TeamMate to Toolbox.
.DESCRIPTION
This scripts takes care of versioning TeamMate, performing a clean build, and generating
ClickOnce files. It can also publish the ClickOnce files to the Toolbox file share.
.PARAMETER debug
Builds the Debug flavor as opposed to the (default) Relase flavor.
.PARAMETER updateVersion
If true, generates a new version and updates source files with that value
.PARAMETER build
If true, performs a build (default value is true unless upload is specified).
.PARAMETER upload
If true, uploads the previous build to Toolbox. This must be invoked after having performed a build.
.PARAMETER noresign
If specified, avoids re-signing the ClickOnce manifest with the custom patched manifest.
.PARAMETER local
If specified, generates a published build targetted for local testing only, NOT FOR UPLOADING TO TOOLBOX.
#>
param([switch]$debug, [switch] $updateVersion, [switch] $build, [switch] $upload, [switch]$noresign, [switch]$local)
###############################################################################
# Helper Functions
###############################################################################
function Get-ScriptDirectory()
{
$invocation = (Get-Variable MyInvocation -Scope 1).Value;
return Split-Path $invocation.MyCommand.Path;
}
function Write-Info($message)
{
Write-Host -ForegroundColor Cyan $message;
}
function Write-Warning($message)
{
Write-Host -ForegroundColor Yellow $message;
}
function Write-Error($message)
{
Write-Host -ForegroundColor Red $message;
}
# Updates a file with a new content, only if the content has changed.
# Also adds the file to a list of files to checkout if the content did change.
function UpdateFile($file, $content, [switch] $UTF8)
{
$oldContent = [System.IO.File]::ReadAllText($file);
if( $content -ne $oldContent )
{
# Ensure version file is writeable
$fileInfo = New-Object System.IO.FileInfo $file
$fileInfo.IsReadOnly = $false;
if( $utf8 )
{
Set-Content -path $file -value $content -encoding UTF8;
}
else
{
Set-Content -path $file -value $content;
}
Write-Host "Updated $file with new version info";
return $true;
}
return $false;
}
# Generates a new build version based on the current date
function GenerateBuildVersion()
{
# We will calculate the 3rd component (upgrade segment) of the version number
# based on the date. The number has to be less than 65355, so the first digit
# should be a number between 1-6 (if we use 0 we mess up stuff). The first number
# will be given by the year mod 6 + 1, e.g. 2009 % 6 -> 5 + 1 -> 6
$date = Get-Date;
$firstDigit = ($date.Year % 6) + 1;
$buildVersion = "{0}{1:00}{2:00}" -f $firstDigit, $date.Month, $date.Day;
return $buildVersion;
}
# Parses a full version, and returns an object with properties for each version component
function ParseVersion($version)
{
$regex = [regex] "(\d+)\.(\d+)\.(\d+)\.(\d+)";
$match = $regex.Match($version);
if(!$match.Success)
{
throw ("String does not match expected version format: {0}" -f $version);
}
$versionObject = new-object psobject;
$versionObject | add-member noteproperty "Major" ([int] $match.Groups[1].Value);
$versionObject | add-member noteproperty "Minor" ([int] $match.Groups[2].Value);
$versionObject | add-member noteproperty "Build" ([int] $match.Groups[3].Value);
$versionObject | add-member noteproperty "Revision" ([int] $match.Groups[4].Value);
return $versionObject;
}
# Updates the build version (3rd component) of a given full version
function UpdateBuildVersion($currentVersion, $buildVersion)
{
$currentBuildVersion = $currentVersion.Build;
if($buildVersion -ne $currentBuildVersion)
{
$currentVersion.Build = $buildVersion;
$currentVersion.Revision = 0;
if($buildVersion -lt $currentBuildVersion)
{
$currentVersion.Minor += 1;
Write-Warning ("WARNING: IMPORTANT!!!! Build version rolled over from {0} to {1} so incrementing minor version to {2}" -f $currentBuildVersion,$buildVersion,$currentVersion.Minor);
}
else
{
$currentVersion.Build = $buildVersion;
}
}
else
{
$currentVersion.Revision = $version.Revision + 1;
}
}
###############################################################################
# Script
###############################################################################
$msbuild = "C:\Program Files (x86)\MSBuild\14.0\Bin\MSBuild.exe"
$scriptFolder = Get-ScriptDirectory;
$versionFile = "$scriptFolder\version.txt";
$buildInfoFile = "$scriptFolder\BuildInfo.cs";
$versionTargetsFile = "$scriptFolder\Microsoft.Internal.Tools.TeamMate.Version.targets";
$project = "$scriptFolder\..\TeamMate\TeamMate.csproj";
$resign = (-not $noresign);
if(-not ($updateVersion -or $build -or $upload))
{
Write-Error "Please specify one or more of: -updateVersion, -build, -upload";
exit 1
}
if($debug)
{
$configs = ( "Debug" );
}
else
{
$configs = ( "Release" );
}
if($updateVersion)
{
$buildVersion = GenerateBuildVersion
$version = ParseVersion (gc $versionFile);
UpdateBuildVersion $version $buildVersion;
$newVersion = "{0}.{1}.{2}.{3}" -f $version.Major,$version.Minor,$version.Build,$version.Revision;
Write-Info "Updating Build Version to $newVersion..."
$ignore = UpdateFile $versionFile $newVersion;
$buildInfo = Get-Content $buildInfoFile;
$buildInfo = $buildInfo -replace "AssemblyVersion\(.*", "AssemblyVersion(""$newVersion"")]";
$buildInfo = $buildInfo -replace "AssemblyFileVersion\(.*", "AssemblyFileVersion(""$newVersion"")]";
$ignore = UpdateFile $buildInfoFile $buildInfo;
$versionTargets = Get-Content $versionTargetsFile;
$versionTargets = $versionTargets -replace "<ApplicationVersion>.*</ApplicationVersion>", "<ApplicationVersion>$newVersion</ApplicationVersion>";
$ignore = UpdateFile $versionTargetsFile $versionTargets -UTF8;
}
if($build)
{
foreach($config in $configs)
{
Write-Info "Building $config...";
. "$msbuild" "$project" "/p:Configuration=$config" "/p:Publish=true" "/p:Local=$local" /nologo /v:m /t:rebuild
if($LastExitCode -ne 0 )
{
Write-Error "MSBuild failed. Exiting early!";
exit 1
}
}
foreach($config in $configs)
{
Write-Info "Publishing ClickOnce files for $config...";
. "$msbuild" "$project" "/p:Configuration=$config" "/p:Publish=true" "/p:Resign=$resign" "/p:Local=$local" /nologo /v:m /t:publish
if($LastExitCode -ne 0 )
{
Write-Error "Publishing failed!";
exit 1;
}
}
}
if($upload)
{
foreach($config in $configs)
{
Write-Info "Uploading ClickOnce files for $config...";
. "$msbuild" "$project" "/p:Configuration=$config" "/p:Publish=true" /nologo /v:m /t:upload
if($LastExitCode -ne 0 )
{
Write-Error "Uploading failed!";
exit 1;
}
}
}
Write-Host ""
Write-Host -ForegroundColor Green "Done...";

26
Source/Build/BuildInfo.cs Normal file
Просмотреть файл

@ -0,0 +1,26 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("TeamMate")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("2.1.21106.0")]
[assembly: AssemblyFileVersion("2.1.21106.0")]

Просмотреть файл

@ -0,0 +1,9 @@
@echo off
setlocal
REM http://msdn.microsoft.com/en-us/library/ff699202.aspx
set CWD=%~dp0
SET CWD=%CWD:~0,-1%
makecert -sv "%CWD%\TeamMate.pvk" -r "%CWD%\TeamMate.cer" -n "CN=Ben Amodio"
pvk2pfx -pvk "%CWD%\TeamMate.pvk" -spc "%CWD%\TeamMate.cer" -pfx "%CWD%\TeamMate.pfx"

Просмотреть файл

@ -0,0 +1 @@
sn -d TEAMMATE

Просмотреть файл

@ -0,0 +1,7 @@
@echo off
setlocal
set SN="%~dp0Tools\sn.exe"
set PFXFILE="%~dp0TeamMate.pfx"
%SN% -i %PFXFILE% TEAMMATE
%PFXFILE%

Двоичные данные
Source/Build/Libraries/MSBuildTasks.dll Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,58 @@
<!--
***********************************************************************************************
Microsoft.Internal.Tools.TeamMate.targets
This file defines the custom variables and steps in the standard build process for TeamMate
C# .NET projects.
Copyright (C) Microsoft Corporation. All rights reserved.
***********************************************************************************************
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<FileAlignment>512</FileAlignment>
<WarningLevel>4</WarningLevel>
<ErrorReport>prompt</ErrorReport>
<NoWarn>467;618</NoWarn>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Publish)' == 'true' ">
<!-- Only sign assemblies if publishing to Toolbox -->
<SignAssembly>true</SignAssembly>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\TeamMate.pfx</AssemblyOriginatorKeyFile>
<!-- For safety purposes, never assign the InstallUrl unless Publish was explicitly set -->
<InstallUrl Condition=" $(Local) != 'true' ">\\tkfiltoolbox\tools\teammate\releases\production\</InstallUrl>
</PropertyGroup>
<PropertyGroup>
<BuildScripts>$(MSBuildThisFileDirectory)</BuildScripts>
</PropertyGroup>
<PropertyGroup>
<ExternalPath>$(MSBuildThisFileDirectory)\..\External</ExternalPath>
<OfficeExternalPath>$(ExternalPath)\Office\14.0</OfficeExternalPath>
</PropertyGroup>
<UsingTask TaskName="MSBuildTasks.KillTask" AssemblyFile="$(BuildScripts)\Libraries\MSBuildTasks.dll" />
</Project>

Просмотреть файл

@ -0,0 +1,24 @@
<!--
***********************************************************************************************
Microsoft.Internal.Tools.TeamMate.targets
This file defines the custom variables and steps in the standard build process for TeamMate
C# .NET projects.
Copyright (C) Microsoft Corporation. All rights reserved.
***********************************************************************************************
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ApplicationVersion>2.1.21106.0</ApplicationVersion>
</PropertyGroup>
<ItemGroup>
<Compile Include="$(MSBuildThisFileDirectory)\BuildInfo.cs">
<InProject>False</InProject>
</Compile>
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,33 @@
<!--
***********************************************************************************************
Microsoft.Internal.Tools.TeamMate.targets
This file defines the custom variables and steps in the standard build process for TeamMate
C# .NET projects.
Copyright (C) Microsoft Corporation. All rights reserved.
***********************************************************************************************
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BaseIntermediateOutputPath>obj\</BaseIntermediateOutputPath>
<BaseBinOutputPath>bin\</BaseBinOutputPath>
<BasePublishOutputPath>publish\</BasePublishOutputPath>
<OutputPath>$(BaseBinOutputPath)$(Configuration)\</OutputPath>
</PropertyGroup>
<PropertyGroup Condition=" '$(ClickOncePublish)' == 'True'">
<PublishUrl>$(BasePublishOutputPath)$(Configuration)\</PublishUrl>
<!-- KLUDGE: Required when doing msbuild /t:publish on the command-line -->
<PublishDir Condition="'$(BuildingInsideVisualStudio)' != 'true'">$(PublishUrl)</PublishDir>
</PropertyGroup>
<Import Project="Microsoft.Internal.Tools.TeamMate.Version.targets" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Двоичные данные
Source/Build/TeamMate.cer Normal file

Двоичный файл не отображается.

Двоичные данные
Source/Build/TeamMate.pvk Normal file

Двоичный файл не отображается.

Двоичные данные
Source/Build/Tools/1033/snrc.dll Normal file

Двоичный файл не отображается.

Двоичные данные
Source/Build/Tools/mage.exe Normal file

Двоичный файл не отображается.

Двоичные данные
Source/Build/Tools/mt.exe Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,9 @@
<?xml version ="1.0"?>
<!-- This allows mt.exe to run on machines with the CLR v4 installed but not 1.1 or 2.0 -->
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0"/>
<supportedRuntime version="v2.0.50727"/>
<supportedRuntime version="v1.1.4322"/>
</startup>
</configuration>

Двоичные данные
Source/Build/Tools/sn.exe Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,6 @@
<?xml version ="1.0"?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<requiredRuntime safemode="true" imageVersion="v4.0.30319" version="v4.0.30319"/>
</startup>
</configuration>

Просмотреть файл

@ -0,0 +1,120 @@
<#
.SYNOPSIS
Updates TeamMate's published ClickOnce application to enable Visual Styles on the WPF app.
.DESCRIPTION
This kludgy workaround is an automation of the steps described in
http://msdn.microsoft.com/en-us/library/hh323463.aspx
The ONLY reason why we need to introduce Microsoft.Windows.Common-Controls
in our custom manifest is to support previewing Outlook message files.
.PARAMETER publishDir
The location of the ClickOnce published files built by MSBuild.
.PARAMETER manifestFile
A custom .manifest file that will be embedded in the resulting TeamMate.exe.deploy file
.PARAMETER certFile
Specifies the name of an X509 certificate file with which to sign a manifest or license file.
#>
param($publishDir, $manifestFile, $certFile);
# Constants used below
$keyContainer = "TEAMMATE";
$password = "TeamMate";
function Get-ScriptDirectory()
{
$invocation = (Get-Variable MyInvocation -Scope 1).Value;
return Split-Path $invocation.MyCommand.Path;
}
function Join-Path-And-Test($p1, $p2)
{
$result = Join-Path $p1 $p2;
if(-not (Test-Path $result))
{
$message = "Expected file {0} was not found" -f $result;
Write-Host -ForegroundColor Red $message;
exit 1;
}
return $result;
}
$buildFolder = Get-ScriptDirectory;
$mageExe = Join-Path-And-Test $buildFolder "Tools\mage.exe";
$mtExe = Join-Path-And-Test $buildFolder "Tools\mt.exe";
$snExe = Join-Path-And-Test $buildFolder "Tools\sn.exe";
if(-not (Test-Path -PathType Container $publishDir))
{
throw ("Publish directory {0} was not found." -f $publishDir);
}
if(-not (Test-Path -PathType Leaf $manifestFile))
{
throw ("Manifest file {0} was not found." -f $manifestFile);
}
if(-not (Test-Path -PathType Leaf $certFile))
{
throw ("Certificate file {0} was not found." -f $certFile);
}
$applicationFile = (dir $publishDir -filter *.application)[0].FullName;
$appFiles = Join-Path-And-Test $publishDir "Application Files";
$latestPublishPath = (dir $appFiles| sort -Descending LastWriteTime )[0].FullName;
$exeDeployFile = (dir $latestPublishPath -filter *.exe.deploy)[0].FullName;
$publishedManifestFile = (dir $latestPublishPath -filter *.manifest)[0].FullName;
Write-Host "Updating published ClickOnce application at $latestPublishPath";
Write-Host "";
Write-Host "Embedding custom manifest file for published TeamMate.exe.deploy...";
& $mtExe -nologo -manifest "$manifestFile" "-outputresource:$exeDeployFile";
if($LastExitCode -ne 0)
{
Write-Error "$mtExe -nologo -manifest `"$manifestFile`" `"-outputresource:$exeDeployFile`"";
Write-Error "Failed with exit code $LastExitCode";
exit $LastExitCode;
}
Write-Host "Re-signing TeamMate.exe.deploy...";
& $snExe -q -Rca $exeDeployFile $keyContainer;
if($LastExitCode -ne 0)
{
Write-Error "$snExe -q -Rca `"$exeDeployFile`" $keyContainer";
Write-Error "Failed with exit code $LastExitCode";
exit $LastExitCode;
}
Write-Host "Updating published manifest TeamMate.exe.manifest...";
$deployFiles = dir "$latestPublishPath\*.deploy";
$deployFiles | %{ $newName = $_.FullName.Substring(0, $_.FullName.Length - 7); ren $_.FullName $newName };
& $mageExe -u "$publishedManifestFile" -cf "$certFile" -password "$password";
$deployFiles | %{ $oldName = $_.FullName.Substring(0, $_.FullName.Length - 7); ren $oldName $_.FullName };
if($LastExitCode -ne 0)
{
Write-Error "$mageExe -u `"$publishedManifestFile`" -cf `"$certFile`" -password pwd";
Write-Error "Failed with exit code $LastExitCode";
exit $LastExitCode;
}
Write-Host "Updating published TeamMate.application...";
& $mageExe -u "$applicationFile" -appm "$publishedManifestFile" -cf "$certFile" -password "$password";
if($LastExitCode -ne 0)
{
Write-Error "$mageExe -u `"$applicationFile`" -appm `"$publishedManifestFile`" -cf `"$certFile`" -password pwd";
Write-Error "Failed with exit code $LastExitCode";
exit $LastExitCode;
}
Write-Host "Done";

1
Source/Build/version.txt Normal file
Просмотреть файл

@ -0,0 +1 @@
2.1.21106.0

Просмотреть файл

@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), Build\Microsoft.Internal.Tools.TeamMate.Settings.targets))\Build\Microsoft.Internal.Tools.TeamMate.Settings.targets" />
<PropertyGroup>
<ProjectGuid>{9AC62340-334D-489B-8C36-5EC5F4C56C8E}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Internal.Tools.TeamMate.Client</RootNamespace>
<AssemblyName>Microsoft.Internal.Tools.TeamMate.Client</AssemblyName>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="WorkItemCreationInfo.cs" />
<Compile Include="PathUtilities.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TeamMateClient.cs" />
</ItemGroup>
<Import Project="$(BuildScripts)\Microsoft.Internal.Tools.TeamMate.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,57 @@
using System;
using System.IO;
namespace Microsoft.Internal.Tools.TeamMate.Client
{
/// <summary>
/// Provides utility methods for manipulating file system paths.
/// </summary>
/// <remarks>
/// This is a trimmed local copy of Foundation.IO.PathUtilities, as we do not want dependencies
/// to another assembly in this client one.
/// </remarks>
internal static class PathUtilities
{
/// <summary>
/// Returns a unique filename that doesn't exist in the given path,
/// by appending an incremented number to the filename (without the
/// extension).
/// </summary>
/// <param name="path">An initial path.</param>
/// <returns>A unique filename path derived from the input.</returns>
public static string EnsureFilenameIsUnique(string path)
{
if (!Exists(path))
{
return path;
}
string name = Path.GetFileNameWithoutExtension(path);
string extension = Path.GetExtension(path);
string dir = Path.GetDirectoryName(path);
int increment = 1;
do
{
increment++;
string newName = String.Format("{0} ({1}){2}", name, increment, extension);
// TODO: Need to make sure path did not exceed max path length.
path = Path.Combine(dir, newName);
}
while (Exists(path));
return path;
}
/// <summary>
/// Determines whether the specified path exists (as a file or directory).
/// </summary>
/// <param name="path">The path.</param>
/// <returns><c>true</c> if the path exists; <c>false</c> if otherwise.</returns>
private static bool Exists(string path)
{
return File.Exists(path) || Directory.Exists(path);
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
using System.Reflection;
using System.Runtime.InteropServices;
[assembly: AssemblyTitle("Client")]
[assembly: AssemblyDescription("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("9ac62340-334d-489b-8c36-5ec5f4c56c8e")]

Просмотреть файл

@ -0,0 +1,96 @@
using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.IO;
using System.Xml.Linq;
namespace Microsoft.Internal.Tools.TeamMate.Client
{
/// <summary>
/// A client class to launch and interact with an installed TeamMateClient instace.
/// </summary>
public class TeamMateClient
{
private const string TeamMateDownloadUrl = "http://toolbox/teammate";
/// <summary>
/// Determines whether TeamMate is installed for the current user.
/// </summary>
public static bool IsInstalled()
{
bool isInstalled = Registry.GetValue(@"HKEY_CLASSES_ROOT\TeamMate.tmx", null, null) != null;
return isInstalled;
}
/// <summary>
/// Open the TeamMate download page in an external web browser.
/// </summary>
public static void LaunchDownloadPage()
{
Process.Start(TeamMateDownloadUrl);
}
/// <summary>
/// Launches TeamMate, creating a work item with the given creation information.
/// </summary>
/// <param name="createInfo">The create information.</param>
public void CreateWorkItem(WorkItemCreationInfo createInfo)
{
if (createInfo == null)
{
throw new ArgumentNullException("createInfo");
}
EnsureIsInstalled();
string tmxFile = Path.Combine(Path.GetTempPath(), "Outlook.tmx");
tmxFile = PathUtilities.EnsureFilenameIsUnique(tmxFile);
XDocument doc = CreateActionXml(createInfo);
doc.Save(tmxFile);
Process.Start(tmxFile);
}
private static XDocument CreateActionXml(WorkItemCreationInfo createInfo)
{
XElement fieldsElement = new XElement("Fields");
foreach (var entry in createInfo.Fields)
{
fieldsElement.Add(new XElement("Field", new XAttribute("Name", entry.Key), entry.Value));
}
XElement attachmentsElement = new XElement("Attachments");
foreach (var attachment in createInfo.Attachments)
{
attachmentsElement.Add(new XElement("Attachment",
new XAttribute("Path", attachment.Path),
new XAttribute("DeleteOnSave", attachment.DeleteOnSave)
));
}
XDocument doc = new XDocument(
new XElement("TeamMate",
new XAttribute("Version", "1.0"),
new XAttribute("DeleteOnLoad", "true"),
new XElement("Action",
new XAttribute("Type", "CreateWorkItem"),
new XElement("WorkItem",
fieldsElement,
attachmentsElement
)
)
)
);
return doc;
}
private static void EnsureIsInstalled()
{
if (!IsInstalled())
{
throw new InvalidOperationException("TeamMate cannot be launched. Please install TeamMate from " + TeamMateDownloadUrl);
}
}
}
}

Просмотреть файл

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
namespace Microsoft.Internal.Tools.TeamMate.Client
{
public class WorkItemCreationInfo
{
private IDictionary<string, object> fields = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
public WorkItemCreationInfo()
{
this.Attachments = new List<AttachmentInfo>();
}
public string Title
{
get { return this.GetField("System.Title") as string; }
set { this.SetField("System.Title", value); }
}
public string History
{
get { return this.GetField("System.History") as string; }
set { this.SetField("System.History", value); }
}
public string Description
{
get { return this.GetField("System.Description") as string; }
set { this.SetField("System.Description", value); }
}
public IDictionary<string, object> Fields
{
get { return this.fields; }
}
public void SetField(string name, object value)
{
if (value != null)
{
this.fields[name] = value;
}
else
{
this.fields.Remove(name);
}
}
public object GetField(string name)
{
object result;
this.fields.TryGetValue(name, out result);
return result;
}
public ICollection<AttachmentInfo> Attachments { get; private set; }
}
public class AttachmentInfo
{
public AttachmentInfo(string path, bool deleteOnSave = false)
{
if (path == null)
{
throw new ArgumentNullException("path");
}
this.Path = path;
this.DeleteOnSave = deleteOnSave;
}
public string Path { get; set; }
public bool DeleteOnSave { get; set; }
}
}

Двоичные данные
Source/External/Lync/Microsoft.Lync.Controls.Framework.dll поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
Source/External/Lync/Microsoft.Lync.Controls.dll поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
Source/External/Lync/Microsoft.Lync.Model.dll поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
Source/External/Lync/Microsoft.Lync.Utilities.dll поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
Source/External/Lync/Microsoft.Office.Uc.dll поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
Source/External/Office/14.0/Microsoft.Office.Interop.Excel.dll поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
Source/External/Office/14.0/Microsoft.Office.Interop.OneNote.dll поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
Source/External/Office/14.0/Microsoft.Office.Interop.Outlook.dll поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
Source/External/Office/14.0/Microsoft.Office.Interop.PowerPoint.dll поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
Source/External/Office/14.0/Microsoft.Office.Interop.Word.dll поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
Source/External/Office/14.0/OFFICE.DLL поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
Source/External/Unofficial.HockeySDK.WPF/Microsoft.HockeyApp.Core45.dll поставляемый Normal file

Двоичный файл не отображается.

Двоичные данные
Source/External/Unofficial.HockeySDK.WPF/Microsoft.HockeyApp.Kit.dll поставляемый Normal file

Двоичный файл не отображается.

5
Source/External/Unofficial.HockeySDK.WPF/readme.txt поставляемый Normal file
Просмотреть файл

@ -0,0 +1,5 @@
Signed versions of the Unofficial HockeyApp SDK for WPF applications, by MACK Mathieu.
See https://github.com/mathieumack/HockeySDK-Windows for more info.
Signing was required to consume in a full trust application in ClickOnce.

Просмотреть файл

@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
namespace Microsoft.Internal.Tools.TeamMate.Foundation
{
/// <summary>
/// A comparer that compares absolute URIs.
/// </summary>
public class AbsoluteUriComparer : IEqualityComparer<Uri>
{
/// <summary>
/// Determines whether the specified objects are equal.
/// </summary>
/// <param name="x">The first object of type <paramref name="T" /> to compare.</param>
/// <param name="y">The second object of type <paramref name="T" /> to compare.</param>
/// <returns>
/// true if the specified objects are equal; otherwise, false.
/// </returns>
public bool Equals(Uri x, Uri y)
{
return String.Equals(Normalize(x), Normalize(y), StringComparison.Ordinal);
}
/// <summary>
/// Returns a hash code for this instance.
/// </summary>
/// <param name="obj">The object.</param>
/// <returns>
/// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.
/// </returns>
public int GetHashCode(Uri obj)
{
return Normalize(obj).GetHashCode();
}
/// <summary>
/// Normalizes the specified URI to a comparable value.
/// </summary>
/// <param name="uri">The URI.</param>
/// <returns>The normalized URI string.</returns>
private string Normalize(Uri uri)
{
// TODO: Match this more closely to TFS AbsoluteURIComparer. E.g. do we need to trim slashes et al?
return uri.AbsoluteUri.ToLowerInvariant();
}
}
}

Просмотреть файл

@ -0,0 +1,25 @@
using System;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Chaos
{
/// <summary>
/// An exception thrown by the chaos monkey whenever it introduces chaos into our product.
/// </summary>
public class ChaosException : Exception
{
public ChaosException()
: base("The chaos monkey was naughty and injected this exception!")
{
}
public ChaosException(string message)
: base(message)
{
}
public ChaosException(string message, Exception inner)
: base(message, inner)
{
}
}
}

Просмотреть файл

@ -0,0 +1,111 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics;
using System;
using System.Threading.Tasks;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Chaos
{
public static class ChaosMonkey
{
[ThreadStatic]
private static Random random;
private static readonly Random GlobalRandom = new Random();
private static readonly Task NullTask = Task.FromResult<object>(null);
/// <summary>
/// Enables or disables chaos in the system.
/// </summary>
public static bool IsEnabled { get; set; }
/// <summary>
/// Potentially introduce chaos in the system, for a given chaos scenario.
/// </summary>
/// <param name="scenario">The scenario.</param>
public static Task ChaosAsync(ChaosScenario scenario)
{
Assert.ParamIsNotNull(scenario, nameof(scenario));
if (IsEnabled)
{
return DoChaosAsync(scenario);
}
else
{
return NullTask;
}
}
/// <summary>
/// Potentially introduce chaos in the system, for a given chaos scenario.
/// </summary>
/// <param name="scenario">The scenario.</param>
public static void Chaos(ChaosScenario scenario)
{
Assert.ParamIsNotNull(scenario, nameof(scenario));
if (IsEnabled)
{
if (scenario.Delay > 0)
{
DelayAsync(scenario).Wait();
}
Fail(scenario);
}
}
private static async Task DoChaosAsync(ChaosScenario scenario)
{
if (IsEnabled)
{
if (scenario.Delay > 0)
{
await DelayAsync(scenario);
}
Fail(scenario);
}
}
private static void Fail(ChaosScenario scenario)
{
if (ShouldFail(scenario.FailureRate))
{
throw new ChaosException($"The chaos monkey was naughty and injected this exception! ({scenario.Name})");
}
}
private static bool ShouldFail(double failureRate)
{
return failureRate > 0 && GetThreadSafeRandom().NextDouble() <= failureRate;
}
private static Task DelayAsync(ChaosScenario scenario)
{
Log.Info($"Delaying {scenario.Delay}ms for chaos scenario '{scenario.Name}'");
return Task.Delay(scenario.Delay);
}
public static Task ChaosAsync(object chooseProject)
{
throw new NotImplementedException();
}
// Random is not thread-safe so use an instance per thread
// See https://blogs.msdn.microsoft.com/pfxteam/2009/02/19/getting-random-numbers-in-a-thread-safe-way/
private static Random GetThreadSafeRandom()
{
if (random == null)
{
int seed;
lock (GlobalRandom)
{
seed = GlobalRandom.Next();
random = new Random(seed);
}
}
return random;
}
}
}

Просмотреть файл

@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Chaos
{
/// <summary>
/// Defines a chaos scenario and its metadata for use by the Chaos moneky.
/// </summary>
public class ChaosScenario : INotifyPropertyChanged
{
public const double NeverFail = 0.0;
public const double FailSeldomly = 0.25;
public const double FailSometimes = 0.5;
public const double FailFrequently = 0.75;
public const double FailAlways = 1.0;
public const int Slow = 1000;
public const int VerySlow = 3000;
public const int SuperSlow = 10000;
private double failureRate;
private int delay;
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Initializes a new instance of the <see cref="ChaosScenario"/> class.
/// </summary>
/// <param name="name">The scenario name.</param>
/// <param name="failureRate">The failure rate (from 0.0 to 1.0).</param>
/// <param name="delay">The delay (in milliseconds).</param>
public ChaosScenario(string name, double failureRate = 0, int delay = 0)
{
this.Name = name;
this.FailureRate = failureRate;
this.Delay = delay;
}
/// <summary>
/// Gets the scenario name.
/// </summary>
public string Name { get; private set; }
/// <summary>
/// Gets or sets the current failure rate for this scenario (from 0.0 to 1.0, 1.0 being 100% failure).
/// </summary>
public double FailureRate
{
get { return this.failureRate; }
set
{
if (value != this.failureRate)
{
if (value < 0 || value > 1.0)
{
throw new ArgumentOutOfRangeException("FailureRate", "Failure rate must be between 0.0 and 1.0");
}
this.failureRate = value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.FailureRate)));
}
}
}
/// <summary>
/// Gets or sets the current time delay, in milliseconds, for this scenario.
/// </summary>
public int Delay
{
get { return this.delay; }
set
{
if (value != this.delay)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException("Delay", "Delay must be greater or equal to 0.");
}
this.delay = value;
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(this.Delay)));
}
}
}
/// <summary>
/// Resets the failure rate and delay for this scenario back to 0.
/// </summary>
public void Reset()
{
this.FailureRate = 0;
this.Delay = 0;
}
public override string ToString()
{
return this.Name;
}
public static ICollection<ChaosScenario> LoadScenariosFromStaticFields(Type type)
{
var allFields = type.GetTypeInfo().DeclaredFields;
var scenarioFields = allFields.Where(f => f.IsPublic && f.IsStatic && f.FieldType == typeof(ChaosScenario));
var scenarios = scenarioFields.Select(f => f.GetValue(null)).OfType<ChaosScenario>().OrderBy(s => s.Name).ToList();
return scenarios;
}
}
}

Просмотреть файл

@ -0,0 +1,96 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics;
using System.Collections.Generic;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Collections
{
/// <summary>
/// Defines extension methods for collection types.
/// </summary>
public static class CollectionExtensions
{
/// <summary>
/// Adds the elements in another collection.
/// </summary>
/// <typeparam name="T">The type of elements in the collection.</typeparam>
/// <param name="collection">The collection.</param>
/// <param name="items">The items to add.</param>
public static void AddRange<T>(this ICollection<T> collection, IEnumerable<T> items)
{
Assert.ParamIsNotNull(collection, "collection");
Assert.ParamIsNotNull(items, "items");
foreach (var item in items)
{
collection.Add(item);
}
}
/// <summary>
/// Adds the elements in another collection.
/// </summary>
/// <param name="collection">The collection.</param>
/// <param name="items">The items to add.</param>
public static void AddRange(this System.Collections.IList collection, System.Collections.IEnumerable items)
{
Assert.ParamIsNotNull(collection, "collection");
Assert.ParamIsNotNull(items, "items");
foreach (var item in items)
{
collection.Add(item);
}
}
/// <summary>
/// Removes the elements in another collection.
/// </summary>
/// <typeparam name="T">The type of elements in the collection.</typeparam>
/// <param name="collection">The collection.</param>
/// <param name="items">The items to remove.</param>
public static void RemoveRange<T>(this ICollection<T> collection, IEnumerable<T> items)
{
Assert.ParamIsNotNull(collection, "collection");
Assert.ParamIsNotNull(items, "items");
foreach (var item in items)
{
collection.Remove(item);
}
}
/// <summary>
/// Removes the elements in another collection.
/// </summary>
/// <param name="collection">The collection.</param>
/// <param name="items">The items to remove.</param>
public static void RemoveRange(this System.Collections.IList collection, System.Collections.IEnumerable items)
{
Assert.ParamIsNotNull(collection, "collection");
Assert.ParamIsNotNull(items, "items");
foreach (var item in items)
{
collection.Remove(item);
}
}
/// <summary>
/// Attempts to get a value for a given key. If not present, returns the default value.
/// </summary>
/// <typeparam name="TKey">The type of the key.</typeparam>
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <param name="dict">The dictionary.</param>
/// <param name="key">The key.</param>
/// <returns>The looked up value, or if not found, the default value for the corresponding type.</returns>
public static TValue TryGetValueOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> dict, TKey key)
{
TValue value;
if (!dict.TryGetValue(key, out value))
{
value = default(TValue);
}
return value;
}
}
}

Просмотреть файл

@ -0,0 +1,61 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics;
using System.Collections.Generic;
using System.Collections.ObjectModel;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Collections
{
/// <summary>
/// Provides utility methods for collections.
/// </summary>
public static class CollectionUtilities
{
/// <summary>
/// Adds an item to a list in MRU fashion, keeping the number of items in the list under
/// a maximum limit.
/// </summary>
/// <typeparam name="T">The type of elements in the collection.</typeparam>
/// <param name="list">The list.</param>
/// <param name="item">The item to add.</param>
/// <param name="maxItems">The maximum items to keep in the list.</param>
/// <returns><c>true</c> if changes to the list were made, otherwise <c>false</c>.</returns>
public static bool AddToMruList<T>(this IList<T> list, T item, int maxItems)
{
Assert.ParamIsNotNull(list, "list");
Assert.ParamIsNotNull(item, "item");
Assert.ParamIsNotNegative(maxItems, "maxItems");
int originalIndex = list.IndexOf(item);
if (originalIndex == 0)
{
// Item is already at the front, no changes required
}
else if (originalIndex == -1)
{
// Item is not in the list, add it to the front and trim
list.Insert(0, item);
while (list.Count > maxItems)
{
list.RemoveAt(list.Count - 1);
}
}
else
{
// Item is in the list, it just needs to be moved to the front
ObservableCollection<T> observable = list as ObservableCollection<T>;
if (observable != null)
{
// Optimization for observable collection, to avoid firing multiple events.
observable.Move(originalIndex, 0);
}
else
{
list.RemoveAt(originalIndex);
list.Insert(0, item);
}
}
bool neededModifications = (originalIndex != 0);
return neededModifications;
}
}
}

Просмотреть файл

@ -0,0 +1,24 @@
namespace Microsoft.Internal.Tools.TeamMate.Foundation.CommandLine
{
public abstract class CommandBase : ICommand
{
protected CommandBase()
{
}
protected void Initialize(string name, string description, string usage)
{
this.CommandName = name;
this.CommandDescription = description;
this.CommandUsage = usage;
}
public string CommandName { get; private set; }
public string CommandDescription { get; private set; }
public string CommandUsage { get; private set; }
public abstract void Run(string[] args);
}
}

Просмотреть файл

@ -0,0 +1,40 @@
using System;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.CommandLine
{
/// <summary>
/// An exception class that indicates an error condition when parsing command line arguments.
/// </summary>
public class CommandLineArgumentException : Exception
{
/// <summary>
/// Initializes a new instance of this exception.
/// </summary>
public CommandLineArgumentException()
{
}
/// <summary>
/// Initializes a new instance of the this exception class with a specified
/// error message.
/// </summary>
/// <param name="message">The message that describes the error.</param>
public CommandLineArgumentException(string message)
: base(message)
{
}
/// <summary>
/// Initializes a new instance of the System.Exception class with a specified
/// error message and a reference to the inner exception that is the cause of
/// this exception.
/// </summary>
/// <param name="message">The error message that explains the reason for the exception.</param>
/// <param name="innerException">The exception that is the cause of the current exception,
/// or a <c>null</c> reference (Nothing in Visual Basic) if no inner exception is specified.</param>
public CommandLineArgumentException(string message, Exception innerException)
: base(message, innerException)
{
}
}
}

Просмотреть файл

@ -0,0 +1,199 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.CommandLine
{
/// <summary>
/// A helper class to parse command-lines.
/// </summary>
public class CommandLineArgumentParser
{
private static readonly ICollection<string> EmptyArray = new string[0];
private ICollection<string> validOptions = EmptyArray;
private ICollection<string> validMultiValueOptions = EmptyArray;
private ICollection<string> validSwitches = EmptyArray;
private IDictionary<string, IList<string>> arguments = new Dictionary<string, IList<string>>();
/// <summary>
/// Initializes a new instance of the <see cref="CommandLineArgumentParser"/> class.
/// </summary>
public CommandLineArgumentParser()
{
}
public ICollection<string> ValidOptions
{
get { return this.validOptions; }
set { this.validOptions = value ?? EmptyArray; }
}
public ICollection<string> ValidSwitches
{
get { return this.validSwitches; }
set { this.validSwitches = value ?? EmptyArray; }
}
public ICollection<string> ValidMultiValueOptions
{
get { return this.validMultiValueOptions; }
set { this.validMultiValueOptions = value ?? EmptyArray; }
}
/// <summary>
/// Gets a value indicating whether this instance has any arguments.
/// </summary>
public bool HasArguments
{
get { return arguments.Any(); }
}
/// <summary>
/// Determines whether a given switch was specified.
/// </summary>
public bool HasSwitch(string name)
{
return arguments.Keys.Contains(name);
}
/// <summary>
/// Gets the value for a given argument. Returns <c>null</c> if the argument was not defined.
/// </summary>
public string GetValue(string name)
{
IList<string> values = GetValues(name);
return values.FirstOrDefault();
}
/// <summary>
/// Gets the multiple available values for a given argument.
/// </summary>
public IList<string> GetValues(string name)
{
IList<string> values;
arguments.TryGetValue(name, out values);
return (values != null) ? values : new string[0];
}
/// <summary>
/// Gets the value for a given argument. Throws an exception if the argument was not defined.
/// </summary>
public string GetRequiredValue(string name)
{
string value = GetValue(name);
if (String.IsNullOrEmpty(value))
{
throw new CommandLineArgumentException(String.Format("Please specify a value for required option '{0}'.", name));
}
return value;
}
/// <summary>
/// Gets an input argument as a required value that needs to be an existing file.
/// </summary>
/// <param name="name">The name.</param>
/// <returns>The validated input file.</returns>
public string GetRequiredFile(string name)
{
string value = GetRequiredValue(name);
if (!File.Exists(value))
{
throw new CommandLineArgumentException(String.Format("File {0} does not exist", value));
}
return value;
}
/// <summary>
/// Gets the URI for a given argument. Returns <c>null</c> if the argument was not defined.
/// </summary>
public Uri GetUri(string name)
{
Uri result = null;
string value = GetValue(name);
if (value != null)
{
if (!Uri.TryCreate(value, UriKind.Absolute, out result))
{
throw new CommandLineArgumentException(value + " is not a valid absolute URL");
}
}
return result;
}
/// <summary>
/// Gets the filename for a given argument. Returns <c>null</c> if the argument was not defined.
/// </summary>
public string GetExistingFile(string name)
{
string filename = GetValue(name);
if (filename != null)
{
if (!File.Exists(filename))
{
throw new CommandLineArgumentException("Could not find file " + filename);
}
}
return filename;
}
/// <summary>
/// Parses the command-line arguments into a dictionary.
/// </summary>
/// <param name="args">The command-line arguments.</param>
public void Parse(IEnumerable<string> args)
{
arguments.Clear();
Regex regex = new Regex("/([^:]+)(?::(.*))?");
foreach (var arg in args)
{
Match match = regex.Match(arg);
if (match.Success)
{
string argName = match.Groups[1].Value;
string value = (match.Groups.Count >= 2) ? match.Groups[2].Value : String.Empty;
bool isSwitch = validSwitches != null && validSwitches.Contains(argName);
bool isOption = validOptions != null && validOptions.Contains(argName);
bool isMultiValueOpton = validMultiValueOptions != null && validMultiValueOptions.Contains(argName);
if (!isSwitch && !isOption && !isMultiValueOpton)
{
throw new CommandLineArgumentException("Unrecognized option " + arg);
}
if ((isOption || isMultiValueOpton) && String.IsNullOrEmpty(value))
{
throw new CommandLineArgumentException("Please specify a value for the " + argName + " option");
}
if ((isSwitch || isOption) && arguments.Keys.Contains(argName))
{
throw new CommandLineArgumentException("Argument " + argName + " was specified more than once");
}
IList<string> values;
if (!arguments.TryGetValue(argName, out values))
{
values = new List<string>();
arguments[argName] = values;
}
values.Add(value);
}
else
{
throw new CommandLineArgumentException("Unexpected argument " + arg);
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,160 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.CommandLine
{
public class CommandLineTool
{
private IDictionary<string, ICommand> commands = new Dictionary<string, ICommand>();
public string Description { get; set; }
public void RegisterCommandsInNamespace(Type typeInNamespace)
{
string nsName = typeInNamespace.Namespace;
var typesInNamespace = typeInNamespace.Assembly.GetTypes().Where(t => t.Namespace == nsName).ToArray();
var commandTypes = typesInNamespace.Where(t => typeof(ICommand).IsAssignableFrom(t)).ToArray();
foreach (var commandType in commandTypes)
{
var command = (ICommand)Activator.CreateInstance(commandType);
RegisterCommand(command);
}
}
public void RegisterCommand(ICommand command)
{
if (command.CommandName == null)
{
throw new ArgumentException(String.Format("Cannot register a command with a null name. Command type was {0}", command.GetType().FullName), "command");
}
ICommand existingCommand;
if (this.commands.TryGetValue(command.CommandName, out existingCommand))
{
throw new InvalidOperationException(string.Format("A command with the name {0} already exists. Command type is {1}",
command.CommandName, existingCommand.GetType().Name));
}
this.commands[command.CommandName] = command;
}
public void Run(string[] args)
{
string commandName = args.FirstOrDefault();
string[] commandArgs = args.Skip(1).ToArray();
if (commandName == null
|| commandName == "/?"
|| commandName == "-?"
|| (commandName == "help" && commandArgs.Length == 0))
{
Console.Write(GetHelp());
return;
}
if (commandName == "help")
{
string helpCommandName = commandArgs.First();
ICommand helpCommand = GetCommand(helpCommandName);
Console.WriteLine(GetCommandHelp(helpCommand));
return;
}
ICommand command = GetCommand(commandName);
command.Run(commandArgs);
}
private ICommand GetCommand(string commandName)
{
ICommand command;
if (!commands.TryGetValue(commandName, out command))
{
throw new InvalidOperationException(string.Format("Unrecognized command: {0}.", commandName));
}
return command;
}
private string GetHelp()
{
StringBuilder sb = new StringBuilder();
AppendDescription(sb);
string processName = GetProcessName();
int maxCommandNameLength = commands.Values.Select(c => c.CommandName.Length).Max();
int helpLinePaddingLength = processName.Length + 1 + maxCommandNameLength + 2;
string helpLinePadding = GetPadding(helpLinePaddingLength);
foreach (var command in commands.Values.OrderBy(c => c.CommandName))
{
string padding = GetPadding(maxCommandNameLength - command.CommandName.Length);
var description = String.Join('\n' + helpLinePadding, command.CommandDescription.Trim().Split('\n'));
sb.AppendFormat("{0} {1}{2} {3}", processName, command.CommandName, padding, description);
sb.AppendLine();
sb.AppendLine();
}
return sb.ToString();
}
public static string GetProcessName()
{
return Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().MainModule.ModuleName);
}
/// <summary>
/// Gets the current program version.
/// </summary>
public static string GetProcessVersion()
{
var assembly = Assembly.GetEntryAssembly();
AssemblyFileVersionAttribute fileVersion = assembly.GetCustomAttribute<AssemblyFileVersionAttribute>();
if (fileVersion != null)
{
return fileVersion.Version;
}
// Fall back to assembly version if a file version is not available...
return new AssemblyName(assembly.FullName).Version.ToString();
}
private void AppendDescription(StringBuilder sb)
{
if (this.Description != null)
{
var description = this.Description.Trim();
if (!String.IsNullOrWhiteSpace(description))
{
sb.AppendLine(description);
sb.AppendLine();
}
}
}
private string GetCommandHelp(ICommand helpCommand)
{
StringBuilder sb = new StringBuilder();
AppendDescription(sb);
sb.AppendLine(helpCommand.CommandDescription.Trim());
sb.AppendLine();
sb.AppendLine(helpCommand.CommandUsage.Trim());
sb.AppendLine();
string commandHelp = sb.ToString();
return commandHelp;
}
private static string GetPadding(int paddingLength)
{
return new StringBuilder(paddingLength).Append(' ', paddingLength).ToString();
}
}
}

Просмотреть файл

@ -0,0 +1,13 @@
namespace Microsoft.Internal.Tools.TeamMate.Foundation.CommandLine
{
public interface ICommand
{
string CommandName { get; }
string CommandDescription { get; }
string CommandUsage { get; }
void Run(string[] args);
}
}

Просмотреть файл

@ -0,0 +1,64 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics;
using System.ComponentModel;
using System.Linq;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.ComponentModel
{
/// <summary>
/// Provides extension methods for types in the ComponentModel namespace.
/// </summary>
public static class ComponentModelExtensions
{
/// <summary>
/// Gets the count of items in a collection view.
/// </summary>
/// <param name="collectionView">The collection view.</param>
/// <returns>The number of items in the collection view.</returns>
public static int GetCount(this ICollectionView collectionView)
{
Assert.ParamIsNotNull(collectionView, "collectionView");
var collection = collectionView.SourceCollection as System.Collections.ICollection;
if (collection != null)
{
// If the source collection is a collection (most likely the case), optimize to get the count directly
return collection.Count;
}
else
{
var enumerable = collectionView.SourceCollection;
if (enumerable != null)
{
return enumerable.OfType<object>().Count();
}
}
return 0;
}
/// <summary>
/// Determines whether the current item is in the first position of the collection.
/// </summary>
/// <param name="collectionView">The collection view.</param>
/// <returns><c>true</c> if the current item is in the first position, otherwise <c>false</c>.</returns>
public static bool IsCurrentFirst(this ICollectionView collectionView)
{
Assert.ParamIsNotNull(collectionView, "collectionView");
return collectionView.CurrentPosition == 0;
}
/// <summary>
/// Determines whether the current item is in the last position of the collection.
/// </summary>
/// <param name="collectionView">The collection view.</param>
/// <returns><c>true</c> if the current item is in the last position, otherwise <c>false</c>.</returns>
public static bool IsCurrentLast(this ICollectionView collectionView)
{
Assert.ParamIsNotNull(collectionView, "collectionView");
int count = collectionView.GetCount();
return count > 0 && collectionView.CurrentPosition == count - 1;
}
}
}

Просмотреть файл

@ -0,0 +1,124 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics;
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.ComponentModel
{
/// <summary>
/// A base class for observable objects that fire property notification changes.
/// </summary>
public abstract class ObservableObjectBase : INotifyPropertyChanged
{
/// <summary>
/// Occurs when a property value changes.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raises PropertyChanged event. This method can only be called on the thread associated with this object's dispatcher.
/// </summary>
/// <param name="propertyName">The name of the property that changed.</param>
/// <exception cref="System.InvalidOperationException">The calling thread does not have access to this object.</exception>
protected virtual void OnPropertyChanged(string propertyName)
{
Assert.ParamIsNotNull(propertyName, "propertyName");
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
/// <summary>
/// A helper method that sets property value and raises PropertyChanged event if the value has changed.
/// </summary>
/// <typeparam name="T">The type of the property being set.</typeparam>
/// <param name="propertyDataField">A reference to the data member which is used to store property value.</param>
/// <param name="value">New property value.</param>
/// <param name="propertyName">The name of the property.</param>
/// <returns>
/// True if the property value has changed, false otherwise.
/// </returns>
[MethodImpl(MethodImplOptions.NoInlining)]
protected bool SetProperty<T>(ref T propertyDataField, T value, [CallerMemberName] string propertyName = null)
{
Assert.ParamIsNotNullOrEmpty(propertyName, "propertyName");
if (!Object.Equals(propertyDataField, value))
{
propertyDataField = value;
OnPropertyChanged(propertyName);
return true;
}
return false;
}
/// <summary>
/// A helper method that sets property value and raises PropertyChanged event if the value has changed.
/// Optimized implementation for string type.
/// </summary>
/// <param name="field">A reference to the data member which is used to store property value.</param>
/// <param name="value">New property value.</param>
/// <param name="propertyName">The name of the property.</param>
/// <returns>True if the property value has changed, false otherwise.</returns>
[MethodImpl(MethodImplOptions.NoInlining)]
protected bool SetProperty(ref string field, string value, [CallerMemberName] string propertyName = null)
{
Assert.ParamIsNotNullOrEmpty(propertyName, "propertyName");
if (!string.Equals(field, value, StringComparison.Ordinal))
{
field = value;
OnPropertyChanged(propertyName);
return true;
}
return false;
}
/// <summary>
/// A helper method that sets property value and raises PropertyChanged event if the value has changed.
/// Optimized implementation for System.Int32 type.
/// </summary>
/// <param name="field">A reference to the data member which is used to store property value.</param>
/// <param name="value">New property value.</param>
/// <param name="propertyName">The name of the property.</param>
/// <returns>True if the property value has changed, false otherwise.</returns>
[MethodImpl(MethodImplOptions.NoInlining)]
protected bool SetProperty(ref int field, int value, [CallerMemberName] string propertyName = null)
{
Assert.ParamIsNotNullOrEmpty(propertyName, "propertyName");
if (field != value)
{
field = value;
OnPropertyChanged(propertyName);
return true;
}
return false;
}
/// <summary>
/// A helper method that sets property value and raises PropertyChanged event if the value has changed.
/// Optimized implementation for System.Boolean type.
/// </summary>
/// <param name="field">A reference to the data member which is used to store property value.</param>
/// <param name="value">New property value.</param>
/// <param name="propertyName">The name of the property.</param>
/// <returns>True if the property value has changed, false otherwise.</returns>
[MethodImpl(MethodImplOptions.NoInlining)]
protected bool SetProperty(ref bool field, bool value, [CallerMemberName] string propertyName = null)
{
Assert.ParamIsNotNullOrEmpty(propertyName, "propertyName");
if (field != value)
{
field = value;
OnPropertyChanged(propertyName);
return true;
}
return false;
}
}
}

Просмотреть файл

@ -0,0 +1,51 @@
using System;
namespace Microsoft.Internal.Tools.TeamMate.Foundation
{
/// <summary>
/// Provides utility methods for outputting to the console.
/// </summary>
public static class ConsoleUtilities
{
/// <summary>
/// Writes a line to the console using the given foreground color.
/// </summary>
/// <param name="foregroundColor">Color of the foreground.</param>
/// <param name="format">The format.</param>
/// <param name="args">The arguments.</param>
public static void WriteLine(ConsoleColor foregroundColor, string format, params object[] args)
{
ConsoleColor originalColor = Console.ForegroundColor;
try
{
Console.ForegroundColor = foregroundColor;
Console.WriteLine(format, args);
}
finally
{
Console.ForegroundColor = originalColor;
}
}
/// <summary>
/// Writes a line to the console using the default color for warnings (yellow).
/// </summary>
/// <param name="format">The format.</param>
/// <param name="args">The arguments.</param>
public static void WriteWarning(string format, params object[] args)
{
WriteLine(ConsoleColor.Yellow, format, args);
}
/// <summary>
/// Writes a line to the console using the default color for errors (red).
/// </summary>
/// <param name="format">The format.</param>
/// <param name="args">The arguments.</param>
public static void WriteError(string format, params object[] args)
{
WriteLine(ConsoleColor.Red, format, args);
}
}
}

Просмотреть файл

@ -0,0 +1,35 @@
using System;
namespace Microsoft.Internal.Tools.TeamMate.Foundation
{
/// <summary>
/// Provides utility methods for converting types.
/// </summary>
public static class ConvertUtilities
{
/// <summary>
/// Changes an input value to the target type.
/// </summary>
/// <typeparam name="T">The target type.</typeparam>
/// <param name="value">The value.</param>
/// <returns>The converted type.</returns>
public static T ChangeType<T>(object value)
{
Type targetType = typeof(T);
object result = null;
// In the future, add more types here (e.g. Version, TimeSpan, DateTime, etc...)
if (targetType == typeof(Uri) && value is string)
{
result = new Uri((string)value);
}
if (result == null)
{
result = Convert.ChangeType(value, targetType);
}
return (T)result;
}
}
}

Просмотреть файл

@ -0,0 +1,228 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Resources;
using System;
using System.Globalization;
namespace Microsoft.Internal.Tools.TeamMate.Foundation
{
/// <summary>
/// Provides utility methods for working with date times.
/// </summary>
public static class DateTimeExtensions
{
private static string[] Numbers = {
"Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"
};
/// <summary>
/// Determines whether the specified date is after another date.
/// </summary>
/// <param name="date">The date.</param>
/// <param name="other">The other.</param>
/// <returns><c>true</c> if a date was after the other date.</returns>
public static bool IsAfter(this DateTime date, DateTime? other)
{
// Very important to make sure both dates are in the same space, otherwise the comparison gives you bogus values
return other == null || other.Value.ToUniversalTime() < date.ToUniversalTime();
}
/// <summary>
/// Determines whether the specified date is between (inclusive) two dates.
/// </summary>
/// <param name="date">The date.</param>
/// <param name="start">The start date.</param>
/// <param name="end">The end date.</param>
/// <returns></returns>
public static bool IsBetween(this DateTime date, DateTime start, DateTime end)
{
return start <= date && date <= end;
}
/// <summary>
/// Returns a string to describe the time interval between this date and the current time.
/// E.g. "3 minutes", or "11 seconds".
/// </summary>
/// <param name="date">The date.</param>
public static string ToFriendlyElapsedTimeString(this DateTime date)
{
TimeSpan difference = (DateTime.UtcNow - date.ToUniversalTime());
// TODO: Assert is positive difference or handle future date?
return difference.ToFriendlyString();
}
/// <summary>
/// Returns a string to describe the time interval between this date and the current time, with the "ago" word.
/// E.g. "3 minutes ago", or "11 seconds ago".
/// </summary>
/// <param name="date">The date.</param>
public static string ToFriendlyElapsedTimeStringWithAgo(this DateTime date)
{
string result = date.ToFriendlyElapsedTimeString();
return String.Format(ResourceStrings.Ago, result);
}
/// <summary>
/// Returns a short date string that represents this date. The string format depends on the
/// the time difference with now (e.g. "3 minutes ago", "Today at 3:00PM", "Yesterday at 11:00AM",
/// or "on Monday 10/16/2014");
/// </summary>
/// <param name="date">The date.</param>
public static string ToFriendlyShortDateString(this DateTime date)
{
return date.ToFriendlyDateString(false);
}
/// <summary>
/// Returns a date string that represents this date. The string format depends on the
/// the time difference with now (e.g. "3 minutes ago", "Today at 3:00PM", "Yesterday at 11:00AM",
/// or "on Monday 10/16/2014");
/// </summary>
/// <param name="date">The date.</param>
public static string ToFriendlyLongDateString(this DateTime date)
{
return date.ToFriendlyDateString(true);
}
/// <summary>
/// Returns a string that represents the date in cormparison to the current time, only taking into
/// account the date component (eg. "Today", "Yesterday", "Monday", "Last Week", "3 Weeks Ago", "Last Month",
/// "Older", "Newer").
/// </summary>
/// <param name="date">The date.</param>
/// <remarks>
/// Based on Outlook's date grouping for conversations.
/// </remarks>
public static string ToFriendlyDatePeriod(this DateTime date)
{
DateTime today = DateTime.Today;
TimeSpan difference = today - date.ToLocalTime().Date;
if (difference >= TimeSpan.Zero)
{
if (difference.TotalDays < 1)
{
return "Today";
}
if (difference.TotalDays < 2)
{
return "Yesterday";
}
int weeksDifference = today.WeeksDifference(date);
if (weeksDifference == 0)
{
// A day in this week
return date.ToString("dddd");
}
if (weeksDifference > 0 && weeksDifference <= 3 && weeksDifference < Numbers.Length)
{
// A previous week in this month
return (weeksDifference == 1) ? "Last Week" : String.Format("{0} Weeks Ago", Numbers[weeksDifference]);
}
int monthsDifference = today.MonthsDifference(date);
if (monthsDifference == 1)
{
return "Last Month";
}
return "Older";
}
else
{
return "Newer";
}
}
/// <summary>
/// Returns a short date string that represents this date. The string format depends on the
/// the time difference with now (e.g. "3 minutes ago", "Today at 3:00PM", "Yesterday at 11:00AM",
/// or "on Monday 10/16/2014");
/// </summary>
/// <param name="date">The date.</param>
private static string ToFriendlyDateString(this DateTime date, bool longDate)
{
// Make sure the date is in local time
date = date.ToLocalTime();
DateTime now = DateTime.Now;
TimeSpan timeDifference = (now - date);
// TODO: Assert is positive difference or handle future date?
if (timeDifference.TotalHours < 7)
{
string result = timeDifference.ToFriendlyString();
return String.Format(ResourceStrings.Ago, result);
}
else if (date.Date == now.Date)
{
string time = date.ToShortTimeString();
return String.Format(ResourceStrings.TimeStampTodayAt, time);
}
else if ((date + TimeSpan.FromDays(1)).Date == now.Date)
{
string time = date.ToShortTimeString();
return String.Format(ResourceStrings.TimeStampYesterdayAt, time);
}
else
{
if (longDate)
{
if (timeDifference.TotalDays <= 5)
{
string day = date.ToString("dddd", CultureInfo.CurrentCulture);
string time = date.ToShortTimeString();
return String.Format(ResourceStrings.TimeStampDayAt, day, time);
}
else
{
string day = date.ToString("ddd", CultureInfo.CurrentCulture);
string time = date.ToString("g", CultureInfo.CurrentCulture);
return String.Format(ResourceStrings.TimeStampFullDate, day, time);
}
}
else
{
string day = date.ToString("ddd", CultureInfo.CurrentCulture);
string fullDate = String.Format(ResourceStrings.DayAndDate, day, date.ToShortDateString());
return String.Format(ResourceStrings.OnDate, fullDate);
}
}
}
/// <summary>
/// Gets the number of months between two dates.
/// </summary>
/// <param name="date">The date.</param>
/// <param name="otherDate">The other date.</param>
/// <returns>The number of months between the two dates (negative if otherDate is later than this date).</returns>
private static int MonthsDifference(this DateTime date, DateTime otherDate)
{
var diff = (date.Year - otherDate.Year) * 12 + (date.Month - otherDate.Month);
return diff;
}
/// <summary>
/// Gets the number of weeks between two dates.
/// </summary>
/// <param name="date">The date.</param>
/// <param name="otherDate">The other date.</param>
/// <returns>The number of weeks between the two dates (negative if otherDate is later than this date).</returns>
private static int WeeksDifference(this DateTime date, DateTime otherDate)
{
var culture = CultureInfo.CurrentCulture;
var calendarWeekRule = CalendarWeekRule.FirstDay;
var firstDayOfWeek = culture.DateTimeFormat.FirstDayOfWeek;
int week1 = culture.Calendar.GetWeekOfYear(date, calendarWeekRule, firstDayOfWeek);
int week2 = culture.Calendar.GetWeekOfYear(otherDate, calendarWeekRule, firstDayOfWeek);
var diff = (date.Year - otherDate.Year) * 52 + (week1 - week2);
return diff;
}
}
}

Просмотреть файл

@ -0,0 +1,83 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics;
using System;
namespace Microsoft.Internal.Tools.TeamMate.Foundation
{
public class DeferredAction : IDisposable
{
private object sempahoreCountLock = new object();
private int semaphoreCount;
public DeferredAction(Action action)
{
Assert.ParamIsNotNull(action, "action");
this.Action = action;
}
public bool IsDeferring
{
get
{
return this.semaphoreCount > 0;
}
}
public Action Action { get; private set; }
public void InvokeIfNotDeferred()
{
if (this.ShouldInvoke())
{
this.Invoke();
}
}
public IDisposable Acquire()
{
lock (this.sempahoreCountLock)
{
this.semaphoreCount++;
}
return this;
}
private void Release()
{
bool shouldInvoke = false;
lock (this.sempahoreCountLock)
{
if (this.semaphoreCount > 0)
{
this.semaphoreCount--;
shouldInvoke = this.ShouldInvoke();
}
}
if (shouldInvoke)
{
Invoke();
}
}
private void Invoke()
{
this.Action.Invoke();
}
private bool ShouldInvoke()
{
lock (sempahoreCountLock)
{
return (this.semaphoreCount == 0);
}
}
void IDisposable.Dispose()
{
this.Release();
}
}
}

Просмотреть файл

@ -0,0 +1,35 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics;
using System;
namespace Microsoft.Internal.Tools.TeamMate.Foundation
{
/// <summary>
/// A helper class to implement disposable patterns for API usability to execute
/// an action when Dispose() is called.
/// </summary>
public class DelegateDisposable : IDisposable
{
private Action disposeAction;
private bool isDisposed;
/// <summary>
/// Initializes a new instance of the <see cref="DelegateDisposable"/> class.
/// </summary>
/// <param name="action">The action to be invoked on dispose.</param>
public DelegateDisposable(Action action)
{
Assert.ParamIsNotNull(action, "disposeAction");
this.disposeAction = action;
}
public void Dispose()
{
if(!isDisposed)
{
isDisposed = true;
disposeAction();
}
}
}
}

Просмотреть файл

@ -0,0 +1,162 @@
using System;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics
{
/// <summary>
/// A helper static class used to assert common conditions.
/// </summary>
public static class Assert
{
/// <summary>
/// Asserts that a given parameter value satisfies an arbitrary assertion.
/// </summary>
/// <param name="assertion">If false, then an argument exception will be thrown.</param>
/// <param name="paramName">The parameter name.</param>
/// <param name="message">The message to throw as part of the assertion.</param>
public static void ParamIs(bool assertion, string paramName, string message)
{
if (!assertion)
{
throw new ArgumentException(message, paramName);
}
}
/// <summary>
/// Asserts that a given parameter value is not <c>null</c>.
/// </summary>
/// <param name="value">The parameter value.</param>
/// <param name="paramName">The parameter name.</param>
public static void ParamIsNotNull(object value, string paramName)
{
if (value == null)
{
throw new ArgumentNullException(paramName);
}
}
/// <summary>
/// Asserts that a given string parameter value is not <c>null</c> or empty.
/// </summary>
/// <param name="value">The parameter value.</param>
/// <param name="paramName">The parameter name.</param>
public static void ParamIsNotNullOrEmpty(string value, string paramName)
{
if (value == null)
{
throw new ArgumentNullException(paramName);
}
if (String.IsNullOrEmpty(value))
{
throw new ArgumentException("String parameter cannot be empty", paramName);
}
}
/// <summary>
/// Asserts that a given parameter is equal to or greater than 0.
/// </summary>
/// <param name="value">The parameter value.</param>
/// <param name="paramName">The parameter name.</param>
public static void ParamIsNotNegative(int value, string paramName)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(paramName, value, "Parameter must be equal to or greater than 0");
}
}
/// <summary>
/// Asserts that a given parameter is equal to or greater than 0.
/// </summary>
/// <param name="value">The parameter value.</param>
/// <param name="paramName">The parameter name.</param>
public static void ParamIsNotNegative(long value, string paramName)
{
if (value < 0)
{
throw new ArgumentOutOfRangeException(paramName, value, "Parameter must be equal to or greater than 0");
}
}
/// <summary>
/// Asserts that a given parameter is equal to or greater than 0.
/// </summary>
/// <param name="value">The parameter value.</param>
/// <param name="paramName">The parameter name.</param>
public static void ParamIsNotNegative(TimeSpan value, string paramName)
{
if (value < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(paramName, value, "TimeSpan must be equal to or greater than 0");
}
}
/// <summary>
/// Asserts that a given parameter is greater than 0.
/// </summary>
/// <param name="value">The parameter value.</param>
/// <param name="paramName">The parameter name.</param>
public static void ParamIsGreaterThanZero(int value, string paramName)
{
if (value <= 0)
{
throw new ArgumentOutOfRangeException(paramName, value, "Parameter must greater than 0");
}
}
/// <summary>
/// Asserts that a given parameter is greater than 0.
/// </summary>
/// <param name="value">The parameter value.</param>
/// <param name="paramName">The parameter name.</param>
public static void ParamIsGreaterThanZero(TimeSpan value, string paramName)
{
if (value <= TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(paramName, value, "TimeSpan must greater than 0");
}
}
/// <summary>
/// Asserts that a given parameter is greater than 0.
/// </summary>
/// <param name="value">The parameter value.</param>
/// <param name="paramName">The parameter name.</param>
public static void ParamIsGreaterThanZero(double value, string paramName)
{
if (value <= 0)
{
throw new ArgumentOutOfRangeException(paramName, value, "Value must greater than 0");
}
}
/// <summary>
/// Asserts that a given parameter is within a range (inclusive of the low and high bounds).
/// </summary>
/// <param name="value">The parameter value.</param>
/// <param name="lowBound">The low bound.</param>
/// <param name="highBound">The high bound.</param>
/// <param name="paramName">The parameter name.</param>
public static void ParamIsWithinRange(double value, double lowBound, double highBound, string paramName)
{
if (value < lowBound || value > highBound)
{
throw new ArgumentOutOfRangeException(paramName, value, "Parameter must be a value between " + lowBound + " and " + highBound);
}
}
/// <summary>
/// Asserts that a given parameter is a valid index for a given count or length of collection.
/// </summary>
/// <param name="value">The parameter value.</param>
/// <param name="count">The maximum count.</param>
/// <param name="paramName">The parameter name.</param>
public static void ParamIsValidIndex(int value, int count, string paramName)
{
if (value < 0 || value >= count)
{
throw new ArgumentOutOfRangeException(paramName, value, "Index was out of range. Must be non-negative and less than the size of the collection.");
}
}
}
}

Просмотреть файл

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics
{
/// <summary>
/// A helper class to build command line arguments for starting processes.
/// </summary>
/// <remarks>
/// This class takes care of escaping arguments as needed for argument values that
/// require escaping.
/// </remarks>
public class CommandLineBuilder
{
private static readonly char[] EscapeChars = new char[] { ' ', '\t', '\"' };
private List<string> args = new List<string>();
/// <summary>
/// Determines if an argument value requires escaping.
/// </summary>
/// <param name="value">The value.</param>
/// <returns><c>true</c> if it requires esaping, <c>false</c> if it can be used as is.</returns>
public static bool NeedsEscaping(string value)
{
return value.IndexOfAny(EscapeChars) >= 0;
}
/// <summary>
/// Adds an argument.
/// </summary>
/// <param name="arg">The argument.</param>
public void Add(string arg)
{
this.args.Add(arg);
}
/// <summary>
/// Adds one or more arguments.
/// </summary>
/// <param name="args">The arguments.</param>
public void Add(params string[] args)
{
this.args.AddRange(args);
}
/// <summary>
/// Adds one or more arguments.
/// </summary>
/// <param name="args">The arguments.</param>
public void Add(IEnumerable<string> args)
{
this.args.AddRange(args);
}
/// <summary>
/// Adds two arguments, a switch name and a switch value (e.g. "/priority" "1"), if and only
/// if, the value is not empty.
/// </summary>
/// <param name="switchName">The switch name.</param>
/// <param name="switchValue">The switch value (possibly empty).</param>
public void AddSwitchIfNotNull(string switchName, string switchValue)
{
if (!String.IsNullOrWhiteSpace(switchValue))
{
Add(switchName, switchValue);
}
}
/// <summary>
/// Returns the escaped command line arguments as a single string.
/// </summary>
public override string ToString()
{
return String.Join(" ", args.Select(arg => EscapeArgument(arg)));
}
/// <summary>
/// Escapes an argument if required.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>The escaped value (or the original one if no escaping was required).</returns>
private static string EscapeArgument(string value)
{
bool needsEscaping = NeedsEscaping(value);
if (needsEscaping)
{
char escapeChar = (value.Contains('"')) ? '\'' : '\"';
return escapeChar + value + escapeChar;
}
return value;
}
}
}

Просмотреть файл

@ -0,0 +1,412 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Xml;
using System;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics
{
/// <summary>
/// Serializes & deserializes elements in the Diagnostics namespace to/from XML.
/// </summary>
public class DiagnosticsSerializer
{
/// <summary>
/// A special marker to indicate that an unknwon XML element was deserialized from a telemetry stream.
/// </summary>
public static readonly object UnknownElement = new object();
/// <summary>
/// Serializes the specified system information to a stream.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="stream">The stream.</param>
public void Serialize(SystemInfo info, Stream stream)
{
new XDocument(Serialize(info)).Save(stream);
}
/// <summary>
/// Serializes the specified exception information to a stream.
/// </summary>
/// <param name="info">The information.</param>
/// <param name="stream">The stream.</param>
public void Serialize(ExceptionInfo info, Stream stream)
{
new XDocument(Serialize(info)).Save(stream);
}
/// <summary>
/// Deserializes the event information.
/// </summary>
/// <param name="element">The XML element.</param>
/// <returns>The event information.</returns>
private EventInfo DeserializeEventInfo(XElement element)
{
string name = element.GetAttribute<string>(EventInfoSchema.Name);
DateTime time = element.GetAttribute<DateTime>(EventInfoSchema.Time);
TelemetryEventProperties eventProperties = null;
var properties = element.Element(EventInfoSchema.Properties);
if (properties != null)
{
eventProperties = new TelemetryEventProperties();
foreach (var property in properties.Elements(EventInfoSchema.Property))
{
string propertyName = property.GetAttribute<string>(EventInfoSchema.Name);
string propertyValue = property.GetAttribute<string>(EventInfoSchema.Value);
eventProperties[propertyName] = propertyValue;
}
}
return new EventInfo(time, name, eventProperties);
}
/// <summary>
/// Serializes the specified event information.
/// </summary>
/// <param name="info">The information.</param>
/// <returns>The XML element.</returns>
public XElement Serialize(EventInfo info)
{
XElement e = new XElement(EventInfoSchema.Event,
new XAttribute(EventInfoSchema.Name, info.Name),
new XAttribute(EventInfoSchema.Time, XmlExtensions.ToXmlString(info.Time))
);
var properties = info.Properties;
if (properties != null && properties.Any())
{
XElement propertiesElement = new XElement(EventInfoSchema.Properties);
foreach (var item in properties)
{
if (item.Value != null)
{
propertiesElement.Add(new XElement(EventInfoSchema.Property,
new XAttribute(EventInfoSchema.Name, item.Key),
new XAttribute(EventInfoSchema.Value, XmlExtensions.ToXmlString(item.Value))
));
}
}
e.Add(propertiesElement);
}
return e;
}
/// <summary>
/// Serializes the specified exception exception.
/// </summary>
/// <param name="exception">The exception information.</param>
/// <returns>The XML element.</returns>
public XElement Serialize(ExceptionInfo exception)
{
return Serialize(exception, ExceptionInfoSchema.Exception);
}
/// <summary>
/// Serializes the specified exception information to an element with a given element name.
/// </summary>
/// <param name="exception">The exception.</param>
/// <param name="name">The output element name.</param>
/// <returns>The XML element.</returns>
private XElement Serialize(ExceptionInfo exception, XName name)
{
XElement e = new XElement(name);
e.SetElementValue<string>(ExceptionInfoSchema.Source, exception.Source);
e.SetElementValue<string>(ExceptionInfoSchema.Type, exception.Type);
e.SetElementValue<string>(ExceptionInfoSchema.Message, exception.Message);
e.SetCDataElementValue(ExceptionInfoSchema.StackTrace, exception.StackTrace);
e.SetElementValue<int>(ExceptionInfoSchema.HResult, exception.HResult);
if (exception.InnerException != null)
{
e.Add(Serialize(exception.InnerException, ExceptionInfoSchema.InnerException));
}
e.SetCDataElementValue(ExceptionInfoSchema.FullText, exception.FullText);
return e;
}
/// <summary>
/// Serializes the specified system information.
/// </summary>
/// <param name="info">The information.</param>
/// <returns>The XML element.</returns>
public XElement Serialize(SystemInfo info)
{
var memory = info.Memory;
return new XElement(SystemInfoSchema.SystemInfo, new XAttribute(SystemInfoSchema.SchemaVersion, SystemInfoSchema.CurrentVersion),
new XElement(SystemInfoSchema.OSName, info.OSName),
new XElement(SystemInfoSchema.OSVersion, info.OSVersion),
new XElement(SystemInfoSchema.Is64BitOperatingSystem, info.Is64BitOperatingSystem),
new XElement(SystemInfoSchema.ClrVersion, info.ClrVersion),
new XElement(SystemInfoSchema.SystemCultureName, info.SystemCultureName),
new XElement(SystemInfoSchema.UserCultureName, info.UserCultureName),
new XElement(SystemInfoSchema.TimeZoneName, info.TimeZoneName),
new XElement(SystemInfoSchema.TimeZoneUtcOffset, XmlExtensions.ToXmlString(info.TimeZoneUtcOffset)),
new XElement(SystemInfoSchema.IsRemoteDesktopSession, info.IsRemoteDesktopSession),
new XElement(SystemInfoSchema.IsMultiTouchEnabled, info.IsMultiTouchEnabled),
new XElement(SystemInfoSchema.Memory,
new XElement(SystemInfoSchema.TotalPhysicalMemory, memory.TotalPhysicalMemory),
new XElement(SystemInfoSchema.AvailablePhysicalMemory, memory.AvailablePhysicalMemory),
new XElement(SystemInfoSchema.TotalVirtualMemory, memory.TotalVirtualMemory),
new XElement(SystemInfoSchema.AvailableVirtualMemory, memory.AvailableVirtualMemory),
new XElement(SystemInfoSchema.MemoryLoad, memory.MemoryLoad)
),
new XElement(SystemInfoSchema.Processors,
info.Processors.Select(processor => new XElement(SystemInfoSchema.Processor,
new XElement(SystemInfoSchema.Name, processor.Name),
new XElement(SystemInfoSchema.Family, processor.Family),
new XElement(SystemInfoSchema.NumberOfCores, processor.NumberOfCores),
new XElement(SystemInfoSchema.NumberOfLogicalProcessors, processor.NumberOfLogicalProcessors),
new XElement(SystemInfoSchema.MaxClockSpeed, processor.MaxClockSpeed)
))
),
new XElement(SystemInfoSchema.VirtualScreen,
new XElement(SystemInfoSchema.Width, info.VirtualScreen.Width),
new XElement(SystemInfoSchema.Height, info.VirtualScreen.Height)
),
new XElement(SystemInfoSchema.Screens,
info.Screens.Select(screen => new XElement(SystemInfoSchema.Screen,
new XElement(SystemInfoSchema.Width, screen.Width),
new XElement(SystemInfoSchema.Height, screen.Height),
new XElement(SystemInfoSchema.BitsPerPixel, screen.BitsPerPixel),
new XElement(SystemInfoSchema.IsPrimary, screen.IsPrimary)
))
),
new XElement(SystemInfoSchema.IEVersion, info.IEVersion),
new XElement(SystemInfoSchema.VisualStudioVersions,
info.VisualStudioVersions.Select(version => new XElement(SystemInfoSchema.VisualStudioVersion, version))
)
);
}
/// <summary>
/// Deserializes the exception information.
/// </summary>
/// <param name="element">The XML element.</param>
/// <returns>The exception information.</returns>
public ExceptionInfo DeserializeExceptionInfo(XElement element)
{
ExceptionInfo exception = new ExceptionInfo();
exception.Source = element.GetElementValue<string>(ExceptionInfoSchema.Source);
exception.Type = element.GetElementValue<string>(ExceptionInfoSchema.Type);
exception.Message = element.GetElementValue<string>(ExceptionInfoSchema.Message);
exception.StackTrace = element.GetElementValue<string>(ExceptionInfoSchema.StackTrace);
exception.HResult = element.GetElementValue<int>(ExceptionInfoSchema.HResult);
var innerExceptionElement = element.Element(ExceptionInfoSchema.InnerException);
if (innerExceptionElement != null)
{
exception.InnerException = DeserializeExceptionInfo(innerExceptionElement);
}
exception.FullText = element.GetElementValue<string>(ExceptionInfoSchema.FullText);
return exception;
}
/// <summary>
/// Deserializes an arbitrary telemetry object from an XML element. The result could be an event,
/// exception, application information, session information, or system information, or the unknown element.
/// </summary>
/// <param name="element">The element.</param>
/// <returns>A deserialized telemetry object, or the "Unknown" element if unrecognized.</returns>
public object DeserializeElement(XElement element)
{
// Ordered in descending order of expected frequency
if (element.Name == EventInfoSchema.Event)
{
return DeserializeEventInfo(element);
}
else if (element.Name == ExceptionInfoSchema.Exception)
{
return DeserializeExceptionInfo(element);
}
else if (element.Name == SystemInfoSchema.SystemInfo)
{
return DeserializeSystemInfo(element);
}
return UnknownElement;
}
/// <summary>
/// Deserializes the exception information.
/// </summary>
/// <param name="stream">The stream.</param>
/// <returns>The exception information.</returns>
public ExceptionInfo DeserializeExceptionInfo(Stream stream)
{
var doc = XDocument.Load(stream);
var root = doc.GetExpectedRoot(ExceptionInfoSchema.Exception);
return DeserializeExceptionInfo(root);
}
/// <summary>
/// Deserializes the system information.
/// </summary>
/// <param name="stream">The stream.</param>
/// <returns>The system information.</returns>
public SystemInfo DeserializeSystemInfo(Stream stream)
{
var doc = XDocument.Load(stream);
var root = doc.GetExpectedRoot(SystemInfoSchema.SystemInfo);
return DeserializeSystemInfo(root);
}
/// <summary>
/// Deserializes the system information.
/// </summary>
/// <param name="e">The XML element.</param>
/// <returns>The system information.</returns>
public SystemInfo DeserializeSystemInfo(XElement e)
{
SystemInfo systemInfo = new SystemInfo();
systemInfo.OSName = e.GetElementValue<string>(SystemInfoSchema.OSName);
systemInfo.OSVersion = e.GetElementValue<string>(SystemInfoSchema.OSName);
systemInfo.Is64BitOperatingSystem = e.GetElementValue<bool>(SystemInfoSchema.Is64BitOperatingSystem);
systemInfo.ClrVersion = e.GetElementValue<string>(SystemInfoSchema.ClrVersion);
systemInfo.SystemCultureName = e.GetElementValue<string>(SystemInfoSchema.SystemCultureName);
systemInfo.UserCultureName = e.GetElementValue<string>(SystemInfoSchema.UserCultureName);
systemInfo.TimeZoneName = e.GetElementValue<string>(SystemInfoSchema.TimeZoneName);
systemInfo.TimeZoneUtcOffset = e.GetElementValue<TimeSpan>(SystemInfoSchema.TimeZoneUtcOffset);
systemInfo.IsRemoteDesktopSession = e.GetElementValue<bool>(SystemInfoSchema.IsRemoteDesktopSession);
systemInfo.IsMultiTouchEnabled = e.GetElementValue<bool>(SystemInfoSchema.IsMultiTouchEnabled);
var memoryElement = e.Element(SystemInfoSchema.Memory);
MemoryInfo memory = new MemoryInfo();
memory.TotalPhysicalMemory = memoryElement.GetElementValue<long>(SystemInfoSchema.TotalPhysicalMemory);
memory.AvailablePhysicalMemory = memoryElement.GetElementValue<long>(SystemInfoSchema.AvailablePhysicalMemory);
memory.TotalVirtualMemory = memoryElement.GetElementValue<long>(SystemInfoSchema.TotalVirtualMemory);
memory.AvailableVirtualMemory = memoryElement.GetElementValue<long>(SystemInfoSchema.AvailableVirtualMemory);
memory.MemoryLoad = memoryElement.GetElementValue<int>(SystemInfoSchema.MemoryLoad);
systemInfo.Memory = memory;
var processors = e.Elements(SystemInfoSchema.Processors, SystemInfoSchema.Processor);
foreach (var processor in processors)
{
ProcessorInfo processorInfo = new ProcessorInfo();
processorInfo.Name = processor.GetElementValue<string>(SystemInfoSchema.Name);
processorInfo.Family = processor.GetElementValue<string>(SystemInfoSchema.Family);
processorInfo.NumberOfCores = processor.GetElementValue<int>(SystemInfoSchema.NumberOfCores);
processorInfo.NumberOfLogicalProcessors = processor.GetElementValue<int>(SystemInfoSchema.NumberOfLogicalProcessors);
processorInfo.MaxClockSpeed = processor.GetElementValue<int>(SystemInfoSchema.MaxClockSpeed);
systemInfo.Processors.Add(processorInfo);
}
var virtualScreenElement = e.Element(SystemInfoSchema.VirtualScreen);
VirtualScreenInfo virtualScreen = new VirtualScreenInfo()
{
Width = virtualScreenElement.GetElementValue<int>(SystemInfoSchema.Width),
Height = virtualScreenElement.GetElementValue<int>(SystemInfoSchema.Height)
};
systemInfo.VirtualScreen = virtualScreen;
var screens = e.Elements(SystemInfoSchema.Screens, SystemInfoSchema.Screen);
foreach (var screen in screens)
{
ScreenInfo screenInfo = new ScreenInfo();
screenInfo.Width = screen.GetElementValue<int>(SystemInfoSchema.Width);
screenInfo.Height = screen.GetElementValue<int>(SystemInfoSchema.Height);
screenInfo.BitsPerPixel = screen.GetElementValue<int>(SystemInfoSchema.BitsPerPixel);
screenInfo.IsPrimary = screen.GetElementValue<bool>(SystemInfoSchema.IsPrimary);
systemInfo.Screens.Add(screenInfo);
}
systemInfo.IEVersion = e.GetElementValue<string>(SystemInfoSchema.IEVersion);
var visualStudioVersions = e.Elements(SystemInfoSchema.VisualStudioVersions, SystemInfoSchema.VisualStudioVersion);
foreach (var version in visualStudioVersions)
{
systemInfo.VisualStudioVersions.Add(version.Value);
}
return systemInfo;
}
/// <summary>
/// Describes the XML schema for an EventInfo type.
/// </summary>
private static class EventInfoSchema
{
public static XName Event = "Event";
public static string Name = "Name";
public static string Time = "Time";
public static XName Properties = "Properties";
public static XName Property = "Property";
public static string Value = "Value";
}
/// <summary>
/// Describes the XML schema for an ExceptionInfo type.
/// </summary>
public static class ExceptionInfoSchema
{
public static readonly XName Exception = "Exception";
public static readonly XName Type = "Type";
public static readonly XName StackTrace = "StackTrace";
public static readonly XName Message = "Message";
public static readonly XName HResult = "HResult";
public static readonly XName Source = "Source";
public static readonly XName InnerException = "InnerException";
public static readonly XName FullText = "FullText";
}
/// <summary>
/// Describes the XML schema for a SystemInfo type.
/// </summary>
private static class SystemInfoSchema
{
public static readonly Version CurrentVersion = new Version("1.0");
public static readonly string SchemaVersion = "Version";
public static readonly XName SystemInfo = "SystemInfo";
public static readonly XName OSName = "OSName";
public static readonly XName OSVersion = "OSVersion";
public static readonly XName Is64BitOperatingSystem = "Is64BitOperatingSystem";
public static readonly XName ClrVersion = "ClrVersion";
public static readonly XName SystemCultureName = "SystemCultureName";
public static readonly XName UserCultureName = "UserCultureName";
public static readonly XName TimeZoneName = "TimeZoneName";
public static readonly XName TimeZoneUtcOffset = "TimeZoneUtcOffset";
public static readonly XName IsRemoteDesktopSession = "IsRemoteDesktopSession";
public static readonly XName IsMultiTouchEnabled = "IsMultiTouchEnabled";
public static readonly XName Memory = "Memory";
public static readonly XName TotalPhysicalMemory = "TotalPhysicalMemory";
public static readonly XName AvailablePhysicalMemory = "AvailablePhysicalMemory";
public static readonly XName TotalVirtualMemory = "TotalVirtualMemory";
public static readonly XName AvailableVirtualMemory = "AvailableVirtualMemory";
public static readonly XName MemoryLoad = "MemoryLoad";
public static readonly XName Processors = "Processors";
public static readonly XName Processor = "Processor";
public static readonly XName Name = "Name";
public static readonly XName Family = "Family";
public static readonly XName NumberOfCores = "NumberOfCores";
public static readonly XName NumberOfLogicalProcessors = "NumberOfLogicalProcessors";
public static readonly XName MaxClockSpeed = "MaxClockSpeed";
public static readonly XName VirtualScreen = "VirtualScreen";
public static readonly XName Width = "Width";
public static readonly XName Height = "Height";
public static readonly XName Screens = "Screens";
public static readonly XName Screen = "Screen";
public static readonly XName BitsPerPixel = "BitsPerPixel";
public static readonly XName IsPrimary = "IsPrimary";
public static readonly XName IEVersion = "IEVersion";
public static readonly XName VisualStudioVersions = "VisualStudioVersions";
public static readonly XName VisualStudioVersion = "VisualStudioVersion";
}
}
}

Просмотреть файл

@ -0,0 +1,41 @@
using System;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics
{
/// <summary>
/// Representts telemetry information for a given "event" in an application. An event has a name,
/// an occurrence timestamp, and an optional set of properties.
/// </summary>
public class EventInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="EventInfo"/> class.
/// </summary>
/// <param name="time">The time.</param>
/// <param name="name">The name.</param>
/// <param name="properties">The (optional) event properties.</param>
public EventInfo(DateTime time, string name, TelemetryEventProperties properties)
{
Assert.ParamIsNotNull(name, "name");
this.Time = time;
this.Name = name;
this.Properties = properties;
}
/// <summary>
/// Gets the time.
/// </summary>
public DateTime Time { get; private set; }
/// <summary>
/// Gets the name.
/// </summary>
public string Name { get; private set; }
/// <summary>
/// Gets the properties (could be <c>null</c>).
/// </summary>
public TelemetryEventProperties Properties { get; private set; }
}
}

Просмотреть файл

@ -0,0 +1,93 @@
using System;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics
{
/// <summary>
/// Encapsulates the captured information for a given exception.
/// </summary>
public class ExceptionInfo
{
/// <summary>
/// Gets or sets the type.
/// </summary>
public string Type { get; set; }
/// <summary>
/// Gets or sets the message.
/// </summary>
public string Message { get; set; }
/// <summary>
/// Gets or sets the stack trace.
/// </summary>
public string StackTrace { get; set; }
/// <summary>
/// Gets or sets the source.
/// </summary>
public string Source { get; set; }
/// <summary>
/// Gets or sets the h result.
/// </summary>
public int HResult { get; set; }
/// <summary>
/// Gets or sets the full text of the exception (message, stack trace, plus inner exceptions).
/// </summary>
public string FullText { get; set; }
/// <summary>
/// Gets or sets the inner exception.
/// </summary>
public ExceptionInfo InnerException { get; set; }
/// <summary>
/// Creates exception information from a given exception.
/// </summary>
/// <param name="exception">The exception.</param>
/// <returns>The exception information.</returns>
public static ExceptionInfo Create(Exception exception)
{
Assert.ParamIsNotNull(exception, "exception");
return Create(exception, true);
}
/// <summary>
/// Creates exception information from a given exception.
/// </summary>
/// <param name="error">The error.</param>
/// <param name="captureFullText">if set to <c>true</c> captures the full text for the exception (used only for the root exception,
/// but not for inner exceptions).</param>
/// <returns>
/// The exception information.
/// </returns>
private static ExceptionInfo Create(Exception error, bool captureFullText)
{
ExceptionInfo info = new ExceptionInfo();
info.Type = error.GetType().FullName;
info.Message = error.Message;
info.StackTrace = error.StackTrace;
info.Source = error.Source;
info.HResult = error.HResult;
if (captureFullText)
{
info.FullText = error.ToString();
}
if (error.InnerException != null)
{
info.InnerException = Create(error.InnerException, false);
}
return info;
}
public override string ToString()
{
return this.FullText;
}
}
}

Просмотреть файл

@ -0,0 +1,340 @@
using System;
using System.Diagnostics;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics
{
/// <summary>
/// Provides methods for tracing information.
/// </summary>
public static class Log
{
static Log()
{
Level = LogLevel.Performance;
}
/// <summary>
/// Gets or sets the diagnosis level. Only items at a level matching or above the current
/// level will be emitted.
/// </summary>
public static LogLevel Level { get; set; }
/// <summary>
/// Traces the performance of the block enclosed in the using statement.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
/// <returns>A disposable item that can be used in a using() statement to trace its performance.</returns>
public static IDisposable PerformanceBlock(string message, params object[] args)
{
Assert.ParamIsNotNull(message, "message");
return (Log.AcceptsLevel(LogLevel.Performance)) ? new PerformanceScopeTracer(message, args) : null;
}
/// <summary>
/// Traces a message with a diagnose level of Performance.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
public static void Performance(string message, params object[] args)
{
Trace(LogLevel.Performance, message, args);
}
/// <summary>
/// Traces a message with a diagnose level of Error.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
public static void Error(string message, params object[] args)
{
Trace(LogLevel.Error, message, args);
}
/// <summary>
/// Traces a message with a diagnose level of Information.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
public static void Info(string message, params object[] args)
{
Trace(LogLevel.Info, message, args);
}
/// <summary>
/// Traces a message with a diagnose level of Warning.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
public static void Warn(string message, params object[] args)
{
Trace(LogLevel.Warn, message, args);
}
/// <summary>
/// Traces a message with a diagnose level of error.
/// </summary>
/// <param name="exception">An exception.</param>
public static void Error(Exception exception)
{
Trace(LogLevel.Error, exception.ToString());
}
/// <summary>
/// Traces a message with a diagnose level of Error.
/// </summary>
/// <param name="exception">An exception.</param>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
public static void Error(Exception exception, string message, params object[] args)
{
string formattedMessage = FormatMessage(message, args, exception);
Trace(LogLevel.Error, formattedMessage);
}
/// <summary>
/// Traces a message with a diagnose level of Warning.
/// </summary>
/// <param name="exception">An exception.</param>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
public static void Warn(Exception exception, string message, params object[] args)
{
string formattedMessage = FormatMessage(message, args, exception);
Trace(LogLevel.Warn, formattedMessage);
}
/// <summary>
/// Traces a message with a diagnose level of Warning.
/// </summary>
/// <param name="exception">An exception.</param>
public static void Warn(Exception exception)
{
Trace(LogLevel.Warn, exception.ToString());
}
/// <summary>
/// Traces a message with a diagnose level of Error, and raises an assertion (when in debug mode) to
/// potentially start the debugger.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
public static void ErrorAndBreak(string message, params object[] args)
{
ErrorAndBreak(null, message, args);
}
/// <summary>
/// Traces a message with a diagnose level of Error, and raises an assertion (when in debug mode) to
/// potentially start the debugger.
/// </summary>
/// <param name="exception">The exception.</param>
public static void ErrorAndBreak(Exception exception)
{
ErrorAndBreak(exception, null);
}
/// <summary>
/// Traces a message with a diagnose level of Error, and raises an assertion (when in debug mode) to
/// potentially start the debugger.
/// </summary>
/// <param name="exception">The exception.</param>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
public static void ErrorAndBreak(Exception exception, string message, params object[] args)
{
TraceAndBreak(LogLevel.Error, exception, message, args);
}
/// <summary>
/// Traces a message with a diagnose level of Warning, and raises an assertion (when in debug mode) to
/// potentially start the debugger.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
public static void WarnAndBreak(string message, params object[] args)
{
WarnAndBreak(null, message, args);
}
/// <summary>
/// Traces a message with a diagnose level of Warning, and raises an assertion (when in debug mode) to
/// potentially start the debugger.
/// </summary>
/// <param name="exception">The exception.</param>
public static void WarnAndBreak(Exception exception)
{
WarnAndBreak(exception, null);
}
/// <summary>
/// Traces a message with a diagnose level of Warning, and raises an assertion (when in debug mode) to
/// potentially start the debugger.
/// </summary>
/// <param name="exception">The exception.</param>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
public static void WarnAndBreak(Exception exception, string message, params object[] args)
{
TraceAndBreak(LogLevel.Warn, exception, message, args);
}
/// <summary>
/// Traces a message with the specified diagnose level.
/// </summary>
/// <param name="level">The level.</param>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
private static void Trace(LogLevel level, string message, object[] args = null)
{
if (AcceptsLevel(level))
{
string formattedMessage = FormatMessage(message, args);
string fullMessage = String.Format("{0}: {1}", GetHeader(level), formattedMessage);
System.Diagnostics.Trace.WriteLine(fullMessage);
/*
switch (level)
{
case DiagnoseLevel.Warning:
System.Diagnostics.Trace.TraceWarning(fullMessage);
break;
case DiagnoseLevel.Error:
System.Diagnostics.Trace.TraceError(fullMessage);
break;
case DiagnoseLevel.Information:
default:
System.Diagnostics.Trace.TraceInformation(fullMessage);
break;
}
*/
}
}
/// <summary>
/// Checks if a message with a given level should be outputted.
/// </summary>
/// <param name="level">The level.</param>
/// <returns><c>true</c> if it should be outputted, otherwise <c>false</c></returns>
private static bool AcceptsLevel(LogLevel level)
{
return level <= Log.Level;
}
/// <summary>
/// Formats a message, optionally appending an exception.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
/// <param name="exception">The exception.</param>
/// <returns>The formatted message.</returns>
private static string FormatMessage(string message, object[] args, Exception exception = null)
{
string formattedMessage = (args != null && args.Length > 0) ? String.Format(message, args) : message;
if (exception != null)
{
formattedMessage += Environment.NewLine + exception.ToString();
}
return formattedMessage;
}
/// <summary>
/// Traces a message with a given diagnose level, and raises an assertion (when in debug mode) to
/// potentially start the debugger.
/// </summary>
/// <param name="level">The level.</param>
/// <param name="exception">The exception.</param>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
private static void TraceAndBreak(LogLevel level, Exception exception, string message, object[] args = null)
{
if (message == null && exception != null)
{
message = "Unexpected exception thrown";
}
string formattedMessage = FormatMessage(message, args, exception);
Trace(level, formattedMessage);
Debug.Fail(formattedMessage);
}
/// <summary>
/// Gets the message header for a given diagnose level.
/// </summary>
/// <param name="level">The level.</param>
/// <returns>The header text.</returns>
private static string GetHeader(LogLevel level)
{
switch (level)
{
case LogLevel.Info: return "INFORMATION";
case LogLevel.Warn: return "WARNING";
case LogLevel.Error: return "ERROR";
case LogLevel.Performance: return "PERFORMANCE";
case LogLevel.Debug : return "DEBUG";
default:
Debug.Fail("Need to update GetHeader() to handle new DiagnoseLevel: " + level);
return level.ToString().ToUpper();
}
}
/// <summary>
/// A helper disposable class to start measure the performance in a using statement, and trace
/// its result when the item is disposed.
/// </summary>
private class PerformanceScopeTracer : IDisposable
{
private DateTime startTime;
private string formattedMessage;
private bool disposed;
/// <summary>
/// Initializes a new instance of the <see cref="PerformanceScopeTracer"/> class.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="args">The arguments.</param>
public PerformanceScopeTracer(string message, object[] args)
{
this.formattedMessage = Log.FormatMessage(message, args);
this.startTime = DateTime.Now;
if (Log.AcceptsLevel(LogLevel.Debug))
{
Log.Performance(formattedMessage);
}
}
/// <summary>
/// Traces the elapsed time of the block.
/// </summary>
public void Dispose()
{
if(!disposed)
{
disposed = true;
TimeSpan elapsed = DateTime.Now - startTime;
string message = String.Format("END {0}. ELAPSED TIME: {1}", this.formattedMessage, elapsed);
Log.Performance(message);
}
}
}
}
/// <summary>
/// An output level for diagnosis messages.
/// </summary>
public enum LogLevel
{
// Update GetHeader() whenever you add more levels here...
None,
Error,
Warn,
Info,
Performance,
Debug,
}
}

Просмотреть файл

@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Management;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics
{
/// <summary>
/// Provides extension methods for the Process class.
/// </summary>
public static class ProcessExtensions
{
/// <summary>
/// Kills the process tree.
/// </summary>
/// <param name="process">The process.</param>
public static void KillTree(this Process process)
{
if (!process.HasExited)
{
ICollection<Process> childProcesses = GetChildren(process);
foreach (var child in childProcesses)
{
KillTree(child);
}
if (!process.HasExited)
{
try
{
process.Kill();
}
catch (Win32Exception)
{
// Ignore, process might have exited
}
}
}
}
/// <summary>
/// Gets the child processes.
/// </summary>
/// <param name="process">The process.</param>
/// <returns>A collection of child processes.</returns>
public static ICollection<Process> GetChildren(this Process process)
{
ICollection<Process> childProcesses = new List<Process>();
try
{
if (!process.HasExited)
{
ManagementObjectSearcher searcher = new ManagementObjectSearcher(
"Select * From Win32_Process Where ParentProcessID = " + process.Id.ToString(CultureInfo.InvariantCulture)
);
foreach (ManagementObject item in searcher.Get())
{
try
{
var childPid = Convert.ToInt32(item["ProcessID"]);
childProcesses.Add(Process.GetProcessById(childPid));
}
catch (Exception)
{
// Ignore errors
}
}
}
}
catch (Win32Exception)
{
// Ignore errors
}
return childProcesses;
}
}
}

Просмотреть файл

@ -0,0 +1,33 @@

namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics.Reports
{
/// <summary>
/// An item attached to a diagnostics report.
/// </summary>
public class Attachment
{
/// <summary>
/// Initializes a new instance of the <see cref="Attachment"/> class.
/// </summary>
/// <param name="name">The attachment name.</param>
/// <param name="content">The attachment content.</param>
public Attachment(string name, byte[] content)
{
Assert.ParamIsNotNull(name, "name");
Assert.ParamIsNotNull(content, "content");
this.Name = name;
this.Content = content;
}
/// <summary>
/// Gets the name.
/// </summary>
public string Name { get; private set; }
/// <summary>
/// Gets the content.
/// </summary>
public byte[] Content { get; private set; }
}
}

Просмотреть файл

@ -0,0 +1,76 @@
using System;
using System.Text;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics.Reports
{
/// <summary>
/// An error report that contains exception information.
/// </summary>
public class ErrorReport : UserReportBase
{
/// <summary>
/// The default file extension for error report files.
/// </summary>
public const string FileExtension = ".errx";
/// <summary>
/// Gets or sets the exception in this report.
/// </summary>
public ExceptionInfo Exception { get; set; }
/// <summary>
/// Creates a new error report, and initializes it with a unique id and current timestamp.
/// </summary>
/// <param name="error">The exception.</param>
/// <returns>The created error report.</returns>
public static ErrorReport Create(Exception error)
{
Assert.ParamIsNotNull(error, "error");
ErrorReport report = new ErrorReport();
report.Initialize();
report.Exception = ExceptionInfo.Create(error);
return report;
}
/// <summary>
/// Parses an error report from an error report file.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns>The parsed error report.</returns>
public static ErrorReport FromFile(string filename)
{
Assert.ParamIsNotNull(filename, "filename");
ReportSerializer serializer = new ReportSerializer();
return serializer.ReadErrorReport(filename);
}
/// <summary>
/// Saves the error report to the specified file.
/// </summary>
/// <param name="filename">The filename.</param>
public void Save(string filename)
{
Assert.ParamIsNotNull(filename, "filename");
ReportSerializer serializer = new ReportSerializer();
serializer.Write(this, filename);
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.AppendLine(String.Format("Date: {0}", Date));
if (!String.IsNullOrEmpty(EmailAddress))
{
sb.AppendLine(String.Format("From: {0}", EmailAddress));
}
sb.AppendLine("Exception:");
sb.AppendLine(Exception.ToString());
return sb.ToString();
}
}
}

Просмотреть файл

@ -0,0 +1,77 @@

namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics.Reports
{
/// <summary>
/// A "Send a Smile" feedback report from a user containing the type (smile or frown) and
/// optional user text.
/// </summary>
public class FeedbackReport : UserReportBase
{
/// <summary>
/// The default file extension for feedback report files.
/// </summary>
public const string FileExtension = ".fdbx";
/// <summary>
/// Gets or sets the feedback type.
/// </summary>
public FeedbackType Type { get; set; }
/// <summary>
/// Gets or sets the feedback report text.
/// </summary>
public string Text { get; set; }
/// <summary>
/// Creates a new instance, and initializes it with a unique id and current timestamp.
/// </summary>
/// <returns>The created report.</returns>
public static FeedbackReport Create()
{
FeedbackReport item = new FeedbackReport();
item.Initialize();
return item;
}
/// <summary>
/// Deserializes a feedback report from a given file.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns>The feedback report.</returns>
public static FeedbackReport FromFile(string filename)
{
Assert.ParamIsNotNull(filename, "filename");
ReportSerializer serializer = new ReportSerializer();
return serializer.ReadFeedbackReport(filename);
}
/// <summary>
/// Saves the feedback report to the specified filename.
/// </summary>
/// <param name="filename">The filename.</param>
public void Save(string filename)
{
Assert.ParamIsNotNull(filename, "filename");
ReportSerializer serializer = new ReportSerializer();
serializer.WriteFeedbackReport(this, filename);
}
}
/// <summary>
/// Represents the type of feedback report.
/// </summary>
public enum FeedbackType
{
/// <summary>
/// A positive report (send a smile).
/// </summary>
Smile,
/// <summary>
/// A negative report (send a frown).
/// </summary>
Frown
}
}

Просмотреть файл

@ -0,0 +1,385 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.IO.Packaging;
using Microsoft.Internal.Tools.TeamMate.Foundation.Net.Mime;
using Microsoft.Internal.Tools.TeamMate.Foundation.Xml;
using System;
using System.IO;
using System.IO.Packaging;
using System.Net.Mime;
using System.Xml.Linq;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics.Reports
{
/// <summary>
/// Serializes and deserializes user reports from files.
/// </summary>
internal class ReportSerializer
{
private DiagnosticsSerializer diagnosticsSerializer = new DiagnosticsSerializer();
/// <summary>
/// Reads a feedback report from a file.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns>The read report.</returns>
public FeedbackReport ReadFeedbackReport(string filename)
{
Assert.ParamIsNotNull(filename, "filename");
FeedbackReport report = new FeedbackReport();
using (Package package = Package.Open(filename, FileMode.Open))
{
var feedbackPart = package.GetSingleRelatedPart(Schema.Relationships.Feedback);
if (feedbackPart == null)
{
throw new Exception("Invalid package");
}
ReadUserReport(report, package);
ReadFeedbackReport(report, feedbackPart);
}
return report;
}
/// <summary>
/// Reads the base information from a user report.
/// </summary>
/// <param name="report">The report.</param>
/// <param name="package">The package containing the information.</param>
private void ReadUserReport(UserReportBase report, Package package)
{
ReadReportInfo(report, package);
report.SystemInfo = ReadSystemInfo(package);
ReadAttachments(report, package);
}
/// <summary>
/// Reads the system information from a package.
/// </summary>
/// <param name="package">The package.</param>
/// <returns>The system information.</returns>
private SystemInfo ReadSystemInfo(Package package)
{
SystemInfo result = null;
var systemInfoPart = package.GetSingleRelatedPart(Schema.Relationships.SystemInfo);
if (systemInfoPart != null)
{
using (Stream stream = systemInfoPart.OpenRead())
{
result = diagnosticsSerializer.DeserializeSystemInfo(stream);
}
}
return result;
}
/// <summary>
/// Reads the attachments contained in a package into a user report.
/// </summary>
/// <param name="report">The report.</param>
/// <param name="package">The package.</param>
private void ReadAttachments(UserReportBase report, Package package)
{
foreach (var relationship in package.GetRelationshipsByType(Schema.Relationships.Attachment))
{
PackagePart part = relationship.TryGetInternalPart();
if (part != null)
{
string name = Path.GetFileName(part.Uri.OriginalString);
byte[] content;
using (var inputStream = part.OpenRead())
using (var outputStream = new MemoryStream())
{
inputStream.CopyTo(outputStream);
content = outputStream.GetBuffer();
}
Attachment attachment = new Attachment(name, content);
report.Attachments.Add(attachment);
}
}
}
/// <summary>
/// Reads the feedback report information from a package part.
/// </summary>
/// <param name="feedback">The feedback.</param>
/// <param name="part">The part.</param>
private void ReadFeedbackReport(FeedbackReport feedback, PackagePart part)
{
XDocument doc;
using (var stream = part.GetStream())
{
doc = XDocument.Load(stream);
}
var feedbackElement = doc.Element(Schema.FeedbackXml.Feedback);
feedback.Type = feedbackElement.GetElementValue<FeedbackType>(Schema.FeedbackXml.Type);
feedback.Text = feedbackElement.GetElementValue<string>(Schema.FeedbackXml.Text);
}
/// <summary>
/// Reads the core report information from a package.
/// </summary>
/// <param name="report">The report.</param>
/// <param name="package">The package.</param>
private void ReadReportInfo(UserReportBase report, Package package)
{
var part = package.GetSingleRelatedPart(Schema.Relationships.ReportInfo);
if (part != null)
{
XDocument doc;
using (var stream = part.GetStream())
{
doc = XDocument.Load(stream);
}
var feedbackElement = doc.Element(Schema.ReportInfoXml.ReportInfo);
report.Id = feedbackElement.GetElementValue<Guid>(Schema.ReportInfoXml.Id);
report.Date = feedbackElement.GetElementValue<DateTime>(Schema.ReportInfoXml.Date);
report.EmailAddress = feedbackElement.GetElementValue<string>(Schema.ReportInfoXml.EmailAddress);
report.UserDisplayName = feedbackElement.GetElementValue<string>(Schema.ReportInfoXml.UserDisplayName);
}
}
/// <summary>
/// Writes a feedback report to a file.
/// </summary>
/// <param name="report">The report.</param>
/// <param name="filename">The filename.</param>
public void WriteFeedbackReport(FeedbackReport report, string filename)
{
Assert.ParamIsNotNull(report, "report");
Assert.ParamIsNotNull(filename, "filename");
using (Package package = Package.Open(filename, FileMode.Create))
{
var feedbackPart = package.CreateRelatedPart(Schema.Parts.Feedback, MediaTypeNames.Text.Xml, Schema.Relationships.Feedback);
WriteUserReport(report, package);
WriteFeedback(report, feedbackPart);
}
}
/// <summary>
/// Writes the system information to a package.
/// </summary>
/// <param name="systemInfo">The system information.</param>
/// <param name="package">The package.</param>
private void WriteSystemInfo(SystemInfo systemInfo, Package package)
{
// For API usability, allowing parameter to be null
if (systemInfo != null)
{
var systemInfoPart = package.CreateRelatedPart(Schema.Parts.SystemInfo, MediaTypeNames.Text.Xml, Schema.Relationships.SystemInfo);
using (Stream stream = systemInfoPart.OpenWrite())
{
diagnosticsSerializer.Serialize(systemInfo, stream);
}
}
}
/// <summary>
/// Writes the attachments to a package.
/// </summary>
/// <param name="report">The report.</param>
/// <param name="package">The package.</param>
private void WriteAttachments(UserReportBase report, Package package)
{
foreach (var attachment in report.Attachments)
{
Uri partUri = new Uri(Schema.Parts.AttachmentsBaseUri + attachment.Name, UriKind.Relative);
string mimeType = MimeTypes.GetMimeType(Path.GetExtension(attachment.Name));
var attachmentPart = package.CreateRelatedPart(partUri, mimeType, Schema.Relationships.Attachment);
using (var stream = attachmentPart.OpenWrite())
{
stream.Write(attachment.Content, 0, attachment.Content.Length);
}
}
}
/// <summary>
/// Writes the feedback report to an output package part.
/// </summary>
/// <param name="feedback">The feedback.</param>
/// <param name="part">The part.</param>
private void WriteFeedback(FeedbackReport feedback, PackagePart part)
{
var element = new XElement(Schema.FeedbackXml.Feedback);
element.SetElementValue<FeedbackType>(Schema.FeedbackXml.Type, feedback.Type);
element.SetElementValue<string>(Schema.FeedbackXml.Text, feedback.Text);
XDocument doc = new XDocument(element);
using (var stream = part.OpenWrite())
{
doc.Save(stream);
}
}
/// <summary>
/// Writes the report information to a package.
/// </summary>
/// <param name="report">The report.</param>
/// <param name="package">The package.</param>
private void WriteReportInfo(UserReportBase report, Package package)
{
var element = new XElement(Schema.ReportInfoXml.ReportInfo);
element.SetElementValue<Guid>(Schema.ReportInfoXml.Id, report.Id);
element.SetElementValue<DateTime>(Schema.ReportInfoXml.Date, report.Date);
element.SetElementValue<string>(Schema.ReportInfoXml.EmailAddress, report.EmailAddress);
element.SetElementValue<string>(Schema.ReportInfoXml.UserDisplayName, report.UserDisplayName);
XDocument doc = new XDocument(element);
var part = package.CreateRelatedPart(Schema.Parts.ReportInfo, MediaTypeNames.Text.Xml, Schema.Relationships.ReportInfo);
using (Stream stream = part.OpenWrite())
{
doc.Save(stream);
}
}
/// <summary>
/// Reads an error report from a file.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns>The read error report.</returns>
public ErrorReport ReadErrorReport(string filename)
{
Assert.ParamIsNotNull(filename, "filename");
ErrorReport errorReport = new ErrorReport();
using (Package package = Package.Open(filename, FileMode.Open))
{
ReadUserReport(errorReport, package);
errorReport.Exception = ReadExceptionInfo(package);
}
return errorReport;
}
/// <summary>
/// Reads the exception information from a package..
/// </summary>
/// <param name="package">The package.</param>
/// <returns>The exception information or <c>null if none was contained</c>.</returns>
private ExceptionInfo ReadExceptionInfo(Package package)
{
ExceptionInfo exceptionInfo = null;
var part = package.GetSingleRelatedPart(Schema.Relationships.Exception);
if (part != null)
{
using (Stream stream = part.OpenRead())
{
exceptionInfo = diagnosticsSerializer.DeserializeExceptionInfo(stream);
}
}
return exceptionInfo;
}
/// <summary>
/// Writes an error report to a file.
/// </summary>
/// <param name="errorReport">The error report.</param>
/// <param name="filename">The filename.</param>
public void Write(ErrorReport errorReport, string filename)
{
Assert.ParamIsNotNull(errorReport, "errorReport");
Assert.ParamIsNotNull(filename, "filename");
using (Package package = Package.Open(filename, FileMode.Create))
{
WriteUserReport(errorReport, package);
WriteExceptionInfo(errorReport.Exception, package);
}
}
/// <summary>
/// Writes the common user report information to a package.
/// </summary>
/// <param name="report">The report.</param>
/// <param name="package">The package.</param>
private void WriteUserReport(UserReportBase report, Package package)
{
WriteReportInfo(report, package);
WriteSystemInfo(report.SystemInfo, package);
WriteAttachments(report, package);
}
/// <summary>
/// Writes the exception information to a package.
/// </summary>
/// <param name="exception">The exception.</param>
/// <param name="package">The package.</param>
private void WriteExceptionInfo(ExceptionInfo exception, Package package)
{
// For API usability, allowing parameter to be null
if (exception != null)
{
var part = package.CreateRelatedPart(Schema.Parts.Exception, MediaTypeNames.Text.Xml, Schema.Relationships.Exception);
using (Stream stream = part.OpenWrite())
{
diagnosticsSerializer.Serialize(exception, stream);
}
}
}
/// <summary>
/// The XML schema for user reports.
/// </summary>
internal static class Schema
{
public const string Id = "http://schemas.microsoft.com/TeamMate/UserReports/2014";
public static class Parts
{
public static readonly Uri Feedback = new Uri("feedback.xml", UriKind.Relative);
public static readonly Uri Exception = new Uri("exception.xml", UriKind.Relative);
public static readonly Uri SystemInfo = new Uri("systemInfo.xml", UriKind.Relative);
public static readonly Uri ApplicationInfo = new Uri("applicationInfo.xml", UriKind.Relative);
public static readonly Uri ReportInfo = new Uri("reportInfo.xml", UriKind.Relative);
public const string AttachmentsBaseUri = "attachments/";
}
public static class Relationships
{
// Follow a convention similar to the OpenXML format, e.g. URL: http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate
private const string RelationshipBaseUri = Schema.Id + "/relationships/";
public const string Feedback = RelationshipBaseUri + "feedback";
public const string Exception = RelationshipBaseUri + "exception";
public const string SystemInfo = RelationshipBaseUri + "systemInfo";
public const string ApplicationInfo = RelationshipBaseUri + "applicationInfo";
public const string ReportInfo = RelationshipBaseUri + "reportInfo";
public const string Attachment = RelationshipBaseUri + "attachment";
}
public static class ReportInfoXml
{
public static readonly XNamespace Namespace = Schema.Id + "/report";
public static readonly XName ReportInfo = Namespace + "ReportInfo";
public static readonly XName Id = Namespace + "Id";
public static readonly XName Date = Namespace + "Date";
public static readonly XName EmailAddress = Namespace + "EmailAddress";
public static readonly XName UserDisplayName = Namespace + "UserDisplayName";
}
public static class FeedbackXml
{
public static readonly XNamespace Namespace = Schema.Id + "/feedback";
public static readonly XName Feedback = Namespace + "Feedback";
public static readonly XName Type = Namespace + "Type";
public static readonly XName Text = Namespace + "Text";
}
}
}
}

Просмотреть файл

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics.Reports
{
/// <summary>
/// Base class for diagnostic reports from end users.
/// </summary>
public abstract class UserReportBase
{
/// <summary>
/// Gets or sets the unique id for this report.
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// Gets or sets the date of the report.
/// </summary>
public DateTime Date { get; set; }
/// <summary>
/// Gets or sets the system information.
/// </summary>
public SystemInfo SystemInfo { get; set; }
/// <summary>
/// Gets or sets the email address of the person reporting the issue.
/// </summary>
public string EmailAddress { get; set; }
/// <summary>
/// Gets or sets the User display name.
/// </summary>
public string UserDisplayName { get; set; }
/// <summary>
/// Gets the collection of attachments associated with the report.
/// </summary>
public ICollection<Attachment> Attachments { get; private set; }
/// <summary>
/// Initializes a new instance of the <see cref="UserReportBase"/> class.
/// </summary>
protected UserReportBase()
{
this.Attachments = new List<Attachment>();
}
/// <summary>
/// Initializes this instance with a unique id and timestamp.
/// </summary>
protected void Initialize()
{
this.Id = Guid.NewGuid();
this.Date = DateTime.Now;
}
}
}

Просмотреть файл

@ -0,0 +1,426 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Collections;
using Microsoft.Internal.Tools.TeamMate.Foundation.Native;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Management;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics
{
/// <summary>
/// Represents system information of where an application is running.
/// </summary>
public class SystemInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="SystemInfo"/> class.
/// </summary>
public SystemInfo()
{
this.Processors = new List<ProcessorInfo>();
this.Screens = new List<ScreenInfo>();
this.VisualStudioVersions = new List<string>();
}
/// <summary>
/// Gets or sets a value indicating whether [is64 bit operating system].
/// </summary>
public bool Is64BitOperatingSystem { get; set; }
/// <summary>
/// Gets or sets the OS version.
/// </summary>
public string OSVersion { get; set; }
/// <summary>
/// Gets or sets the name of the OS.
/// </summary>
public string OSName { get; set; }
/// <summary>
/// Gets or sets the CLR version.
/// </summary>
public string ClrVersion { get; set; }
/// <summary>
/// Gets or sets the name of the system culture.
/// </summary>
/// </value>
public string SystemCultureName { get; set; }
/// <summary>
/// Gets or sets the name of the user culture.
/// </summary>
public string UserCultureName { get; set; }
/// <summary>
/// Gets or sets the name of the time zone.
/// </summary>
public string TimeZoneName { get; set; }
/// <summary>
/// Gets or sets the offset of the user's time zone from UTC.
/// </summary>
public TimeSpan TimeZoneUtcOffset { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the current session is running in remote desktop.
/// </summary>
public bool IsRemoteDesktopSession { get; set; }
/// <summary>
/// Gets or sets the memory information.
/// </summary>
public MemoryInfo Memory { get; set; }
/// <summary>
/// Gets or sets the processor information.
/// </summary>
public ICollection<ProcessorInfo> Processors { get; set; }
/// <summary>
/// Gets or sets the virtual screen information.
/// </summary>
public VirtualScreenInfo VirtualScreen { get; set; }
/// <summary>
/// Gets the screens in the system.
/// </summary>
public ICollection<ScreenInfo> Screens { get; private set; }
/// <summary>
/// Gets or sets a value indicating whether multi touch is enabled.
/// </summary>
public bool IsMultiTouchEnabled { get; set; }
/// <summary>
/// Gets or sets the Internet Explorer version.
/// </summary>
public string IEVersion { get; set; }
/// <summary>
/// Gets or sets the collection of Visual Studio versions.
/// </summary>
public ICollection<string> VisualStudioVersions { get; set; }
/// <summary>
/// Captures a snapshot of the current system information.
/// </summary>
/// <returns>The captured system information.</returns>
/// <remarks>
/// This method can take 1+ second, so you might want to call it in an asynchronous fashion.
/// </remarks>
public static SystemInfo Capture()
{
SystemInfo systemInfo = new SystemInfo();
// OS
systemInfo.Is64BitOperatingSystem = Environment.Is64BitOperatingSystem;
systemInfo.OSVersion = Environment.OSVersion.Version.ToString();
var operatingSystem = GetSingleManagementObject("Win32_OperatingSystem");
if (operatingSystem != null)
{
systemInfo.OSName = GetPropertyValue<string>(operatingSystem, "Caption");
}
// CLR
systemInfo.ClrVersion = Environment.Version.ToString();
// Cultures
systemInfo.SystemCultureName = CultureInfo.InstalledUICulture.Name;
systemInfo.UserCultureName = CultureInfo.CurrentCulture.Name;
// TimeZone
systemInfo.TimeZoneName = TimeZone.CurrentTimeZone.StandardName;
systemInfo.TimeZoneUtcOffset = TimeZone.CurrentTimeZone.GetUtcOffset(new DateTime());
// Memory, Processor, Screens
systemInfo.Memory = GetMemoryInfo();
systemInfo.Processors.AddRange(GetProcessorInfos());
systemInfo.Screens.AddRange(GetScreensInfo());
systemInfo.IEVersion = GetIEVersion();
systemInfo.VisualStudioVersions.AddRange(GetVisualStudioVersions());
systemInfo.IsMultiTouchEnabled = GetMultiTouchEnabled();
systemInfo.IsRemoteDesktopSession = System.Windows.Forms.SystemInformation.TerminalServerSession;
var virtualScreen = System.Windows.Forms.SystemInformation.VirtualScreen;
systemInfo.VirtualScreen = new VirtualScreenInfo()
{
Width = virtualScreen.Width,
Height = virtualScreen.Height
};
return systemInfo;
}
/// <summary>
/// Calculate whether multi touch is enabled or not.
/// </summary>
/// <returns><c>true</c> if multi touch is enabled.</returns>
private static bool GetMultiTouchEnabled()
{
NID digitizer = (NID) NativeMethods.GetSystemMetrics((int)SystemMetric.SM_DIGITIZER);
bool isMultiTouchEnabled = digitizer.HasFlag(NID.NID_READY)
&& digitizer.HasFlag(NID.NID_MULTI_INPUT)
&& digitizer.HasFlag(NID.NID_INTEGRATED_TOUCH); // Trying to use integrated touch to differentiate from USB pens and digitizers
return isMultiTouchEnabled;
}
/// <summary>
/// Gets the Internet Explorer version.
/// </summary>
private static string GetIEVersion()
{
string result = null;
using (RegistryKey internetExplorerKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\MICROSOFT\Internet Explorer"))
{
if (internetExplorerKey != null)
{
// For IE10 and above, we need to rely on svcVersion key instead of Version key
// to get the version info for internet explorer. So here we first try to get the
// version from svcVersion key and if the key is not present then we fall back to
// the Version key.
object internetExplorerVersionKeyValue = internetExplorerKey.GetValue("svcVersion");
if (internetExplorerVersionKeyValue == null)
{
// svcVersion key does not exist. Get the value from 'Version' key
internetExplorerVersionKeyValue = internetExplorerKey.GetValue("Version");
}
if (internetExplorerVersionKeyValue != null)
{
result = internetExplorerVersionKeyValue.ToString();
}
}
}
return result;
}
/// <summary>
/// Gets the Visual Studio versions.
/// </summary>
private static ICollection<string> GetVisualStudioVersions()
{
List<string> results = new List<string>();
// KLUDGE: Update this with new versions that we want to recognize on demand
string[] probingVersions = new string[] { "9.0", "10.0", "11.0", "12.0", "13.0", "14.0", "15.0" };
foreach (string probingVersion in probingVersions)
{
var key = Registry.ClassesRoot.OpenSubKey("VisualStudio.DTE." + probingVersion);
if (key != null)
{
results.Add(probingVersion);
key.Close();
}
}
return results;
}
/// <summary>
/// Gets the screens information.
/// </summary>
private static IEnumerable<ScreenInfo> GetScreensInfo()
{
var allScreens = System.Windows.Forms.Screen.AllScreens;
foreach (var screen in allScreens)
{
ScreenInfo screenInfo = new ScreenInfo();
screenInfo.Width = screen.Bounds.Width;
screenInfo.Height = screen.Bounds.Height;
screenInfo.BitsPerPixel = screen.BitsPerPixel;
screenInfo.IsPrimary = screen.Primary;
yield return screenInfo;
}
}
/// <summary>
/// Gets the processor information.
/// </summary>
private static IEnumerable<ProcessorInfo> GetProcessorInfos()
{
foreach (var processor in GetManagementObjects("Win32_processor"))
{
ProcessorInfo processorInfo = new ProcessorInfo();
processorInfo.Name = GetPropertyValue<string>(processor, "Name");
processorInfo.Family = GetPropertyValue<string>(processor, "Caption");
processorInfo.NumberOfCores = (int)GetPropertyValue<uint>(processor, "NumberOfCores");
processorInfo.NumberOfLogicalProcessors = (int)GetPropertyValue<uint>(processor, "NumberOfLogicalProcessors");
processorInfo.MaxClockSpeed = (int)GetPropertyValue<uint>(processor, "MaxClockSpeed");
yield return processorInfo;
}
}
/// <summary>
/// Gets the memory information.
/// </summary>
private static MemoryInfo GetMemoryInfo()
{
MEMORYSTATUSEX memoryStatus = new MEMORYSTATUSEX();
NativeMethods.GlobalMemoryStatusEx(memoryStatus);
MemoryInfo memoryInfo = new MemoryInfo();
memoryInfo.AvailablePhysicalMemory = (long)memoryStatus.ullAvailPhys;
memoryInfo.AvailableVirtualMemory = (long)memoryStatus.ullAvailVirtual;
memoryInfo.MemoryLoad = (int)memoryStatus.dwMemoryLoad;
memoryInfo.TotalPhysicalMemory = (long)memoryStatus.ullTotalPhys;
memoryInfo.TotalVirtualMemory = (long)memoryStatus.ullTotalVirtual;
return memoryInfo;
}
/// <summary>
/// Gets the a set of management objects for a given class name.
/// </summary>
/// <param name="className">Name of the class.</param>
/// <returns>The resulting management object collection.</returns>
private static ManagementObjectCollection GetManagementObjects(string className)
{
SelectQuery query = new SelectQuery(className);
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
return searcher.Get();
}
/// <summary>
/// Gets a single management object for a given class name.
/// </summary>
/// <param name="className">Name of the class.</param>
/// <returns>The single management object, or <c>null</c> if none found.</returns>
private static ManagementBaseObject GetSingleManagementObject(string className)
{
return GetManagementObjects(className).OfType<ManagementBaseObject>().FirstOrDefault();
}
/// <summary>
/// Gets the property value for a given management object property.
/// </summary>
/// <typeparam name="T">The type of the proeprty value.</typeparam>
/// <param name="item">The management object.</param>
/// <param name="propertyName">Name of the property.</param>
/// <returns>The property value, or the default type value if not found or compatible.</returns>
private static T GetPropertyValue<T>(ManagementBaseObject item, string propertyName)
{
var property = item.Properties[propertyName];
return (property != null && property.Value is T) ? (T)property.Value : default(T);
}
}
/// <summary>
/// Represents processor (CPU) information.
/// </summary>
public class ProcessorInfo
{
/// <summary>
/// Gets or sets the name.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets the family.
/// </summary>
public string Family { get; set; }
/// <summary>
/// Gets or sets the number of cores.
/// </summary>
public int NumberOfCores { get; set; }
/// <summary>
/// Gets or sets the number of logical processors.
/// </summary>
public int NumberOfLogicalProcessors { get; set; }
/// <summary>
/// Gets or sets the maximum clock speed.
/// </summary>
public int MaxClockSpeed { get; set; }
}
/// <summary>
/// Represents the system memory information.
/// </summary>
public class MemoryInfo
{
/// <summary>
/// Gets or sets the total physical memory.
/// </summary>
public long TotalPhysicalMemory { get; set; }
/// <summary>
/// Gets or sets the available physical memory.
/// </summary>
public long AvailablePhysicalMemory { get; set; }
/// <summary>
/// Gets or sets the memory load.
/// </summary>
public int MemoryLoad { get; set; }
/// <summary>
/// Gets or sets the total virtual memory.
/// </summary>
public long TotalVirtualMemory { get; set; }
/// <summary>
/// Gets or sets the available virtual memory.
/// </summary>
public long AvailableVirtualMemory { get; set; }
}
/// <summary>
/// Represents screen information.
/// </summary>
public class ScreenInfo
{
/// <summary>
/// Gets or sets the height in pixels.
/// </summary>
public int Height { get; set; }
/// <summary>
/// Gets or sets the width in pixels.
/// </summary>
public int Width { get; set; }
/// <summary>
/// Gets or sets the bits per pixel.
/// </summary>
public int BitsPerPixel { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the screen is the primary screen or not.
/// </summary>
public bool IsPrimary { get; set; }
}
/// <summary>
/// Represents the virtual screen information (for multiple screens).
/// </summary>
public class VirtualScreenInfo
{
/// <summary>
/// Gets or sets the height in pixels.
/// </summary>
public int Height { get; set; }
/// <summary>
/// Gets or sets the width in pixels.
/// </summary>
public int Width { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,184 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics
{
/// <summary>
/// Provides utility mehtods for logging telemetry events.
/// </summary>
/// <remarks>
/// This class follows a similar pattern to the Trace class, and notifications to TraceListeners.
/// </remarks>
public static class Telemetry
{
private static bool isEnabled;
private static bool hasListeners;
private static ICollection<TelemetryListener> listeners = new TelemetryListener[0];
private static Thread workerThread;
private static ConcurrentQueue<NotifyDelegate> workQueue = new ConcurrentQueue<NotifyDelegate>();
private static AutoResetEvent workQueuedEvent = new AutoResetEvent(false);
private static ManualResetEvent workQueuedEmptiedEvent = new ManualResetEvent(false);
/// <summary>
/// Gets or sets a value indicating whether telemetry logging is enabled.
/// </summary>
public static bool IsEnabled
{
get { return isEnabled; }
set
{
if (isEnabled != value)
{
isEnabled = value;
InvalidateHasListeners();
if (IsEnabled)
{
workerThread = new Thread(DoWork);
workerThread.Name = "Telemetry Worker";
workerThread.Priority = ThreadPriority.Lowest;
workerThread.Start();
}
}
}
}
/// <summary>
/// A worker loop that will dequeue telemetry events and notify telemetry listeners.
/// </summary>
private static void DoWork()
{
while (workQueuedEvent.WaitOne())
{
workQueuedEmptiedEvent.Reset();
NotifyDelegate notifyDelegate;
while (workQueue.TryDequeue(out notifyDelegate))
{
try
{
foreach (TelemetryListener listener in listeners)
{
notifyDelegate(listener);
}
}
catch (Exception e)
{
Log.ErrorAndBreak(e, "Unexpected error in Telemetry background work");
}
}
workQueuedEmptiedEvent.Set();
}
}
/// <summary>
/// Flushes any pending telemetry events in this class to telemetry listeners.
/// </summary>
public static void Flush()
{
workQueuedEmptiedEvent.WaitOne();
}
/// <summary>
/// Adds a listener.
/// </summary>
/// <param name="listener">The listener.</param>
public static void AddListener(TelemetryListener listener)
{
Assert.ParamIsNotNull(listener, "listener");
var newListeners = listeners.ToList();
newListeners.Add(listener);
listeners = newListeners.ToArray();
InvalidateHasListeners();
}
/// <summary>
/// Removes a listener.
/// </summary>
/// <param name="listener">The listener.</param>
public static void RemoveListener(TelemetryListener listener)
{
Assert.ParamIsNotNull(listener, "listener");
var newListeners = listeners.ToList();
newListeners.Remove(listener);
listeners = newListeners.ToArray();
InvalidateHasListeners();
}
/// <summary>
/// Logs a given telemetry event.
/// </summary>
/// <param name="name">The event name.</param>
/// <param name="properties">The (optional) event properties.</param>
public static void Event(string name, TelemetryEventProperties properties = null)
{
Assert.ParamIsNotNull(name, "name");
if (!hasListeners)
{
return;
}
Event(new EventInfo(DateTime.Now, name, properties));
}
/// <summary>
/// Logs the given event information.
/// </summary>
/// <param name="info">The event information.</param>
[EditorBrowsable(EditorBrowsableState.Advanced)] // Marked as non-browsable as we want developers to use the more usable overload above
public static void Event(EventInfo info)
{
QueueNotification(l => l.Event(info));
}
/// <summary>
/// Logs the given exception information.
/// </summary>
/// <param name="info">The exception information.</param>
public static void Exception(Exception info)
{
QueueNotification(l => l.Exception(info));
}
/// <summary>
/// Invalidates the has listeners boolean flag based on the current set of listeners.
/// </summary>
private static void InvalidateHasListeners()
{
hasListeners = (isEnabled && listeners.Any());
}
/// <summary>
/// Queues the notification of the given delegate for later.
/// </summary>
/// <param name="notifyDelegate">The notify delegate.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void QueueNotification(NotifyDelegate notifyDelegate)
{
if (!hasListeners)
{
return;
}
workQueue.Enqueue(notifyDelegate);
workQueuedEvent.Set();
}
/// <summary>
/// A delegate that actions (notifies) a given listener.
/// </summary>
/// <param name="listener">The listener.</param>
private delegate void NotifyDelegate(TelemetryListener listener);
}
}

Просмотреть файл

@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics
{
/// <summary>
/// Represents a bag of properties for a telemetry event.
/// </summary>
public class TelemetryEventProperties : Dictionary<string,object>
{
}
}

Просмотреть файл

@ -0,0 +1,30 @@

using System;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics
{
/// <summary>
/// Implements a basic telemetry listener.
/// </summary>
/// <remarks>
/// Follows the same pattern as the base TraceListener.
/// </remarks>
public abstract class TelemetryListener
{
/// <summary>
/// Invoked to log event information.
/// </summary>
/// <param name="info">The event information.</param>
public virtual void Event(EventInfo info)
{
}
/// <summary>
/// Invoked to log exception information.
/// </summary>
/// <param name="info">The exception information.</param>
public virtual void Exception(Exception ex)
{
}
}
}

Просмотреть файл

@ -0,0 +1,61 @@
using System.Diagnostics;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics
{
/// <summary>
/// A helper class to register and unregister the logging of Trace information to a log file.
/// </summary>
public class TraceLogFile
{
private bool registered;
private TextWriterTraceListener traceListener;
private bool originalAutoFlush;
private string traceFile;
/// <summary>
/// Initializes a new instance of the <see cref="TraceLogFile"/> class.
/// </summary>
/// <param name="path">The output file path.</param>
public TraceLogFile(string path)
{
Assert.ParamIsNotNullOrEmpty(path, "path");
this.traceFile = path;
}
/// <summary>
/// Registers the trace log file as a global trace listener. Traced information
/// will start to be output to the output trace file.
/// </summary>
public void Register()
{
if (!registered)
{
this.traceListener = new TextWriterTraceListener(traceFile);
this.originalAutoFlush = Trace.AutoFlush;
Trace.Listeners.Add(this.traceListener);
Trace.AutoFlush = true;
registered = true;
}
}
/// <summary>
/// Unregisters this instance as a global trace listener. Traced information will no longer
/// be output to the output trace file.
/// </summary>
public void Unregister()
{
if (registered)
{
Trace.Listeners.Remove(this.traceListener);
Trace.AutoFlush = originalAutoFlush;
this.traceListener.Close();
this.traceListener = null;
this.originalAutoFlush = false;
registered = false;
}
}
}
}

Просмотреть файл

@ -0,0 +1,310 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics;
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
using System.Security.Principal;
using System.Text;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.DirectoryServices
{
/// <summary>
/// Provides utility methods for reading user information from Active Directory.
/// </summary>
public class DirectoryBrowser
{
private bool defaultSearchRootResolved;
private DirectoryEntry defaultSearchRoot;
private DirectoryBrowserMode mode;
/// <summary>
/// Initializes a new instance of the <see cref="DirectoryBrowser"/> class.
/// </summary>
public DirectoryBrowser()
: this(DirectoryBrowserMode.Default)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DirectoryBrowser"/> class.
/// </summary>
/// <param name="mode">The brower mode to use.</param>
public DirectoryBrowser(DirectoryBrowserMode mode)
{
this.mode = mode;
}
/// <summary>
/// Finds the entry for the active user.
/// </summary>
/// <returns>The active user entry, or <c>null</c> if not found.</returns>
public UserEntry FindMe()
{
var sid = WindowsIdentity.GetCurrent().User.Value;
var result = FindUsersBySids(new string[] { sid }).FirstOrDefault();
return result;
}
/// <summary>
/// Finds the entry for a given user by account name.
/// </summary>
/// <param name="accountName">Name of the account.</param>
/// <returns>The user entry, or <c>null</c> if not found.</returns>
public UserEntry FindUserByAccountName(string accountName)
{
Assert.ParamIsNotNullOrEmpty(accountName, "accountName");
return FindUsersByAccountName(new string[] { accountName }).FirstOrDefault();
}
/// <summary>
/// Finds the user entries for one or more account names.
/// </summary>
/// <param name="mailAddresses">The account names.</param>
/// <returns>The found user entries. Entries might be missing for non matching user names
/// (so the result array does not necessarily match the input collection count)</returns>
public UserEntry[] FindUsersByAccountName(IEnumerable<string> accountNames)
{
Assert.ParamIsNotNull(accountNames, "accountNames");
return UserEntry.FromResults(SearchUsersByProperty(DirectoryProperties.SAMAccountName, accountNames));
}
/// <summary>
/// Finds the user entries for one or more account names.
/// </summary>
/// <param name="mailAddresses">The account names.</param>
/// <returns>The found user entries. Entries might be missing for non matching user names
/// (so the result array does not necessarily match the input collection count)</returns>
public UserEntry[] FindUsersByManager(string managerDistinguishedName)
{
Assert.ParamIsNotNull(managerDistinguishedName, "managerDistinguishedName");
return UserEntry.FromResults(SearchUsersByProperty(DirectoryProperties.Manager, new string[] { managerDistinguishedName }));
}
/// <summary>
/// Finds the entry for a given user by mail address.
/// </summary>
/// <param name="mailAddress">Mail address.</param>
/// <returns>The user entry, or <c>null</c> if not found.</returns>
public UserEntry FindUserByMailAddress(string mailAddress)
{
Assert.ParamIsNotNullOrEmpty(mailAddress, "mailAddress");
return FindUsersByMailAddress(new string[] { mailAddress }).FirstOrDefault();
}
/// <summary>
/// Finds the user entries for one or more mail adderss.
/// </summary>
/// <param name="accountNames">The account names.</param>
/// <returns>The found user entries. Entries might be missing for non matching user names
/// (so the result array does not necessarily match the input collection count)</returns>
public UserEntry[] FindUsersByMailAddress(IEnumerable<string> mailAddresses)
{
Assert.ParamIsNotNull(mailAddresses, "mailAddresses");
return UserEntry.FromResults(SearchUsersByProperty(DirectoryProperties.Mail, mailAddresses));
}
/// <summary>
/// Finds the user entries for a given display name (multiple users might have the same display name).
/// </summary>
/// <param name="displayName">The display name.</param>
/// <returns>The matching user entries.</returns>
public UserEntry[] FindUsersByDisplayName(string displayName)
{
Assert.ParamIsNotNullOrEmpty(displayName, "displayName");
return FindUsersByDisplayName(new string[] { displayName });
}
/// <summary>
/// Finds the user entries for one or more display names.
/// </summary>
/// <param name="displayNames">The display names.</param>
/// <returns>The matching user entries.</returns>
public UserEntry[] FindUsersByDisplayName(IEnumerable<string> displayNames)
{
Assert.ParamIsNotNull(displayNames, "displayNames");
return UserEntry.FromResults(SearchUsersByProperty(DirectoryProperties.DisplayName, displayNames));
}
/// <summary>
/// Finds the user entries for one or more SIDs (security identifiers).
/// </summary>
/// <param name="sids">The SIDs.</param>
/// <returns>The matching user entries.</returns>
public UserEntry[] FindUsersBySids(IEnumerable<string> sids)
{
Assert.ParamIsNotNull(sids, "sids");
// See http://us.generation-nt.com/answer/how-get-correct-sid-format-so-i-can-search-help-37063152.html
// We need to convert the string sids into a more readable hex format
return UserEntry.FromResults(SearchUsersByProperty(DirectoryProperties.ObjectSid, sids.Select(s => SidToHex(s))));
}
/// <summary>
/// Finds the user entries by distinguished names.
/// </summary>
/// <param name="distinguishedNames">The distinguished names.</param>
/// <returns>The matching user entries.</returns>
public UserEntry[] FindUsersByDistinguishedNames(IEnumerable<string> distinguishedNames)
{
Assert.ParamIsNotNull(distinguishedNames, "distinguishedNames");
return UserEntry.FromResults(SearchUsersByProperty(DirectoryProperties.DistinguishedName, distinguishedNames));
}
/// <summary>
/// Creates a directory searcher and initializes it with the appropriate search root and properties to load.
/// </summary>
private DirectorySearcher CreateDirectorySearcher()
{
DirectorySearcher searcher = new DirectorySearcher(DefaultSearchRoot);
foreach (string property in UserEntry.RequiredPropertyNames)
{
searcher.PropertiesToLoad.Add(property);
}
if ((mode & DirectoryBrowserMode.Light) != DirectoryBrowserMode.Light)
{
foreach (string property in UserEntry.ExtraPropertyNames)
{
searcher.PropertiesToLoad.Add(property);
}
}
return searcher;
}
/// <summary>
/// Converts a SID (security identifier) to hexadecimal format used for searching. This is the format in which
/// SIDs are stored and searched for in Active Directory.
/// </summary>
/// <param name="sid">The sid.</param>
/// <returns>The converted sid string.</returns>
private static string SidToHex(string sid)
{
SecurityIdentifier s = new SecurityIdentifier(sid);
byte[] sidBytes = new byte[s.BinaryLength];
s.GetBinaryForm(sidBytes, 0);
string hexSid = '\\' + BitConverter.ToString(sidBytes).ToLower().Replace('-', '\\');
return hexSid;
}
/// <summary>
/// Searches Active Directory for users by a given property name and one or more matching values.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="values">The matching values.</param>
/// <returns>The search result collection.</returns>
private SearchResultCollection SearchUsersByProperty(string property, IEnumerable<string> values)
{
DirectorySearcher searcher = CreateDirectorySearcher();
searcher.Filter = "(&(objectClass=user)" + OrFilter(property, values) + ")";
return searcher.FindAll();
}
/// <summary>
/// Creates an Active Directory search expression filter to match the given property name and one or more values.
/// </summary>
/// <param name="propertyName">Name of the property.</param>
/// <param name="values">The values.</param>
/// <returns>The search expression filter.</returns>
private static string OrFilter(string propertyName, IEnumerable<string> values)
{
StringBuilder filter = new StringBuilder();
foreach (object value in values)
{
filter.AppendFormat("({0}={1})", propertyName, value);
}
return (filter.Length > 0) ? "(|" + filter + ")" : String.Empty;
}
/// <summary>
/// Resolves the default search root for the current domain.
/// </summary>
/// <value>
/// The default search root.
/// </value>
public DirectoryEntry DefaultSearchRoot
{
get
{
// See http://www.infini-tec.de/post/2004/12/30/Find-an-user-in-a-multi-domain-Active-Directory-enironment-programmatically.aspx
if (!defaultSearchRootResolved)
{
// Get the directory entry for the global catalog root
DirectoryEntry gc = new DirectoryEntry("GC:");
// The catalog root has a single child which is the root node for searching
defaultSearchRoot = gc.Children.OfType<DirectoryEntry>().FirstOrDefault();
defaultSearchRootResolved = true;
}
return defaultSearchRoot;
}
}
/// <summary>
/// Gets a value indicating whether we are currently in the context of an Active Directory domain.
/// </summary>
public bool IsInDomain
{
get
{
// Seems to work, alternatively look into something like Domain.GetComputerDomain() maybe...
return (DefaultSearchRoot != null);
}
}
}
/// <summary>
/// A set of flags that indicate what values a directory browser should populate in returned
/// user entries.
/// </summary>
[Flags]
public enum DirectoryBrowserMode
{
Default,
/// <summary>
/// Populate lightweight user values only (e.g. no user thumbnail)
/// </summary>
Light = 0x01
}
/// <summary>
/// Contains the well known names of certain user Active Directory properties.
/// </summary>
internal static class DirectoryProperties
{
public const string DisplayName = "displayname"; // Joe Stevens
public const string CommonName = "cn"; // Joseph Stevens
public const string UserPrincipalName = "userprincipalname"; // jstevens@microsoft.com
public const string ThumbnailPhoto = "thumbnailphoto"; // bytes[]
public const string MailNickname = "mailnickname"; // jstevens
public const string Title = "title"; // SENIOR SDE
public const string Mail = "mail"; // jstevens@microsoft.com
public const string DistinguishedName = "distinguishedname"; // CN=Joe Stevens,OU=UserAccounts,DC=redmond,DC=corp,DC=microsoft,DC=com
public const string Manager = "manager"; // CN=Peter Parker,OU=UserAccounts,DC=europe,DC=corp,DC=microsoft,DC=com
public const string SpokenName = "msexchumspokenname"; // bytes[]
public const string TelephoneNumber = "telephonenumber"; //
public const string HomePage = "wwwhomepage"; //
public const string StreetAddress = "streetaddress"; //
public const string State = "st"; //
public const string GivenName = "givenname"; //
public const string Surname = "sn"; //
public const string PostalCode = "postalcode"; //
public const string SAMAccountName = "sAMAccountName"; // jstevens
public const string ObjectSid = "objectsid"; //
public const string Sip = "msRTCSIP-PrimaryUserAddress"; // sip:jstevens@microsoft.com (used for OCS)
public const string Department = "department"; // Visual Studio
}
}

Просмотреть файл

@ -0,0 +1,85 @@
using System;
using System.Diagnostics;
using System.DirectoryServices.ActiveDirectory;
using System.Security.Principal;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.DirectoryServices
{
/// <summary>
/// Provides utility methods for Active Directory.
/// </summary>
public static class DirectoryUtilities
{
private static Lazy<bool> isComputerInDomain = new Lazy<bool>(() => EvaluateIsComputerInDomain());
private static bool? isCurrentUserInDomain;
private static string lastUserSid;
/// <summary>
/// Gets a value indicating whether the current computer is in a domain.
/// </summary>
public static bool IsComputerInDomain
{
get { return isComputerInDomain.Value; }
}
/// <summary>
/// Gets a value indicating whether the curren tuser is in a domain.
/// </summary>
public static bool IsCurrentUserInDomain
{
get
{
string currentSid = WindowsIdentity.GetCurrent().User.Value;
if (!String.Equals(lastUserSid, currentSid))
{
// A simple check for impersonation, clear caches when the user changes...
isCurrentUserInDomain = null;
}
if (isCurrentUserInDomain == null)
{
lastUserSid = currentSid;
isCurrentUserInDomain = EvaluateIsCurrentUserInDomain();
}
return isCurrentUserInDomain.Value;
}
}
/// <summary>
/// Determines whether the current computer is in a domain.
/// </summary>
/// <returns><c>true</c> if the current computer is in a domain.</returns>
[DebuggerStepThrough]
private static bool EvaluateIsComputerInDomain()
{
try
{
var ignore = Domain.GetComputerDomain();
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// Determines whether the current user is in a domain.
/// </summary>
/// <returns><c>true</c> if the current user is in a domain.</returns>
[DebuggerStepThrough]
private static bool EvaluateIsCurrentUserInDomain()
{
try
{
var ignore = Domain.GetCurrentDomain();
return true;
}
catch (Exception)
{
return false;
}
}
}
}

Просмотреть файл

@ -0,0 +1,206 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.DirectoryServices;
using System.Security.Principal;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.DirectoryServices
{
/// <summary>
/// Describes an entry for a user in Active Directory.
/// </summary>
public class UserEntry
{
/// <summary>
/// The names of the required properties to load from Active Directory to populate a user.
/// </summary>
public static readonly ICollection<string> RequiredPropertyNames = new ReadOnlyCollection<string>(new string[] {
DirectoryProperties.SAMAccountName, DirectoryProperties.DisplayName, DirectoryProperties.GivenName,
DirectoryProperties.Surname, DirectoryProperties.DistinguishedName, DirectoryProperties.UserPrincipalName,
DirectoryProperties.MailNickname, DirectoryProperties.Mail, DirectoryProperties.CommonName, DirectoryProperties.Sip,
DirectoryProperties.ObjectSid, DirectoryProperties.Title, DirectoryProperties.Department
});
/// <summary>
/// The advanced additional property names to load from Active Directory for a user (depending on the mode).
/// </summary>
public static readonly ICollection<string> ExtraPropertyNames = new ReadOnlyCollection<string>(new string[] {
DirectoryProperties.ThumbnailPhoto
});
/// <summary>
/// Creates a user entry from a directory entry.
/// </summary>
/// <param name="entry">The directory entry.</param>
/// <returns>The user entry.</returns>
public static UserEntry FromEntry(DirectoryEntry entry)
{
Assert.ParamIsNotNull(entry, "entry");
return FromEntryOrResult(entry);
}
/// <summary>
/// Creates a user entry from a search result.
/// </summary>
/// <param name="result">The result.</param>
/// <returns>A user entry.</returns>
public static UserEntry FromResult(SearchResult result)
{
Assert.ParamIsNotNull(result, "result");
return FromEntryOrResult(result);
}
/// <summary>
/// Creates one or more user entries from a search result collection.
/// </summary>
/// <param name="results">The search results.</param>
/// <returns>The user entries.</returns>
public static UserEntry[] FromResults(SearchResultCollection results)
{
Assert.ParamIsNotNull(results, "results");
UserEntry[] userEntries = new UserEntry[results.Count];
for (int i = 0; i < results.Count; i++)
{
userEntries[i] = UserEntry.FromResult(results[i]);
}
return userEntries;
}
/// <summary>
/// Creates a user entry from a directory entry or search result.
/// </summary>
/// <param name="entryOrResult">The directory entry or search result.</param>
/// <returns>The user entry.</returns>
public static UserEntry FromEntryOrResult(object entryOrResult)
{
Assert.ParamIsNotNull(entryOrResult, "entryOrResult");
UserEntry item = new UserEntry();
item.AccountName = GetPropertyValue<string>(entryOrResult, DirectoryProperties.SAMAccountName);
item.CommonName = GetPropertyValue<string>(entryOrResult, DirectoryProperties.CommonName);
item.DisplayName = GetPropertyValue<string>(entryOrResult, DirectoryProperties.DisplayName);
item.GivenName = GetPropertyValue<string>(entryOrResult, DirectoryProperties.GivenName);
item.Surname = GetPropertyValue<string>(entryOrResult, DirectoryProperties.Surname);
item.DistinguishedName = GetPropertyValue<string>(entryOrResult, DirectoryProperties.DistinguishedName);
item.UserPrincipalName = GetPropertyValue<string>(entryOrResult, DirectoryProperties.UserPrincipalName);
item.MailNickname = GetPropertyValue<string>(entryOrResult, DirectoryProperties.MailNickname);
item.Mail = GetPropertyValue<string>(entryOrResult, DirectoryProperties.Mail);
item.Sip = GetPropertyValue<string>(entryOrResult, DirectoryProperties.Sip);
item.Title = GetPropertyValue<string>(entryOrResult, DirectoryProperties.Title);
item.Department = GetPropertyValue<string>(entryOrResult, DirectoryProperties.Department);
byte[] sidBytes = GetPropertyValue<byte[]>(entryOrResult, DirectoryProperties.ObjectSid);
if (sidBytes != null)
{
item.Sid = new SecurityIdentifier(sidBytes, 0).Value;
}
byte[] photoBytes = GetPropertyValue<byte[]>(entryOrResult, DirectoryProperties.ThumbnailPhoto);
item.ThumbnailPhotoBytes = photoBytes;
return item;
}
/// <summary>
/// Gets a property value by name from a directory entry or search result.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="entryOrResult">The directory entry or search result.</param>
/// <param name="propertyName">Name of the property.</param>
/// <returns>The property value, or default value type if the property was not available.</returns>
private static T GetPropertyValue<T>(object entryOrResult, string propertyName)
{
object value = null;
if (entryOrResult is DirectoryEntry)
{
PropertyValueCollection values = ((DirectoryEntry)entryOrResult).Properties[propertyName];
value = (values != null && values.Count > 0) ? values[0] : null;
}
else if (entryOrResult is SearchResult)
{
ResultPropertyValueCollection values = ((SearchResult)entryOrResult).Properties[propertyName];
value = (values != null && values.Count > 0) ? values[0] : null;
}
return (value is T) ? (T)value : default(T);
}
/// <summary>
/// Gets the name of the account.
/// </summary>
public string AccountName { get; private set; }
/// <summary>
/// Gets the display name.
/// </summary>
public string DisplayName { get; private set; }
/// <summary>
/// Gets the name of the given.
/// </summary>
public string GivenName { get; private set; }
/// <summary>
/// Gets the surname.
/// </summary>
public string Surname { get; private set; }
/// <summary>
/// Gets the distinguished name.
/// </summary>
public string DistinguishedName { get; private set; }
/// <summary>
/// Gets the user principal name.
/// </summary>
public string UserPrincipalName { get; private set; }
/// <summary>
/// Gets the mail nickname.
/// </summary>
public string MailNickname { get; private set; }
/// <summary>
/// Gets the mail address.
/// </summary>
public string Mail { get; private set; }
/// <summary>
/// Gets the thumbnail photo bytes.
/// </summary>
public byte[] ThumbnailPhotoBytes { get; private set; }
/// <summary>
/// Gets the the common name.
/// </summary>
public string CommonName { get; private set; }
/// <summary>
/// Gets the users SIP address (e.g. for Lync). Might or might not match the users email address.
/// </summary>
public string Sip { get; private set; }
/// <summary>
/// Gets the sid.
/// </summary>
public string Sid { get; private set; }
/// <summary>
/// Gets the title.
/// </summary>
public string Title { get; set; }
/// <summary>
/// Gets the department
/// </summary>
public string Department { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,31 @@
using System;
namespace Microsoft.Internal.Tools.TeamMate.Foundation
{
/// <summary>
/// Provides utility methods to format data.
/// </summary>
public static class FormatUtilities
{
/// <summary>
/// Formats bytes into a friendly string (e.g. KB, MB, GB, etc.)
/// </summary>
/// <param name="bytes">The bytes.</param>
/// <returns>The formatted string.</returns>
public static string FormatBytes(long bytes)
{
string[] units = { "bytes", "KB", "MB", "GB", "TB", "PB" };
int unitIndex = 0;
// TODO: We are losing some rounding here, e.g. 3.72 MB gets rounded to 3MB
while (bytes >= 1024 && unitIndex < units.Length)
{
bytes /= 1024;
unitIndex++;
}
return String.Format("{0} {1}", bytes, units[unitIndex]);
}
}
}

Просмотреть файл

@ -0,0 +1,62 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics;
using System;
using System.IO;
using System.Threading.Tasks;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.IO
{
/// <summary>
/// Provides extension methods for the IO package.
/// </summary>
public static class IOExtensions
{
// Copied from .NET. 80K.
private const int DefaultCopyBufferSize = 0x14000;
/// <summary>
/// Copies a stream asynchronously, optionally reporting percentage progress based on the stream bytes.
/// </summary>
/// <param name="source">The source stream.</param>
/// <param name="destination">The destination stream.</param>
/// <param name="progress">The progress reporter.</param>
/// <param name="length">The optional well known stream length.</param>
public static async Task CopyToAsync(this Stream source, Stream destination, IProgress<double> progress, long? length)
{
Assert.ParamIsNotNull(source, "from");
Assert.ParamIsNotNull(destination, "destination");
if (length != null && length.Value <= 0)
{
throw new ArgumentException("Length must be greater than 0");
}
if (progress != null)
{
progress.Report(0);
}
long totalBytesCopied = 0;
int byteCount;
byte[] buffer = new byte[DefaultCopyBufferSize];
while ((byteCount = await source.ReadAsync(buffer, 0, buffer.Length)) != 0)
{
await destination.WriteAsync(buffer, 0, byteCount);
totalBytesCopied += byteCount;
if (length != null && progress != null)
{
double calculatedProgress = (double)totalBytesCopied / (double)length.Value;
// In case length was not a trustable number, never make progress greater than 100%
calculatedProgress = Math.Min(calculatedProgress, 1.0);
progress.Report(calculatedProgress);
}
}
if (progress != null)
{
progress.Report(1.0);
}
}
}
}

Просмотреть файл

@ -0,0 +1,408 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Packaging;
using System.Linq;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.IO.Packaging
{
/// <summary>
/// Provides extension methods to the System.IO.Packaing.Package type
/// designed to make writing both files and steams into packages.
/// </summary>
public static class PackageExtensions
{
/// <summary>
/// Create a package part in the package.
/// </summary>
/// <param name="package">The package.</param>
/// <param name="partUri">Destination Uri of the file in the package.</param>
/// <param name="contentType">Media type of the file.</param>
/// <param name="relationshipType">The relationship of the package part to its parent.</param>
/// <returns>A package part.</returns>
public static PackagePart CreateRelatedPart(this Package package, Uri partUri, string contentType, string relationshipType)
{
Assert.ParamIsNotNull(package, "package");
Assert.ParamIsNotNull(partUri, "partUri");
Assert.ParamIsNotNull(contentType, "contentType");
Assert.ParamIsNotNull(relationshipType, "relationshipType");
partUri = PackUriHelper.CreatePartUri(partUri);
PackagePart part = package.CreatePart(partUri, contentType);
package.CreateRelationship(part.Uri, TargetMode.Internal, relationshipType);
return part;
}
/// <summary>
/// Creates a related part.
/// </summary>
/// <param name="relatedPart">The related part.</param>
/// <param name="partUri">The part URI.</param>
/// <param name="contentType">Type of the content.</param>
/// <param name="relationshipType">Type of the relationship.</param>
/// <returns>A package part.</returns>
public static PackagePart CreateRelatedPart(this PackagePart relatedPart, Uri partUri, string contentType, string relationshipType)
{
Assert.ParamIsNotNull(relatedPart, "relatedPart");
Assert.ParamIsNotNull(partUri, "partUri");
Assert.ParamIsNotNull(contentType, "contentType");
Assert.ParamIsNotNull(relationshipType, "relationshipType");
partUri = PackUriHelper.CreatePartUri(partUri);
PackagePart part = relatedPart.Package.CreatePart(partUri, contentType);
relatedPart.CreateRelationship(part.Uri, TargetMode.Internal, relationshipType);
return part;
}
/// <summary>
/// Gets an existing package part (based on the part uri), or creates it if it doesn't already exist, including a relationship for the part.
/// </summary>
/// <param name="package">A package.</param>
/// <param name="partUri">The target part URI.</param>
/// <param name="contentType">The media type describing the part (used for creation).</param>
/// <param name="relationshipType">The relationship type (used for creating the relationship).</param>
/// <returns>The looked up or created part.</returns>
public static PackagePart GetOrCreateRelatedPart(this Package package, Uri partUri, string contentType, string relationshipType)
{
Assert.ParamIsNotNull(package, "package");
return DoGetOrCreatePart(package, partUri, contentType, relationshipType, null);
}
/// <summary>
/// Gets an existing package part (based on the part uri), or creates it if it doesn't already exist, including a relationship for the part.
/// </summary>
/// <param name="parentPart">A parent part (for creating the relationship).</param>
/// <param name="partUri">The target part URI.</param>
/// <param name="contentType">The media type describing the part (used for creation).</param>
/// <param name="relationshipType">The relationship type (used for creating the relationship).</param>
/// <returns>The looked up or created part.</returns>
public static PackagePart GetOrCreateRelatedPart(this PackagePart parentPart, Uri partUri, string contentType, string relationshipType)
{
Assert.ParamIsNotNull(parentPart, "parentPart");
return DoGetOrCreatePart(parentPart.Package, partUri, contentType, relationshipType, parentPart);
}
/// <summary>
/// Gets an existing package part (based on the part uri), or creates it if it doesn't already exist, including a relationship for the part.
/// </summary>
/// <param name="package">A package.</param>
/// <param name="partUri">The target part URI.</param>
/// <param name="contentType">The media type describing the part (used for creation).</param>
/// <param name="relationshipType">The relationship type (used for creating the relationship).</param>
/// <param name="relatedPart">An optional parent part (for creating the relationship), or <c>null</c> to add a global relationship with the package.</param>
/// <returns>The looked up or created part.</returns>
private static PackagePart DoGetOrCreatePart(Package package, Uri partUri, string contentType, string relationshipType, PackagePart relatedPart)
{
Assert.ParamIsNotNull(package, "package");
Assert.ParamIsNotNull(partUri, "partUri");
Assert.ParamIsNotNull(contentType, "contentType");
Assert.ParamIsNotNull(relationshipType, "relationshipType");
PackagePart result = package.TryGetPart(partUri);
if (result != null)
{
// Found an existing part, at least assert that the content-type is what we expected
Debug.Assert(String.Equals(contentType, result.ContentType), String.Format(CultureInfo.CurrentCulture,
"Unexpected content type for part {0}. Expected {1}, actual was {2}", partUri, contentType, result.ContentType));
}
else if(relatedPart != null)
{
result = relatedPart.CreateRelatedPart(partUri, contentType, relationshipType);
}
else if (relatedPart != null)
{
result = package.CreateRelatedPart(partUri, contentType, relationshipType);
}
return result;
}
/// <summary>
/// Gets a writeable stream for a package part (overwriting the part contents if it already exists).
/// </summary>
/// <param name="part">A part.</param>
/// <returns>A writeable stream for the part.</returns>
public static Stream OpenWrite(this PackagePart part)
{
Assert.ParamIsNotNull(part, "part");
return part.GetStream(FileMode.Create, FileAccess.Write);
}
/// <summary>
/// Opens a read-only stream for a package part..
/// </summary>
/// <param name="part">The part.</param>
/// <returns>The opened stream for reading.</returns>
public static Stream OpenRead(this PackagePart part)
{
Assert.ParamIsNotNull(part, "part");
return part.GetStream(FileMode.Open, FileAccess.Read);
}
/// <summary>
/// Extracts the contents of a package part to an output file.
/// </summary>
/// <param name="part">A part.</param>
/// <param name="outputFile">The output file.</param>
public static void ExtractTo(this PackagePart part, string outputFile)
{
Assert.ParamIsNotNull(outputFile, "outputFile");
using (Stream sourceStream = part.GetStream())
using (Stream outputStream = File.Create(outputFile))
{
sourceStream.CopyTo(outputStream);
}
}
/// <summary>
/// Deletes a package part and all of its relationships and owned parts in a cascading
/// (recursive) fashion.
/// </summary>
/// <param name="rootPart">The root package part to remove.</param>
public static void CascadeDelete(this PackagePart rootPart)
{
Assert.ParamIsNotNull(rootPart, "rootPart");
// Do a breadth first traversal of relationships, avoiding circular loops
Package package = rootPart.Package;
ICollection<PackagePart> partsToRemove = new HashSet<PackagePart>();
Queue<PackagePart> partsToProcess = new Queue<PackagePart>();
partsToProcess.Enqueue(rootPart);
while (partsToProcess.Any())
{
PackagePart part = partsToProcess.Dequeue();
partsToRemove.Add(part);
foreach (PackageRelationship relationship in part.GetRelationships())
{
PackagePart targetPart = relationship.TryGetInternalPart();
if (targetPart != null && !partsToRemove.Contains(targetPart))
{
partsToProcess.Enqueue(targetPart);
}
}
}
foreach (PackagePart part in partsToRemove)
{
package.DeletePart(part.Uri);
}
}
/// <summary>
/// Deletes a relationship and all of its target parts (and relationships) in a cascading
/// (recursive) fashion.
/// </summary>
/// <param name="relationship">A package relationship.</param>
public static void CascadeDeleteRelationship(this Package package, PackageRelationship relationship)
{
Assert.ParamIsNotNull(package, "package");
Assert.ParamIsNotNull(relationship, "relationship");
CascadeDelete(relationship);
package.DeleteRelationship(relationship.Id);
}
/// <summary>
/// Deletes a relationship and all of its target parts (and relationships) in a cascading
/// (recursive) fashion.
/// </summary>
/// <param name="relationship">A package relationship.</param>
public static void CascadeDeleteRelationship(this PackagePart part, PackageRelationship relationship)
{
Assert.ParamIsNotNull(part, "part");
Assert.ParamIsNotNull(relationship, "relationship");
CascadeDelete(relationship);
part.DeleteRelationship(relationship.Id);
}
/// <summary>
/// Deletes all of the related parts of a relationship in a cascading (recursive) fashion.
/// </summary>
/// <param name="relationship"></param>
private static void CascadeDelete(PackageRelationship relationship)
{
PackagePart part = relationship.TryGetInternalPart();
if (part != null)
{
part.CascadeDelete();
}
}
/// <summary>
/// Gets a single relationship by type.
/// </summary>
/// <param name="package">A package.</param>
/// <param name="relationshipType">The relationship type.</param>
/// <returns>The single relationship of that type that was found, or <c>null</c> if none were found.</returns>
public static PackageRelationship GetSingleRelationshipByType(this Package package, string relationshipType)
{
Assert.ParamIsNotNull(package, "package");
Assert.ParamIsNotNull(relationshipType, "relationshipType");
return GetFirstRelationship(package.GetRelationshipsByType(relationshipType), relationshipType);
}
/// <summary>
/// Gets a single relationship by type.
/// </summary>
/// <param name="part">A package part.</param>
/// <param name="relationshipType">The relationship type.</param>
/// <returns>The single relationship of that type that was found, or <c>null</c> if none were found.</returns>
public static PackageRelationship GetSingleRelationshipByType(this PackagePart part, string relationshipType)
{
Assert.ParamIsNotNull(part, "part");
Assert.ParamIsNotNull(relationshipType, "relationshipType");
return GetFirstRelationship(part.GetRelationshipsByType(relationshipType), relationshipType);
}
/// <summary>
/// Gets a single relationship by matching the target URI.
/// </summary>
/// <param name="package">A package.</param>
/// <param name="targetUri">The target URI.</param>
/// <returns>The matching relationship, or <c>null</c> if none found.</returns>
public static PackageRelationship GetSingleRelationshipByTargetUri(this Package package, Uri targetUri)
{
Assert.ParamIsNotNull(package, "package");
Assert.ParamIsNotNull(targetUri, "targetUri");
return package.GetRelationships().FirstOrDefault(rel => rel.TargetUri.Equals(targetUri));
}
/// <summary>
/// Gets a single relationship by matching the target URI.
/// </summary>
/// <param name="part">A package part.</param>
/// <param name="targetUri">The target URI.</param>
/// <returns>The matching relationship, or <c>null</c> if none found.</returns>
public static PackageRelationship GetSingleRelationshipByTargetUri(this PackagePart part, Uri targetUri)
{
Assert.ParamIsNotNull(part, "part");
Assert.ParamIsNotNull(targetUri, "targetUri");
return part.GetRelationships().FirstOrDefault(rel => rel.TargetUri.Equals(targetUri));
}
/// <summary>
/// Gets a single part associated through a given relationship type.
/// </summary>
/// <param name="package">A package.</param>
/// <param name="relationshipType">The relationship type.</param>
/// <returns>The single related part, or <c>null</c> if not found.</returns>
public static PackagePart GetSingleRelatedPart(this Package package, string relationshipType)
{
Assert.ParamIsNotNull(package, "package");
Assert.ParamIsNotNull(relationshipType, "relationshipType");
PackageRelationship relationship = package.GetSingleRelationshipByType(relationshipType);
return (relationship != null) ? relationship.TryGetInternalPart() : null;
}
/// <summary>
/// Gets a single part associated through a given relationship type.
/// </summary>
/// <param name="part">A package part.</param>
/// <param name="relationshipType">The relationship type.</param>
/// <returns>The single related part, or <c>null</c> if not found.</returns>
public static PackagePart GetSingleRelatedPart(this PackagePart part, string relationshipType)
{
Assert.ParamIsNotNull(part, "part");
Assert.ParamIsNotNull(relationshipType, "relationshipType");
PackageRelationship relationship = part.GetSingleRelationshipByType(relationshipType);
return (relationship != null) ? relationship.TryGetInternalPart() : null;
}
/// <summary>
/// Gets the package part of a relationship, if it is internal and it exists.
/// </summary>
/// <param name="relationship">A relationship.</param>
/// <returns>The related part, or <c>null</c> if not internal or doesn't exist.</returns>
public static PackagePart TryGetInternalPart(this PackageRelationship relationship)
{
Assert.ParamIsNotNull(relationship, "relationship");
PackagePart part = null;
if (relationship.TargetMode == TargetMode.Internal)
{
var partUri = PackUriHelper.ResolvePartUri(relationship.SourceUri, relationship.TargetUri);
part = relationship.Package.TryGetPart(partUri);
}
else
{
string message = "Requested part that is not internal for relationship: " + relationship;
Debug.Fail(message);
}
return part;
}
/// <summary>
/// Tries to get a package part, if the uri exists. This is different from GetPart() in that that will
/// throw if the URI doesn't exist.
/// </summary>
/// <param name="package">A package.</param>
/// <param name="partUri">A part uri.</param>
/// <returns>The package part, or <c>null</c> if the URI doesn't exist.</returns>
public static PackagePart TryGetPart(this Package package, Uri partUri)
{
Assert.ParamIsNotNull(package, "package");
Assert.ParamIsNotNull(partUri, "partUri");
PackagePart part = null;
if (package.PartExists(partUri))
{
part = package.GetPart(partUri);
}
return part;
}
/// <summary>
/// Deletes a package part from a given package.
/// </summary>
/// <param name="part">The part.</param>
public static void Delete(this PackagePart part)
{
part.Package.DeletePart(part.Uri);
}
/// <summary>
/// Gets the first relationship in a collection of relationships.
/// </summary>
/// <param name="relationships">A collection of relationships.</param>
/// <param name="relationshipType">The relationship type that was used to query these relationships.</param>
/// <returns>The first relationship (if available) or <c>null</c> if none are available.</returns>
private static PackageRelationship GetFirstRelationship(PackageRelationshipCollection relationships, string relationshipType)
{
int relationShipCount = relationships.Count();
if (relationShipCount > 0)
{
if (relationShipCount != 1)
{
string message = String.Format(CultureInfo.CurrentCulture, "Expected single relationship of type {0}. Instead, we found {1}", relationshipType, relationShipCount);
Debug.Fail(message);
}
return relationships.First();
}
return null;
}
}
}

Просмотреть файл

@ -0,0 +1,818 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.IO
{
/// <summary>
/// Provides utility methods for manipulating file system paths.
/// </summary>
public static class PathUtilities
{
/// <summary>
/// A fully qualified file name length must be less or equal to this value.
/// </summary>
public const int MaxPathLength = 260 - 1; // Remove one character for NULL, this is a legacy string constant from C
/// <summary>
/// A directory name must be less than or equal to this value.
/// </summary>
public const int MaxDirectoryLength = 248 - 1; // Remove one character for NULL, this is a legacy string constant from C
/// <summary>
/// Checks if two filenames are equal.
/// </summary>
/// <param name="filename1">A filename.</param>
/// <param name="filename2">Another filename.</param>
/// <returns><c>true</c> if the filenames are equal.</returns>
public static bool FileNamesAreEqual(string filename1, string filename2)
{
return String.Equals(filename1, filename2, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Checks if two paths are equal.
/// </summary>
/// <param name="path1">A path.</param>
/// <param name="path2">Another path.</param>
/// <returns><c>true</c> if the paths are equal.</returns>
public static bool PathsAreEqual(string path1, string path2)
{
return String.Equals(path1, path2, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Checks if two file extensions are equal.
/// </summary>
/// <param name="extension1">A file extension.</param>
/// <param name="extension2">Another file extension.</param>
/// <returns><c>true</c> if the extensions are equal.</returns>
public static bool ExtensionsAreEqual(string extension1, string extension2)
{
return String.Equals(extension1, extension2, StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// Attempts to find a file in the PATH environment variable.
/// </summary>
/// <param name="filename">The filename.</param>
/// <returns>The full path to the found file, or <c>null</c> if it was not found in any of the folders
/// in the PATH environment variable.</returns>
public static string FindInPath(string filename)
{
string path = Environment.GetEnvironmentVariable("PATH");
if (path != null)
{
var pathTokens = path.Split(Path.PathSeparator).Select(p => p.Trim()).Where(p => !String.IsNullOrEmpty(p));
foreach (string pathEntry in pathTokens)
{
string fullPath = Path.Combine(pathEntry, filename);
if (File.Exists(fullPath))
{
return fullPath;
}
}
}
// Not found
return null;
}
/// <summary>
/// Converts an arbitrary string name to a valid filename by trimming or replacing invalid characters.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="replacement">An optional replacement character (none by default, invalid characters will be removed).</param>
/// <returns>A valid filename to use for saving to a file.</returns>
public static string ToValidFileName(string name, char replacement = (char) 0)
{
Assert.ParamIsNotNull(name, "name");
var invalidChars = Path.GetInvalidFileNameChars();
StringBuilder sb = new StringBuilder(name);
for (int i = 0; i < sb.Length; i++)
{
if (invalidChars.Contains(sb[i]))
{
sb.Remove(i, 1);
if (replacement > 0)
{
sb.Insert(i, replacement);
}
else
{
i--;
}
}
}
if (name.Length > 0 && sb.Length == 0)
{
// TODO: All characters were trimmed, how do we make this a valid filename? Arbitrarily assign some value?
}
return sb.ToString();
}
/// <summary>
/// Gets a unique temporary filename in the current user's temporary folder.
/// </summary>
/// <param name="preferredName">An otional preferred name for the file (<c>null</c> by default, which generates a random name).</param>
/// <returns>The unique or random filename under the current user's temporary folder.</returns>
public static string GetTempFilename(string preferredName = null)
{
return GetUniqueOrRandomFilename(Path.GetTempPath(), preferredName);
}
/// <summary>
/// Gets a unique or random filename under a given parent path.
/// </summary>
/// <param name="parentPath">The parent path.</param>
/// <param name="preferredName">An otional preferred name for the file (<c>null</c> by default, which generates a random name).</param>
/// <returns>The unique or random filename under a given directory.</returns>
public static string GetUniqueOrRandomFilename(string parentPath, string preferredName = null)
{
Assert.ParamIsNotNullOrEmpty(parentPath, "parentPath");
if (preferredName == null)
{
preferredName = Path.GetRandomFileName();
}
string path = Path.Combine(parentPath, preferredName);
// Use a padding in case the name is made unique further down, where e.g. " (17)" is appended (giving ourselves a 5 char buffer)
int additionalPadding = 5;
int excessLength = (path.Length + additionalPadding) - MaxPathLength;
if (excessLength > 0)
{
bool trimSucceeded = false;
string baseName = Path.GetFileNameWithoutExtension(preferredName);
if (baseName.Length > excessLength)
{
// We can trim the base filename (keeping the extension as is) to a safer full path length
baseName = baseName.Substring(0, baseName.Length - excessLength).TrimEnd();
if (baseName.Length > 0)
{
string extension = Path.GetExtension(preferredName);
path = Path.Combine(parentPath, baseName + extension);
trimSucceeded = true;
}
}
if (!trimSucceeded)
{
Log.WarnAndBreak("Could not trim path length to fit within valid length, directory name was too long: {0}", path);
}
}
path = EnsureFilenameIsUnique(path);
return path;
}
/// <summary>
/// Returns a unique filename that doesn't exist in the given path,
/// by appending an incremented number to the filename (without the
/// extension).
/// </summary>
/// <param name="path">An initial path.</param>
/// <returns>A unique filename path derived from the input.</returns>
public static string EnsureFilenameIsUnique(string path)
{
Assert.ParamIsNotNullOrEmpty(path, "path");
if (!Exists(path))
{
return path;
}
string name = Path.GetFileNameWithoutExtension(path);
string extension = Path.GetExtension(path);
string dir = Path.GetDirectoryName(path);
int increment = 1;
do
{
increment++;
string newName = String.Format("{0} ({1}){2}", name, increment, extension);
// TODO: Need to make sure path did not exceed max path length.
path = Path.Combine(dir, newName);
}
while (Exists(path));
return path;
}
/// <summary>
/// Determines whether the specified path exists (as a file or directory).
/// </summary>
/// <param name="path">The path.</param>
/// <returns><c>true</c> if the path exists; <c>false</c> if otherwise.</returns>
public static bool Exists(string path)
{
Assert.ParamIsNotNullOrEmpty(path, "path");
return File.Exists(path) || Directory.Exists(path);
}
/// <summary>
/// Tries to delete a file or folder.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="mode">The deletion mode.</param>
/// <returns><c>true</c> if th edeletion was successfull or there was nothign to delete (the file didn't exist). <c>false</c> if the deletion failed.</returns>
public static bool TryDelete(string path, DeleteMode mode = DeleteMode.None)
{
Assert.ParamIsNotNullOrEmpty(path, "path");
try
{
if (File.Exists(path))
{
File.Delete(path);
}
else if (Directory.Exists(path))
{
DeleteRecursively(path, mode);
}
return true;
}
catch (Exception e)
{
Log.ErrorAndBreak(e, "Error attempting to delete file or folder with path: " + path);
}
return false;
}
/// <summary>
/// Deletes a directory recursively.
/// </summary>
/// <param name="path">The path.</param>
/// <param name="mode">The deletion mode.</param>
public static void DeleteRecursively(string path, DeleteMode mode = DeleteMode.None)
{
Assert.ParamIsNotNullOrEmpty(path, "path");
DeleteRecursively(new DirectoryInfo(path), mode);
}
/// <summary>
/// Recursively deletes a directory.
/// </summary>
/// <param name="directory">The base directory.</param>
public static void DeleteRecursively(DirectoryInfo directory, DeleteMode mode = DeleteMode.None)
{
Assert.ParamIsNotNull(directory, "directory");
DeleteContents(directory, mode);
bool force = (mode & DeleteMode.Force) == DeleteMode.Force;
try
{
if (force)
{
directory.Attributes &= ~FileAttributes.ReadOnly;
}
directory.Delete();
}
catch (IOException e)
{
throw new IOException("Couldn't delete " + directory.FullName, e);
}
}
/// <summary>
/// Deletes the contents of a given directory (but not the directory itself).
/// </summary>
/// <param name="path">The path.</param>
/// <param name="mode">The deletion mode.</param>
public static void DeleteContents(string path, DeleteMode mode = DeleteMode.None)
{
Assert.ParamIsNotNullOrEmpty(path, "path");
DeleteContents(new DirectoryInfo(path), mode);
}
/// <summary>
/// Deletes the contents of a given directory (but not the directory itself).
/// </summary>
/// <param name="path">The path.</param>
/// <param name="mode">The deletion mode.</param>
public static void DeleteContents(DirectoryInfo directory, DeleteMode mode = DeleteMode.None)
{
Assert.ParamIsNotNull(directory, "directory");
foreach (DirectoryInfo subDirectory in directory.GetDirectories())
DeleteRecursively(subDirectory, mode);
bool force = (mode & DeleteMode.Force) == DeleteMode.Force;
foreach (FileInfo file in directory.GetFiles())
{
try
{
if (force)
{
file.Attributes &= ~FileAttributes.ReadOnly;
}
file.Delete();
}
catch (IOException e)
{
throw new IOException("Couldn't delete " + file.FullName, e);
}
}
}
/// <summary>
/// Copies a directory recursively.
/// </summary>
/// <param name="sourceDirectory">The source directory.</param>
/// <param name="targetDirectory">The target directory.</param>
public static void CopyRecursively(string sourceDirectory, string targetDirectory)
{
Assert.ParamIsNotNullOrEmpty(sourceDirectory, "sourceDirectory");
Assert.ParamIsNotNullOrEmpty(targetDirectory, "targetDirectory");
if (!Directory.Exists(sourceDirectory))
{
throw new DirectoryNotFoundException("Invalid source directory " + sourceDirectory);
}
if (!Directory.Exists(targetDirectory))
{
Directory.CreateDirectory(targetDirectory);
}
string[] sources = Directory.GetFileSystemEntries(sourceDirectory);
foreach (string source in sources)
{
string target = Path.Combine(targetDirectory, Path.GetFileName(source));
if (File.Exists(source))
{
File.Copy(source, target, true);
}
else if (Directory.Exists(source))
{
CopyRecursively(source, target);
}
}
}
/// <summary>
/// Ensures the given directory exists, and creates it if it doesn't.
/// </summary>
/// <param name="path">The path.</param>
public static void EnsureDirectoryExists(string path)
{
Assert.ParamIsNotNullOrEmpty(path, "path");
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
}
/// <summary>
/// Ensures the parent directory of the given path exists, and creates it if it doesn't.
/// </summary>
/// <param name="path">The path.</param>
public static void EnsureParentDirectoryExists(string path)
{
Assert.ParamIsNotNullOrEmpty(path, "path");
EnsureDirectoryExists(Path.GetDirectoryName(path));
}
/// <summary>
/// Ensures that a file exists, or creates a 0-byte file if it doesn't.
/// </summary>
/// <param name="path">The path.</param>
public static void EnsureFileExists(string path)
{
Assert.ParamIsNotNullOrEmpty(path, "path");
if (!File.Exists(path))
{
EnsureParentDirectoryExists(path);
File.WriteAllBytes(path, new byte[0]);
}
}
/// <summary>
/// Ensures that a file path is writeable. If the file exists and is read-only,
/// it will be made writeable. Otherwise, we ensure that its parent directory
/// exists.
/// </summary>
/// <param name="filename">The filename that will be written to.</param>
public static void EnsureFileIsWriteable(string filename)
{
Assert.ParamIsNotNullOrEmpty(filename, "filename");
if (File.Exists(filename))
{
// Ensure the file is not read-only
FileAttributes attributes = File.GetAttributes(filename);
if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
{
attributes &= ~FileAttributes.ReadOnly;
File.SetAttributes(filename, attributes);
}
}
else
{
EnsureParentDirectoryExists(filename);
}
}
/// <summary>
/// Returns the path of the given full path relative to a base path.
/// </summary>
/// <param name="basePath">The base path.</param>
/// <param name="fullPath">The full path.</param>
/// <returns>The path of the given full path relative to a base path.</returns>
public static string GetRelativePath(string basePath, string fullPath)
{
Assert.ParamIsNotNullOrEmpty(basePath, "basePath");
Assert.ParamIsNotNullOrEmpty(fullPath, "fullPath");
if (!Path.IsPathRooted(basePath))
{
throw new ArgumentException("Base path " + basePath + " is not rooted");
}
if (!Path.IsPathRooted(fullPath))
{
throw new ArgumentException("Full path " + fullPath + " is not rooted");
}
if (!fullPath.StartsWith(basePath, StringComparison.InvariantCultureIgnoreCase))
{
throw new ArgumentException("Full path " + fullPath + " is not a descendant of " + basePath);
}
return fullPath.Substring(basePath.Length).TrimStart(Path.DirectorySeparatorChar);
}
/// <summary>
/// Finds a set of files and directories matching the specified search pattern.
/// </summary>
/// <param name="searchPattern">The search string to match against the names of files.
/// Can include the following wildcards: ..., *, ?.</param>
/// <param name="baseDirectory">The base directory to start the search from (Optional). If
/// the search pattern defines a root path, this parameter is ignored. If <c>null</c>,
/// then the current directory will be used.</param>
/// <returns>
/// A collection of the files and directories matching the search pattern.
/// </returns>
/// <remarks>
/// <para>The following wildcards are permitted in the search pattern:</para>
/// <list>
/// <item>*: Matches zero or more characters</item>
/// <item>?: Exactly one character</item>
/// <item>...: Search in all subdirectories</item>
/// </list>
/// <para>If the search pattern does not define a root path, then the current directory
/// will be the starting point of the search.</para>
/// </remarks>
public static ICollection<string> FindFileSystemEntries(string searchPattern, string baseDirectory = null)
{
Assert.ParamIsNotNullOrEmpty(searchPattern, "searchPattern");
return Find(searchPattern, SearchType.FilesAndDirectories, baseDirectory);
}
/// <summary>
/// Finds a set of directories matching the specified search pattern.
/// </summary>
/// <param name="searchPattern">The search string to match against the names of directories.
/// Can include the following wildcards: ..., *, ?.</param>
/// <param name="baseDirectory">The base directory to start the search from (Optional). If
/// the search pattern defines a root path, this parameter is ignored. If <c>null</c>,
/// then the current directory will be used.</param>
/// <returns>A collection of the directories matching the search pattern.</returns>
/// <remarks>
/// <para>The following wildcards are permitted in the search pattern:</para>
/// <list>
/// <item>*: Matches zero or more characters</item>
/// <item>?: Exactly one character</item>
/// <item>...: Search in all subdirectories</item>
/// </list>
/// <para>If the search pattern does not define a root path, then the current directory
/// will be the starting point of the search.</para>
/// </remarks>
public static ICollection<string> FindDirectories(string searchPattern, string baseDirectory = null)
{
Assert.ParamIsNotNullOrEmpty(searchPattern, "searchPattern");
return Find(searchPattern, SearchType.Directories, baseDirectory);
}
/// <summary>
/// Finds a set of files matching the specified search pattern.
/// </summary>
/// <param name="searchPattern">The search string to match against the names of files.
/// Can include the following wildcards: ..., *, ?.</param>
/// <param name="baseDirectory">The base directory to start the search from (Optional). If
/// the search pattern defines a root path, this parameter is ignored. If <c>null</c>,
/// then the current directory will be used.</param>
/// <returns>A collection of the files matching the search pattern.</returns>
/// <remarks>
/// <para>The following wildcards are permitted in the search pattern:</para>
/// <list>
/// <item>*: Matches zero or more characters</item>
/// <item>?: Exactly one character</item>
/// <item>...: Search in all subdirectories</item>
/// </list>
/// <para>If the search pattern does not define a root path, then the current directory
/// will be the starting point of the search.</para>
/// </remarks>
public static ICollection<string> FindFiles(string searchPattern, string baseDirectory = null)
{
Assert.ParamIsNotNullOrEmpty(searchPattern, "searchPattern");
return Find(searchPattern, SearchType.Files, baseDirectory);
}
/// <summary>
/// Finds a set of files and/or directories matching the specified search pattern.
/// </summary>
/// <param name="searchPattern">The search string to match against the names of files.
/// Can include the following wildcards: ..., *, ?.</param>
/// <param name="searchType">Defines the type of file system entry being searched for.</param>
/// <param name="baseDirectory">The base directory to start the search from (Optional). If
/// the search pattern defines a root path, this parameter is ignored. If <c>null</c>,
/// then the current directory will be used.</param>
/// <returns>
/// A collection of the files and directories matching the search pattern.
/// </returns>
/// <remarks>
/// <para>The following wildcards are permitted in the search pattern:</para>
/// <list>
/// <item>*: Matches zero or more characters</item>
/// <item>?: Exactly one character</item>
/// <item>...: Search in all subdirectories</item>
/// </list>
/// <para>If the search pattern does not define a root path, then the current directory
/// will be the starting point of the search.</para>
/// </remarks>
private static ICollection<string> Find(string searchPattern, SearchType searchType, string baseDirectory)
{
// First expand any environment variable definition in the search pattern.
searchPattern = Environment.ExpandEnvironmentVariables(searchPattern);
if (baseDirectory == null)
{
baseDirectory = Environment.CurrentDirectory;
}
if (!ContainsWildcards(searchPattern))
{
IList<string> result = new List<string>();
// No wildcards, optimized to search for an absolut or relative path
string fullPath = Path.Combine(baseDirectory, searchPattern);
if (PathMatches(fullPath, searchType))
{
result.Add(Path.GetFullPath(fullPath));
}
return result;
}
else
{
// The pattern contains wildcards, tokenize and resolve each level...
ICollection<string> currentLevel = new List<string>();
ICollection<string> nextLevel = new List<string>();
// Figure out if the search pattern defines a root, otherwise we need to use the
// base directory as the starting point
string root = Path.GetPathRoot(searchPattern);
if (!String.IsNullOrEmpty(root))
{
searchPattern = searchPattern.Substring(root.Length);
}
else
{
root = baseDirectory;
}
// Push the root as the current level of the search
currentLevel.Add(root);
// Split the pattern into each directory level (RemoveEmptyEntries also cleans up
// two or more contiguos directory separators, e.g. c:\foo\\bar, as well as any
// starting or ending separator).
string[] tokens = searchPattern.Split(new char[] { Path.DirectorySeparatorChar },
StringSplitOptions.RemoveEmptyEntries);
// For each token we have, will we have base paths to search from
for (int i = 0; i < tokens.Length && currentLevel.Count > 0; i++)
{
string token = tokens[i];
bool isLastToken = (i == tokens.Length - 1);
// Search for directories with every token, except for the last. At that point
// we need to return the search type passed as an argument to the method
SearchType currentSearchType = (isLastToken) ? searchType : SearchType.Directories;
currentLevel = GetDescendants(currentLevel, token, currentSearchType);
}
// At the end of the loops, the current level will contain the result
return currentLevel;
}
}
/// <summary>
/// Determines whether the specified value contains wildcards.
/// </summary>
/// <param name="value">The value.</param>
/// <returns>
/// <c>true</c> if the specified value contains wildcards; otherwise, <c>false</c>.
/// </returns>
private static bool ContainsWildcards(string value)
{
return value.Contains("?") || value.Contains("*") || value.Contains("...");
}
/// <summary>
/// Gets the direct descendants of a given set of base paths that match a given search pattern.
/// If the recursive wildcard (...) is used, then all descendants are searched for, not only the
/// direct ones.
/// </summary>
/// <param name="basePaths">The base paths that will be searched.</param>
/// <param name="searchPattern">The search pattern.</param>
/// <param name="searchType">Defines the type of file system entry being searched for.</param>
/// <returns>A collection of matching files/directories for all the input base paths.</returns>
private static ICollection<string> GetDescendants(ICollection<string> basePaths, string searchPattern, SearchType searchType)
{
List<string> results = new List<string>();
bool patternHasWildcards = ContainsWildcards(searchPattern);
foreach (string basePath in basePaths)
{
if (!Directory.Exists(basePath))
{
continue;
}
if (patternHasWildcards)
{
results.AddRange(GetDescendants(basePath, searchPattern, searchType));
}
else
{
string next = Path.Combine(basePath, searchPattern);
if (PathMatches(next, searchType))
{
results.Add(next);
}
}
}
return results;
}
/// <summary>
/// Gets the direct descendants of a given set base path that match a given search pattern.
/// If the recursive wildcard (...) is used, then all descendants are searched for, not only the
/// direct ones.
/// </summary>
/// <param name="path">The starting base path.</param>
/// <param name="searchPattern">The search pattern.</param>
/// <param name="searchType">Defines the type of file system entry being searched for.</param>
/// <returns>A collection of matching files/directories for the input base path.</returns>
private static string[] GetDescendants(string path, string searchPattern, SearchType searchType)
{
try
{
// Recursive wildcard
if (searchPattern.Equals("..."))
{
if (searchType == SearchType.Directories)
{
return Directory.GetDirectories(path, "*", SearchOption.AllDirectories);
}
else if (searchType == SearchType.Files)
{
return Directory.GetFiles(path, "*", SearchOption.AllDirectories);
}
// KLUDGE: Directory doesn't provide a Directory.GetFileSystemEntries() that
// has a 3rd parameter. Emulate it on our own...
string[] dirs = Directory.GetDirectories(path, "*", SearchOption.AllDirectories);
string[] files = Directory.GetFiles(path, "*", SearchOption.AllDirectories);
return LightMerge(dirs, files);
}
else
{
if (searchType == SearchType.Directories)
{
return Directory.GetDirectories(path, searchPattern);
}
else if (searchType == SearchType.Files)
{
return Directory.GetFiles(path, searchPattern);
}
return Directory.GetFileSystemEntries(path, searchPattern);
}
}
catch (IOException) { }
catch (UnauthorizedAccessException) { }
// If we got here, there was an IO error and an access control error,
// return 0 results...
return new string[0];
}
/// <summary>
/// Merges two arrays in an optimized way when one of the arrays is of zero length.
/// If arrays need to be merged, then the result will also be sorted.
/// </summary>
/// <param name="array1">One array.</param>
/// <param name="array2">Another array.</param>
/// <returns>The resulting array (will be one of the input arrays if the other
/// was empty).</returns>
private static string[] LightMerge(string[] array1, string[] array2)
{
if (array1.Length == 0)
{
return array2;
}
if (array2.Length == 0)
{
return array1;
}
string[] result = new string[array1.Length + array2.Length];
array1.CopyTo(result, 0);
array2.CopyTo(result, array1.Length);
Array.Sort<string>(result);
return result;
}
/// <summary>
/// Determines if a given path matches a given search type (if it is an existing file
/// or directory).
/// </summary>
/// <param name="path">The path.</param>
/// <param name="searchType">Defines the type of file system entry being searched for.</param>
/// <returns><c>true</c> if the path matches the search type; otherwise <c>false</c>.</returns>
private static bool PathMatches(string path, SearchType searchType)
{
switch (searchType)
{
case SearchType.Directories:
return Directory.Exists(path);
case SearchType.Files:
return File.Exists(path);
case SearchType.FilesAndDirectories:
return Directory.Exists(path) || File.Exists(path);
}
throw new InvalidOperationException("Unrecognized search type: " + searchType);
}
/// <summary>
/// Defines constants for scoping a search for files only, directories only,
/// or both.
/// </summary>
private enum SearchType
{
Files, Directories, FilesAndDirectories
}
}
/// <summary>
/// Affects how file and directory deletions occur.
/// </summary>
[Flags]
public enum DeleteMode
{
None,
/// <summary>
/// Force deletes read-only files by changing their bit before deleting.
/// </summary>
Force = 0x01
}
}

Просмотреть файл

@ -0,0 +1,148 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics;
using System;
using System.Diagnostics;
using System.IO;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.IO
{
/// <summary>
/// A class to manage the creation and disposal of temporary directories.
/// </summary>
public class TempDirectory : IDisposable
{
private string path;
private bool disposed;
/// <summary>
/// Creates a temporary directory for the current process (based on the process name).
/// </summary>
/// <returns>The temporary directory.</returns>
public static TempDirectory CreateForProcess()
{
Process process = Process.GetCurrentProcess();
string folderName = String.Format("{0}.{1}", System.IO.Path.GetFileNameWithoutExtension(process.ProcessName), process.Id);
folderName = PathUtilities.ToValidFileName(folderName);
string path = PathUtilities.GetUniqueOrRandomFilename(System.IO.Path.GetTempPath(), folderName);
return new TempDirectory(path);
}
/// <summary>
/// Creates a temporary directory in the TEMP directory, with an optional preferred name.
/// </summary>
/// <param name="preferredName">An optional preferred name.</param>
/// <returns>The temporary directory.</returns>
public static TempDirectory CreateInTempPath(string preferredName = null)
{
string path = PathUtilities.GetTempFilename(preferredName);
return new TempDirectory(path);
}
/// <summary>
/// Initializes a new instance of the <see cref="TempDirectory"/> class.
/// </summary>
/// <param name="path">The path of the temporary directory.</param>
/// <param name="createImmediately">if set to <c>true</c>, creates the directory immediately. Otherwise, the directory is created later on demand.</param>
public TempDirectory(string path, bool createImmediately = true)
{
Assert.ParamIsNotNullOrEmpty(path, "path");
this.path = path;
if (createImmediately)
{
EnsureIsCreated();
}
}
/// <summary>
/// Creates a temporary sub directory.
/// </summary>
/// <param name="preferredName">An optional preferred name..</param>
/// <param name="createImmediately">if set to <c>true</c>, creates the directory immediately. Otherwise, the directory is created later on demand.</param>
/// <returns></returns>
public TempDirectory CreateTempSubDirectory(string preferredName = null, bool createImmediately = true)
{
return new TempDirectory(GetUniqueOrRandomFilename(preferredName), createImmediately);
}
/// <summary>
/// Ensures that the temporary directory has been created (used when the instance was created with createImmediately = false).
/// </summary>
public void EnsureIsCreated()
{
PathUtilities.EnsureDirectoryExists(this.path);
}
/// <summary>
/// Gets the path to the temp directory.
/// </summary>
public string Path
{
get { return this.path; }
}
/// <summary>
/// Gets a unique or random filename in the temp directory.
/// </summary>
/// <param name="preferredName">An optional preferred name.</param>
/// <returns>The file path.</returns>
public string GetUniqueOrRandomFilename(string preferredName = null)
{
return PathUtilities.GetUniqueOrRandomFilename(this.path, preferredName);
}
/// <summary>
/// Deletes the directory and all of its contents.
/// </summary>
public void Delete()
{
if (Directory.Exists(this.path))
{
PathUtilities.DeleteRecursively(this.path, DeleteMode.Force);
}
}
/// <summary>
/// Deletes the directory contents..
/// </summary>
public void DeleteContents()
{
PathUtilities.DeleteContents(this.path, DeleteMode.Force);
}
/// <summary>
/// Attempts to delete the directory and all of its contents.
/// </summary>
/// <returns><c>true</c> if the directory was succesfully deleted.</returns>
public bool TryDelete()
{
return PathUtilities.TryDelete(this.path);
}
/// <summary>
/// Returns a <see cref="System.String" /> that represents this instance.
/// </summary>
/// <returns>
/// A <see cref="System.String" /> that represents this instance.
/// </returns>
public override string ToString()
{
return this.path;
}
#region IDisposable Members
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
if (!this.disposed)
{
Delete();
this.disposed = true;
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,70 @@
using Microsoft.Internal.Tools.TeamMate.Foundation.Diagnostics;
using System;
using System.IO;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.IO
{
/// <summary>
/// Manages the creation and deletion of temporary files.
/// </summary>
public class TempFile : IDisposable
{
private string path;
private bool disposed;
/// <summary>
/// Creates a temporary file in the TEMP folder, with an optional preferred name.
/// </summary>
/// <param name="preferredName">An optional preferred name.</param>
/// <returns>The temporary file.</returns>
public static TempFile Create(string preferredName = null)
{
string path = PathUtilities.GetTempFilename(preferredName);
return new TempFile(path);
}
internal TempFile(string path)
{
Assert.ParamIsNotNullOrEmpty(path, "path");
// Make sure file exists
PathUtilities.EnsureFileExists(path);
this.path = path;
}
/// <summary>
/// Gets the file path.
/// </summary>
public string Path
{
get { return this.path; }
}
/// <summary>
/// Deletes temporary file if it exists.
/// </summary>
public void Delete()
{
if (File.Exists(this.path))
{
File.Delete(this.path);
}
}
#region IDisposable Members
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
if (!this.disposed)
{
Delete();
this.disposed = true;
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,38 @@
using System;
namespace Microsoft.Internal.Tools.TeamMate.Foundation
{
public class LazyWeakReference<T> where T : class
{
private Func<T> valueFactory;
private WeakReference weakRefence = new WeakReference(null);
public LazyWeakReference(Func<T> valueFactory)
{
this.valueFactory = valueFactory;
}
public T Value
{
get
{
T result = (T)weakRefence.Target;
if (result == null)
{
result = valueFactory();
weakRefence.Target = result;
}
return result;
}
}
public bool IsValueCreated
{
get
{
return weakRefence != null && weakRefence.IsAlive;
}
}
}
}

Просмотреть файл

@ -0,0 +1,418 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), Build\Microsoft.Internal.Tools.TeamMate.Settings.targets))\Build\Microsoft.Internal.Tools.TeamMate.Settings.targets" />
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<ProductVersion>9.0.30729</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{1967369E-0368-4888-B743-B16ABAE28B1F}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Microsoft.Internal.Tools.TeamMate.Foundation</RootNamespace>
<AssemblyName>Microsoft.Internal.Tools.TeamMate.Foundation</AssemblyName>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Data" />
<Reference Include="System.DirectoryServices" />
<Reference Include="System.Drawing" />
<Reference Include="System.Management" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq">
<RequiredTargetFramework>3.5</RequiredTargetFramework>
</Reference>
<Reference Include="System.Xml" />
<Reference Include="UIAutomationProvider" />
<Reference Include="WindowsBase" />
<Reference Include="WindowsFormsIntegration" />
</ItemGroup>
<ItemGroup>
<Compile Include="AbsoluteUriComparer.cs" />
<Compile Include="Chaos\ChaosException.cs" />
<Compile Include="Chaos\ChaosMonkey.cs" />
<Compile Include="Chaos\ChaosScenario.cs" />
<Compile Include="Collections\CollectionExtensions.cs" />
<Compile Include="Collections\CollectionUtilities.cs" />
<Compile Include="CommandLine\CommandBase.cs" />
<Compile Include="CommandLine\CommandLineArgumentException.cs" />
<Compile Include="CommandLine\CommandLineArgumentParser.cs" />
<Compile Include="CommandLine\CommandLineTool.cs" />
<Compile Include="CommandLine\ICommand.cs" />
<Compile Include="ComponentModel\ComponentModelExtensions.cs" />
<Compile Include="ComponentModel\ObservableObjectBase.cs" />
<Compile Include="ConsoleUtilities.cs" />
<Compile Include="DateTimeExtensions.cs" />
<Compile Include="DeferredAction.cs" />
<Compile Include="DelegateDisposable.cs" />
<Compile Include="Diagnostics\Assert.cs" />
<Compile Include="Diagnostics\CommandLineBuilder.cs" />
<Compile Include="Diagnostics\Log.cs" />
<Compile Include="Diagnostics\EventInfo.cs" />
<Compile Include="Diagnostics\ProcessExtensions.cs" />
<Compile Include="Diagnostics\SystemInfo.cs" />
<Compile Include="Diagnostics\DiagnosticsSerializer.cs" />
<Compile Include="Diagnostics\Telemetry.cs" />
<Compile Include="Diagnostics\TelemetryEventProperties.cs" />
<Compile Include="Diagnostics\TelemetryListener.cs" />
<Compile Include="Diagnostics\TraceLogFile.cs" />
<Compile Include="DirectoryServices\DirectoryBrowser.cs" />
<Compile Include="DirectoryServices\DirectoryUtilities.cs" />
<Compile Include="DirectoryServices\UserEntry.cs" />
<Compile Include="ConvertUtilities.cs" />
<Compile Include="Diagnostics\Reports\Attachment.cs" />
<Compile Include="Diagnostics\Reports\ErrorReport.cs" />
<Compile Include="Diagnostics\ExceptionInfo.cs" />
<Compile Include="Diagnostics\Reports\FeedbackReport.cs" />
<Compile Include="Diagnostics\Reports\ReportSerializer.cs" />
<Compile Include="Diagnostics\Reports\UserReportBase.cs" />
<Compile Include="FormatUtilities.cs" />
<Compile Include="IO\IOExtensions.cs" />
<Compile Include="IO\Packaging\PackageExtensions.cs" />
<Compile Include="IO\PathUtilities.cs" />
<Compile Include="IO\TempDirectory.cs" />
<Compile Include="IO\TempFile.cs" />
<Compile Include="LazyWeakReference.cs" />
<Compile Include="Native\ComCtl32.cs" />
<Compile Include="Native\ComImports.cs" />
<Compile Include="Native\Clr.cs" />
<Compile Include="Native\DwmApi.cs" />
<Compile Include="Native\Enums.cs" />
<Compile Include="Native\Gdi32.cs" />
<Compile Include="Native\Kernel32.cs" />
<Compile Include="Native\Ole32.cs" />
<Compile Include="Native\OleAut32.cs" />
<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" />
<Compile Include="Native\User32.cs" />
<Compile Include="Native\WtsApi32.cs" />
<Compile Include="Net\Mime\MimeTypes.cs" />
<Compile Include="ObjectUtilities.cs" />
<Compile Include="PredicateUtilities.cs" />
<Compile Include="Reflection\ReflectionExtensions.cs" />
<Compile Include="Reflection\ReflectionUtilities.cs" />
<Compile Include="Resources\ResourceStrings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>ResourceStrings.resx</DependentUpon>
</Compile>
<Compile Include="Resources\FoundationResources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>FoundationResources.resx</DependentUpon>
</Compile>
<Compile Include="Runtime\InteropServices\InteropUtilities.cs" />
<Compile Include="Runtime\InteropServices\RetryMessageFilterScope.cs" />
<Compile Include="Runtime\InteropServices\RetryMesssageFillter.cs" />
<Compile Include="Runtime\Serialization\SerializationUtilities.cs" />
<Compile Include="ServiceModel\WcfClientProxy.cs" />
<Compile Include="Shell\ApplicationRegistrationServices.cs" />
<Compile Include="Shell\ExternalWebBrowser.cs" />
<Compile Include="Shell\SessionNotificationHelper.cs" />
<Compile Include="Shell\ShortcutUtilities.cs" />
<Compile Include="Shell\WndProcHelper.cs" />
<Compile Include="StringExtensions.cs" />
<Compile Include="StringUtilities.cs" />
<Compile Include="SystemExtensions.cs" />
<Compile Include="Text\CsvReader.cs" />
<Compile Include="Text\CsvWriter.cs" />
<Compile Include="Text\RtfUtilities.cs" />
<Compile Include="Threading\ITaskContext.cs" />
<Compile Include="Threading\LinearRegression.cs" />
<Compile Include="Threading\SingleTaskRunner.cs" />
<Compile Include="Threading\TaskContext.cs" />
<Compile Include="Threading\TaskUtilities.cs" />
<Compile Include="TimeSpanExtensions.cs" />
<Compile Include="UriUtilities.cs" />
<Compile Include="Validation\DefaultValidations.cs" />
<Compile Include="Validation\FluentUtilities.cs" />
<Compile Include="Validation\IValidationRule.cs" />
<Compile Include="Validation\PropertyValidator.cs" />
<Compile Include="Validation\PropertyValidatorContext.cs" />
<Compile Include="Validation\ValidationRule.cs" />
<Compile Include="Windows\ClipboardUtilities.cs" />
<Compile Include="Windows\Controls\Data\CompoundFilter.cs" />
<Compile Include="Windows\Controls\Data\GroupNameConverter.cs" />
<Compile Include="Windows\Controls\Data\ISelectableItem.cs" />
<Compile Include="Windows\Controls\Data\ListFieldInfo.cs" />
<Compile Include="Windows\Controls\Data\ListViewFilter.cs" />
<Compile Include="Windows\Controls\FontIcon.cs" />
<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" />
<Compile Include="Windows\Controls\TreeItemViewModelBase.cs" />
<Compile Include="Windows\Converters\BrushLuminosityConverter.cs" />
<Compile Include="Windows\Converters\EnumDisplayStringConverter.cs" />
<Compile Include="Windows\Converters\RemainingTimeConverter.cs" />
<Compile Include="Windows\Converters\StaticMapConverter.cs" />
<Compile Include="Windows\DelegateFactory.cs" />
<Compile Include="Windows\HslColor.cs" />
<Compile Include="Windows\Input\CommandDictionary.cs" />
<Compile Include="Windows\Media\Effects\GrayscaleEffect.cs" />
<Compile Include="Windows\MVVM\IGlobalCommandProvider.cs" />
<Compile Include="Windows\MVVM\ValidatableViewModelBase.cs" />
<Compile Include="Validation\ValidationContext.cs" />
<Compile Include="Validation\ValidationFailure.cs" />
<Compile Include="Validation\ValidationResult.cs" />
<Compile Include="Validation\PropertyValidationRule.cs" />
<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" />
<Compile Include="Windows\Controls\BusySpinner.xaml.cs">
<DependentUpon>BusySpinner.xaml</DependentUpon>
</Compile>
<Compile Include="Windows\Controls\ButtonPanel.cs" />
<Compile Include="Windows\Controls\Callout.cs" />
<Compile Include="Windows\Controls\ControlResources.cs" />
<Compile Include="Windows\Controls\Data\GroupingViewUtilities.cs" />
<Compile Include="Windows\Controls\Data\ListView.cs" />
<Compile Include="Windows\Controls\Data\ListViewModel.cs" />
<Compile Include="Windows\Controls\DialogPanel.cs" />
<Compile Include="Windows\Controls\ExceptionDialog.xaml.cs">
<DependentUpon>ExceptionDialog.xaml</DependentUpon>
</Compile>
<Compile Include="Windows\Controls\FileBrowser.xaml.cs">
<DependentUpon>FileBrowser.xaml</DependentUpon>
</Compile>
<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>
<Compile Include="Windows\Controls\ProgressIndicator.xaml.cs">
<DependentUpon>ProgressIndicator.xaml</DependentUpon>
</Compile>
<Compile Include="Windows\Controls\ProgressRing.xaml.cs">
<DependentUpon>ProgressRing.xaml</DependentUpon>
</Compile>
<Compile Include="Windows\Controls\Transition.cs" />
<Compile Include="Windows\Controls\TransitionControl.xaml.cs">
<DependentUpon>TransitionControl.xaml</DependentUpon>
</Compile>
<Compile Include="Windows\Controls\VideoPlayer.xaml.cs">
<DependentUpon>VideoPlayer.xaml</DependentUpon>
</Compile>
<Compile Include="Windows\Converters\BooleanConverter.cs" />
<Compile Include="Windows\Converters\Converters.cs" />
<Compile Include="Windows\Converters\DateGroupingConverter.cs" />
<Compile Include="Windows\Converters\PercentageConverter.cs" />
<Compile Include="Windows\Converters\OneWayConverterBase.cs" />
<Compile Include="Windows\Converters\StringConverter.cs" />
<Compile Include="Windows\Converters\ThicknessValueConverter.cs" />
<Compile Include="Windows\Converters\VisibilityConverter.cs" />
<Compile Include="Windows\Documents\Highlighter.cs" />
<Compile Include="Windows\Documents\TextFragment.cs" />
<Compile Include="Windows\Documents\TextUtilities.cs" />
<Compile Include="Windows\DragAndDrop\ItemsControlDragDropService.cs" />
<Compile Include="Windows\DragAndDrop\DragDropHelper.cs" />
<Compile Include="Windows\DragAndDrop\DraggedAdorner.cs" />
<Compile Include="Windows\DragAndDrop\DragMoveWithinBoundsHelper.cs" />
<Compile Include="Windows\DragAndDrop\InsertionAdorner.cs" />
<Compile Include="Windows\DragAndDrop\DragDropUtilities.cs" />
<Compile Include="Windows\ExtendedSystemParameters.cs" />
<Compile Include="Windows\Input\KeyGestureUtilities.cs" />
<Compile Include="Windows\Media\Animation\AnimationHelper.cs" />
<Compile Include="Windows\MVVM\ICommandProvider.cs" />
<Compile Include="Windows\MVVM\ValidationUtilities.cs" />
<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" />
<Compile Include="Windows\Input\UICommand.cs" />
<Compile Include="Windows\InteropExtensions.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<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" />
<Compile Include="Windows\Transfer\DataObjectExtensions.cs" />
<Compile Include="Windows\Transfer\FileGroup.cs" />
<Compile Include="Windows\Transfer\CustomDataFormats.cs" />
<Compile Include="Windows\Transfer\HtmlDataFactory.cs" />
<Compile Include="Windows\UI.cs" />
<Compile Include="Windows\UserFeedback.cs" />
<Compile Include="Windows\WindowStateInfo.cs" />
<Compile Include="Windows\WindowUtilities.cs" />
<Compile Include="Windows\WpfExtensions.cs" />
<Compile Include="Xml\XmlExtensions.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\FoundationResources.resx">
<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>
<SubType>Designer</SubType>
</EmbeddedResource>
<Resource Include="Windows\Media\Effects\GrayscaleEffect.ps" />
</ItemGroup>
<ItemGroup>
<Resource Include="Windows\Controls\Resources\Controls.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Resource>
</ItemGroup>
<ItemGroup>
<Page Include="Themes\Office.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Themes\Generic.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Windows\Controls\BusySpinner.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Windows\Controls\ExceptionDialog.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Windows\Controls\FileBrowser.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Windows\Controls\ImageViewer.xaml">
<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>
</Page>
<Page Include="Windows\Controls\ProgressIndicator.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Windows\Controls\ProgressRing.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Resource Include="Windows\Controls\Resources\Animations.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Resource>
<Page Include="Windows\Controls\TransitionControl.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Resource Include="Windows\Controls\Resources\Transitions.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Resource>
<Page Include="Windows\Controls\VideoPlayer.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Content Include="Resources\Cursors\ClosedHand.cur" />
<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>
</Resource>
</ItemGroup>
<ItemGroup />
<Import Project="$(BuildScripts)\Microsoft.Internal.Tools.TeamMate.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,14 @@
using System.Runtime.InteropServices;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Native
{
/// <summary>
/// Exposes PInvoke method wrappers for functions in clr.dll.
/// </summary>
public static partial class NativeMethods
{
[DllImport("clr.dll", CharSet = CharSet.Unicode, ExactSpelling = true, PreserveSig = false)]
public static extern void CorLaunchApplication(uint hostType, string applicationFullName, int manifestPathsCount,
string[] manifestPaths, int activationDataCount, string[] activationData, PROCESS_INFORMATION processInformation);
}
}

Просмотреть файл

@ -0,0 +1,23 @@
using System;
using System.Runtime.InteropServices;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Native
{
/// <summary>
/// Exposes PInvoke method wrappers for functions in comctl32.dll.
/// </summary>
public static partial class NativeMethods
{
[DllImport("comctl32.dll")]
public extern static int ImageList_Draw(IntPtr hIml, int i, IntPtr hdcDst, int x, int y, int fStyle);
[DllImport("comctl32.dll")]
public extern static int ImageList_DrawIndirect(ref IMAGELISTDRAWPARAMS pimldp);
[DllImport("comctl32.dll")]
public extern static int ImageList_GetIconSize(IntPtr himl, ref int cx, ref int cy);
[DllImport("comctl32.dll")]
public extern static IntPtr ImageList_GetIcon(IntPtr himl, int i, int flags);
}
}

Просмотреть файл

@ -0,0 +1,411 @@
using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.Text;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Native
{
// Defines COM imports to expose well-known COM objects as C# classes
[ComImport]
[Guid("46EB5926-582E-4017-9FDF-E8998DAA0950")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IImageList
{
[PreserveSig]
int Add(IntPtr hbmImage, IntPtr hbmMask, ref int pi);
[PreserveSig]
int ReplaceIcon(int i, IntPtr hicon, ref int pi);
[PreserveSig]
int SetOverlayImage(int iImage, int iOverlay);
[PreserveSig]
int Replace(int i, IntPtr hbmImage, IntPtr hbmMask);
[PreserveSig]
int AddMasked(IntPtr hbmImage, int crMask, ref int pi);
[PreserveSig]
int Draw(ref IMAGELISTDRAWPARAMS pimldp);
[PreserveSig]
int Remove(int i);
[PreserveSig]
int GetIcon(int i, int flags, ref IntPtr picon);
[PreserveSig]
int GetImageInfo(int i, ref IMAGEINFO pImageInfo);
[PreserveSig]
int Copy(int iDst, IImageList punkSrc, int iSrc, int uFlags);
[PreserveSig]
int Merge(int i1, IImageList punk2, int i2, int dx, int dy, ref Guid riid, ref IntPtr ppv);
[PreserveSig]
int Clone(ref Guid riid, ref IntPtr ppv);
[PreserveSig]
int GetImageRect(int i, ref RECT prc);
[PreserveSig]
int GetIconSize(ref int cx, ref int cy);
[PreserveSig]
int SetIconSize(int cx, int cy);
[PreserveSig]
int GetImageCount(ref int pi);
[PreserveSig]
int SetImageCount(int uNewCount);
[PreserveSig]
int SetBkColor(int clrBk, ref int pclr);
[PreserveSig]
int GetBkColor(ref int pclr);
[PreserveSig]
int BeginDrag(int iTrack, int dxHotspot, int dyHotspot);
[PreserveSig]
int EndDrag();
[PreserveSig]
int DragEnter(IntPtr hwndLock, int x, int y);
[PreserveSig]
int DragLeave(IntPtr hwndLock);
[PreserveSig]
int DragMove(int x, int y);
[PreserveSig]
int SetDragCursorImage(ref IImageList punk, int iDrag, int dxHotspot, int dyHotspot);
[PreserveSig]
int DragShowNolock(int fShow);
[PreserveSig]
int GetDragImage(ref POINT ppt, ref POINT pptHotspot, ref Guid riid, ref IntPtr ppv);
[PreserveSig]
int GetItemFlags(int i, ref int dwFlags);
[PreserveSig]
int GetOverlayImage(int iOverlay, ref int piIndex);
};
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000000B-0000-0000-C000-000000000046")]
public interface IStorage
{
[return: MarshalAs(UnmanagedType.Interface)]
IStream CreateStream([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved1, [In, MarshalAs(UnmanagedType.U4)] int reserved2);
[return: MarshalAs(UnmanagedType.Interface)]
IStream OpenStream([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, IntPtr reserved1, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved2);
[return: MarshalAs(UnmanagedType.Interface)]
IStorage CreateStorage([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.U4)] int grfMode, [In, MarshalAs(UnmanagedType.U4)] int reserved1, [In, MarshalAs(UnmanagedType.U4)] int reserved2);
[return: MarshalAs(UnmanagedType.Interface)]
IStorage OpenStorage([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, IntPtr pstgPriority, [In, MarshalAs(UnmanagedType.U4)] int grfMode, IntPtr snbExclude, [In, MarshalAs(UnmanagedType.U4)] int reserved);
void CopyTo(int ciidExclude, [In, MarshalAs(UnmanagedType.LPArray)] Guid[] pIIDExclude, IntPtr snbExclude, [In, MarshalAs(UnmanagedType.Interface)] IStorage stgDest);
void MoveElementTo([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In, MarshalAs(UnmanagedType.Interface)] IStorage stgDest, [In, MarshalAs(UnmanagedType.BStr)] string pwcsNewName, [In, MarshalAs(UnmanagedType.U4)] int grfFlags);
void Commit(int grfCommitFlags);
void Revert();
void EnumElements([In, MarshalAs(UnmanagedType.U4)] int reserved1, IntPtr reserved2, [In, MarshalAs(UnmanagedType.U4)] int reserved3, [MarshalAs(UnmanagedType.Interface)] out object ppVal);
void DestroyElement([In, MarshalAs(UnmanagedType.BStr)] string pwcsName);
void RenameElement([In, MarshalAs(UnmanagedType.BStr)] string pwcsOldName, [In, MarshalAs(UnmanagedType.BStr)] string pwcsNewName);
void SetElementTimes([In, MarshalAs(UnmanagedType.BStr)] string pwcsName, [In] System.Runtime.InteropServices.ComTypes.FILETIME pctime, [In] System.Runtime.InteropServices.ComTypes.FILETIME patime, [In] System.Runtime.InteropServices.ComTypes.FILETIME pmtime);
void SetClass([In] ref Guid clsid);
void SetStateBits(int grfStateBits, int grfMask);
void Stat([Out]out System.Runtime.InteropServices.ComTypes.STATSTG pStatStg, int grfStatFlag);
}
[ComImport, Guid("591209c7-767b-42b2-9fba-44ee4615f2c7")]
public class ApplicationRegistrationClass
{
}
[CoClass(typeof(ApplicationRegistrationClass))]
[ComImport, Guid("4e530b0a-e611-4c77-a3ac-9031d022281b")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IApplicationRegistration
{
[return: MarshalAs(UnmanagedType.LPWStr)]
string QueryCurrentDefault(
[MarshalAs(UnmanagedType.LPWStr)] string query,
AssociationType queryType,
AssociationLevel queryLevel);
[return: MarshalAs(UnmanagedType.Bool)]
bool QueryAppIsDefault(
[MarshalAs(UnmanagedType.LPWStr)] string query,
AssociationType queryType,
AssociationLevel queryLevel,
[MarshalAs(UnmanagedType.LPWStr)] string appRegistryName);
[return: MarshalAs(UnmanagedType.Bool)]
bool QueryAppIsDefaultAll(
AssociationLevel queryLevel,
[MarshalAs(UnmanagedType.LPWStr)] string appRegistryName);
void SetAppAsDefault(
[MarshalAs(UnmanagedType.LPWStr)] string appRegistryName,
[MarshalAs(UnmanagedType.LPWStr)] string set,
AssociationType setType);
void SetAppAsDefaultAll(
[MarshalAs(UnmanagedType.LPWStr)] string appRegistryName);
void ClearUserAssociations();
}
public enum AssociationType
{
FileExtension,
UrlProtocol,
StartMenuClient,
MimeType
}
public enum AssociationLevel
{
Machine,
Effective,
User
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("8895b1c6-b41f-4c1c-a562-0d564250836f")]
public interface IPreviewHandler
{
void SetWindow(IntPtr hwnd, ref RECT rect);
void SetRect(ref RECT rect);
void DoPreview();
void Unload();
void SetFocus();
void QueryFocus(out IntPtr phwnd);
[PreserveSig]
uint TranslateAccelerator(ref MSG pmsg);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("b824b49d-22ac-4161-ac8a-9916e8fa3f7f")]
public interface IInitializeWithStream
{
void Initialize(IStream pstream, uint grfMode);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("b7d14566-0509-4cce-a71f-0a554233bd9b")]
public interface IInitializeWithFile
{
void Initialize([MarshalAs(UnmanagedType.LPWStr)] string pszFilePath, uint grfMode);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("7F73BE3F-FB79-493C-A6C7-7EE14E245841")]
public interface IInitializeWithItem
{
void Initialize(IShellItem psi, uint grfMode);
}
[ComImport]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
public interface IShellItem
{
void BindToHandler(IntPtr pbc,
[MarshalAs(UnmanagedType.LPStruct)]Guid bhid,
[MarshalAs(UnmanagedType.LPStruct)]Guid riid,
out IntPtr ppv);
void GetParent(out IShellItem ppsi);
void GetDisplayName(SIGDN sigdnName, out IntPtr ppszName);
void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
void Compare(IShellItem psi, uint hint, out int piOrder);
};
[ComImportAttribute()]
[GuidAttribute("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IShellItemImageFactory
{
void GetImage(
[In, MarshalAs(UnmanagedType.Struct)] SIZE size,
[In] SIIGBF flags,
[Out] out IntPtr phbm);
}
/// <summary>
/// The IOleMessageFilter interface provides COM servers and applications with the ability to selectively
/// handle incoming and outgoing COM messages while waiting for responses from synchronous calls.
/// Filtering messages helps to ensure that calls are handled in a manner that improves
/// performance and avoids deadlocks. COM messages can be synchronous, asynchronous, or input-synchronized;
/// the majority of interface calls are synchronous.
/// </summary>
[ComImport, Guid("00000016-0000-0000-C000-000000000046"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
public interface IOleMessageFilter
{
/// <summary>
/// This method is an object-based method that provides the ability to filter or reject incoming calls
/// (or call backs) to an object or a process. This method is called prior to each method
/// invocation originating outside the current process.
/// </summary>
/// <param name="dwCallType">Kind of incoming call that has been received.</param>
/// <param name="hTaskCaller">Handle of the task calling this task.</param>
/// <param name="dwTickCount">Elapsed tick count since the outgoing call was made if dwCallType is not CALLTYPE_TOPLEVEL.</param>
/// <param name="lpInterfaceInfo">Pointer to an INTERFACEINFO structure, which identifies the object, the interface, and the method making the call.</param>
/// <returns>
/// <para>SERVERCALL_ISHANDLED: The application might be able to process the call.</para>
/// <para>SERVERCALL_REJECTED: The application cannot handle the call due to an unforeseen problem,
/// such as network unavailability, or if it is in the process of terminating.</para>
/// <para>SERVERCALL_RETRYLATER: The application cannot handle the call at this time.</para>
/// </returns>
[PreserveSig]
int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo);
/// <summary>
/// This client-based method gives the application an opportunity to display a dialog box so
/// the user can retry or cancel the call, or switch to the task identified by hTaskCallee.
/// </summary>
/// <param name="hTaskCallee">Handle of the server task that rejected the call.</param>
/// <param name="dwTickCount">Number of elapsed ticks since the call was made.</param>
/// <param name="dwRejectType">Specifies either SERVERCALL_REJECTED or SERVERCALL_RETRYLATER, as returned by the object application.</param>
/// <returns>
/// <para>-1: The call should be canceled. COM then returns RPC_E_CALL_REJECTED from the original method call.</para>
/// <para>Value &gt;= 0 and &lt;100: The call is to be retried immediately.</para>
/// <para>Value &gt;= 100: COM will wait for this many milliseconds and then retry the call.</para>
/// </returns>
[PreserveSig]
int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);
/// <summary>
/// This client-based method is called by COM when a Windows message appears in a COM application's
/// message queue while the application is waiting for a reply to a remote call.
/// </summary>
/// <param name="hTaskCallee">Task handle of the called application that has not yet responded.</param>
/// <param name="dwTickCount">Number of ticks since the call was made.</param>
/// <param name="dwPendingType">Type of call made during which a message or event was received.</param>
[PreserveSig]
int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
}
[ComImport, Guid("7E5FE3D9-985F-4908-91F9-EE19F9FD1514")]
public class AppVisibilityClass
{
}
[CoClass(typeof(AppVisibilityClass))]
[ComImport, Guid("2246EA2D-CAEA-4444-A3C4-6DE827E44313"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAppVisibility
{
MONITOR_APP_VISIBILITY GetAppVisibilityOnMonitor(IntPtr hMonitor);
bool IsLauncherVisible();
int Advise(IAppVisibilityEvents pCallback);
void Unadvise([In] int dwCookie);
}
public enum MONITOR_APP_VISIBILITY
{
MAV_UNKNOWN = 0,
MAV_NO_APP_VISIBLE = 1,
MAV_APP_VISIBLE = 2
}
[ComImport, Guid("6584CE6B-7D82-49C2-89C9-C6BC02BA8C38"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IAppVisibilityEvents
{
void AppVisibilityOnMonitorChanged(IntPtr hMonitor, MONITOR_APP_VISIBILITY previousMode, MONITOR_APP_VISIBILITY currentMode);
void LauncherVisibilityChange(bool currentVisibleState);
}
/// <summary>The IShellLink interface allows Shell links to be created, modified, and resolved</summary>
[CoClass(typeof(CShellLink))]
[ComImport(), InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("000214F9-0000-0000-C000-000000000046")]
interface IShellLinkW
{
/// <summary>Retrieves the path and file name of a Shell link object</summary>
void GetPath([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszFile, int cchMaxPath, IntPtr pfd, uint fFlags);
/// <summary>Retrieves the list of item identifiers for a Shell link object</summary>
void GetIDList(out IntPtr ppidl);
/// <summary>Sets the pointer to an item identifier list (PIDL) for a Shell link object.</summary>
void SetIDList(IntPtr pidl);
/// <summary>Retrieves the description string for a Shell link object</summary>
void GetDescription([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszName, int cchMaxName);
/// <summary>Sets the description for a Shell link object. The description can be any application-defined string</summary>
void SetDescription([MarshalAs(UnmanagedType.LPWStr)] string pszName);
/// <summary>Retrieves the name of the working directory for a Shell link object</summary>
void GetWorkingDirectory([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszDir, int cchMaxPath);
/// <summary>Sets the name of the working directory for a Shell link object</summary>
void SetWorkingDirectory([MarshalAs(UnmanagedType.LPWStr)] string pszDir);
/// <summary>Retrieves the command-line arguments associated with a Shell link object</summary>
void GetArguments([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszArgs, int cchMaxPath);
/// <summary>Sets the command-line arguments for a Shell link object</summary>
void SetArguments([MarshalAs(UnmanagedType.LPWStr)] string pszArgs);
/// <summary>Retrieves the hot key for a Shell link object</summary>
void GetHotkey(out short pwHotkey);
/// <summary>Sets a hot key for a Shell link object</summary>
void SetHotkey(short wHotkey);
/// <summary>Retrieves the show command for a Shell link object</summary>
void GetShowCmd(out int piShowCmd);
/// <summary>Sets the show command for a Shell link object. The show command sets the initial show state of the window.</summary>
void SetShowCmd(int iShowCmd);
/// <summary>Retrieves the location (path and index) of the icon for a Shell link object</summary>
void GetIconLocation([Out(), MarshalAs(UnmanagedType.LPWStr)] StringBuilder pszIconPath,
int cchIconPath, out int piIcon);
/// <summary>Sets the location (path and index) of the icon for a Shell link object</summary>
void SetIconLocation([MarshalAs(UnmanagedType.LPWStr)] string pszIconPath, int iIcon);
/// <summary>Sets the relative path to the Shell link object</summary>
void SetRelativePath([MarshalAs(UnmanagedType.LPWStr)] string pszPathRel, int dwReserved);
/// <summary>Attempts to find the target of a Shell link, even if it has been moved or renamed</summary>
void Resolve(IntPtr hwnd, uint fFlags);
/// <summary>Sets the path and file name of a Shell link object</summary>
void SetPath([MarshalAs(UnmanagedType.LPWStr)] string pszFile);
}
[ComImport, Guid("00021401-0000-0000-C000-000000000046"), ClassInterface(ClassInterfaceType.None)]
public class CShellLink
{
}
[ComImport, Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IPropertyStore
{
UInt32 GetCount([Out] out uint propertyCount);
UInt32 GetAt([In] uint propertyIndex, out PropertyKey key);
UInt32 GetValue([In] ref PropertyKey key, [Out] PropVariant pv);
UInt32 SetValue([In] ref PropertyKey key, [In] PropVariant pv);
UInt32 Commit();
}
}

Просмотреть файл

@ -0,0 +1,323 @@
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Native
{
/// <summary>
/// Basic implementation of the IStream interface (wraps a .NET Stream).
/// </summary>
/// <remarks>
/// Some of the methods are not supported supported, see implementation for more details.
/// </remarks>
internal class ComStreamAdapter : IStream, IDisposable
{
private const long POSITION_NOT_SET = -1;
private const int STG_E_INVALIDFUNCTION = 32774;
private const int CHUNK = 4096;
private const string METHOD_NOT_SUPPORTED = "Method not supported.";
private const string UNKNOWN_ERROR = "Unknown error.";
private long indexPosition = POSITION_NOT_SET;
private Stream stream;
/// <summary>
/// Initializes a new instance of the StreamWrapper with the specified input stream.
/// </summary>
/// <param name="stream">The stream being wrapped.</param>
internal ComStreamAdapter(Stream stream)
{
this.indexPosition = POSITION_NOT_SET;
this.stream = stream;
}
#region IStream Members
/// <summary>
/// Creates a new stream object with its own seek pointer that references the same bytes as the original stream.
/// </summary>
/// <param name="ppstm">When this method returns, contains the new stream object. This parameter is passed uninitialized.</param>
public void Clone(out IStream ppstm)
{
ppstm = null;
ThrowNotSupportedException();
}
/// <summary>
/// Ensures that any changes made to a stream object that is open in transacted mode are reflected in the parent storage.
/// </summary>
/// <param name="grfCommitFlags">A value that controls how the changes for the stream object are committed.</param>
public void Commit(int grfCommitFlags)
{
stream.Flush();
}
/// <summary>
/// Copies a specified number of bytes from the current seek pointer in the stream to the current seek pointer in another stream.
/// </summary>
/// <param name="pstm">A reference to the destination stream.</param>
/// <param name="cb">The number of bytes to copy from the source stream.</param>
/// <param name="pcbRead">On successful return, contains the actual number of bytes read from the source.</param>
/// <param name="pcbWritten">On successful return, contains the actual number of bytes written to the destination.</param>
public void CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
{
byte[] buffer = new byte[CHUNK];
long written = 0;
int read = 0;
if (cb != 0)
{
SetSizeToPosition();
do
{
int count = CHUNK;
if (written + CHUNK > cb)
{
count = (int)(cb - written);
}
if ((read = stream.Read(buffer, 0, count)) == 0)
{
break;
}
pstm.Write(buffer, read, IntPtr.Zero);
written += read;
}
while (written < cb);
}
if (pcbRead != IntPtr.Zero)
{
Marshal.WriteInt64(pcbRead, written);
}
if (pcbWritten != IntPtr.Zero)
{
Marshal.WriteInt64(pcbWritten, written);
}
}
/// <summary>
/// Reads a specified number of bytes from the stream object into memory starting at the current seek pointer.
/// </summary>
/// <param name="pv">When this method returns, contains the data read from the stream. This parameter is passed uninitialized.</param>
/// <param name="cb">The number of bytes to read from the stream object.</param>
/// <param name="pcbRead">A pointer to a ULONG variable that receives the actual number of bytes read from the stream object.</param>
public void Read(byte[] pv, int cb, IntPtr pcbRead)
{
int read = 0;
if (cb != 0)
{
SetSizeToPosition();
read = stream.Read(pv, 0, cb);
}
if (pcbRead != IntPtr.Zero)
{
Marshal.WriteInt32(pcbRead, read);
}
}
/// <summary>
/// Changes the seek pointer to a new location relative to the beginning of the stream, to the end of the stream, or to the current seek pointer.
/// </summary>
/// <param name="dlibMove">The displacement to add to <paramref name="dwOrigin" />.</param>
/// <param name="dwOrigin">The origin of the seek. The origin can be the beginning of the file, the current seek pointer, or the end of the file.</param>
/// <param name="plibNewPosition">On successful return, contains the offset of the seek pointer from the beginning of the stream.</param>
/// <exception cref="System.Runtime.InteropServices.ExternalException">
/// </exception>
public void Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
{
long newPosition = 0;
SeekOrigin seekOrigin = SeekOrigin.Begin;
try
{
seekOrigin = (SeekOrigin)dwOrigin;
}
catch
{
throw new ExternalException(UNKNOWN_ERROR, STG_E_INVALIDFUNCTION);
}
if (stream.CanWrite)
{
switch (seekOrigin)
{
case SeekOrigin.Begin:
newPosition = dlibMove;
break;
case SeekOrigin.Current:
newPosition = indexPosition;
if (newPosition == POSITION_NOT_SET)
{
newPosition = stream.Position;
}
newPosition += dlibMove;
break;
case SeekOrigin.End:
newPosition = stream.Length + dlibMove;
break;
default:
// should never happen
throw new ExternalException(UNKNOWN_ERROR, STG_E_INVALIDFUNCTION);
}
if (newPosition > stream.Length)
{
indexPosition = newPosition;
}
else
{
stream.Position = newPosition;
indexPosition = POSITION_NOT_SET;
}
}
else
{
try
{
newPosition = stream.Seek(dlibMove, seekOrigin);
}
catch (ArgumentException)
{
throw new ExternalException(UNKNOWN_ERROR, STG_E_INVALIDFUNCTION);
}
indexPosition = POSITION_NOT_SET;
}
if (plibNewPosition != IntPtr.Zero)
{
Marshal.WriteInt64(plibNewPosition, newPosition);
}
}
/// <summary>
/// Changes the size of the stream object.
/// </summary>
/// <param name="libNewSize">The new size of the stream as a number of bytes.</param>
public void SetSize(long libNewSize)
{
stream.SetLength(libNewSize);
}
/// <summary>
/// Retrieves the <see cref="T:System.Runtime.InteropServices.STATSTG" /> structure for this stream.
/// </summary>
/// <param name="pstatstg">When this method returns, contains a STATSTG structure that describes this stream object. This parameter is passed uninitialized.</param>
/// <param name="grfStatFlag">Members in the STATSTG structure that this method does not return, thus saving some memory allocation operations.</param>
public void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag)
{
pstatstg = new System.Runtime.InteropServices.ComTypes.STATSTG();
pstatstg.cbSize = stream.Length;
}
/// <summary>
/// Writes a specified number of bytes into the stream object starting at the current seek pointer.
/// </summary>
/// <param name="pv">The buffer to write this stream to.</param>
/// <param name="cb">The number of bytes to write to the stream.</param>
/// <param name="pcbWritten">On successful return, contains the actual number of bytes written to the stream object. If the caller sets this pointer to <see cref="F:System.IntPtr.Zero" />, this method does not provide the actual number of bytes written.</param>
public void Write(byte[] pv, int cb, IntPtr pcbWritten)
{
if (cb != 0)
{
SetSizeToPosition();
stream.Write(pv, 0, cb);
}
if (pcbWritten != IntPtr.Zero)
{
Marshal.WriteInt32(pcbWritten, cb);
}
}
/// <summary>
/// Discards all changes that have been made to a transacted stream since the last <see cref="M:System.Runtime.InteropServices.ComTypes.IStream.Commit(System.Int32)" /> call.
/// </summary>
/// <exception cref="System.Runtime.InteropServices.ExternalException"></exception>
public void Revert()
{
throw new ExternalException(METHOD_NOT_SUPPORTED, STG_E_INVALIDFUNCTION);
}
/// <summary>
/// Restricts access to a specified range of bytes in the stream.
/// </summary>
/// <param name="libOffset">The byte offset for the beginning of the range.</param>
/// <param name="cb">The length of the range, in bytes, to restrict.</param>
/// <param name="dwLockType">The requested restrictions on accessing the range.</param>
public void LockRegion(long libOffset, long cb, int dwLockType)
{
ThrowNotSupportedException();
}
/// <summary>
/// Removes the access restriction on a range of bytes previously restricted with the <see cref="M:System.Runtime.InteropServices.ComTypes.IStream.LockRegion(System.Int64,System.Int64,System.Int32)" /> method.
/// </summary>
/// <param name="libOffset">The byte offset for the beginning of the range.</param>
/// <param name="cb">The length, in bytes, of the range to restrict.</param>
/// <param name="dwLockType">The access restrictions previously placed on the range.</param>
public void UnlockRegion(long libOffset, long cb, int dwLockType)
{
ThrowNotSupportedException();
}
#endregion
/// <summary>
/// Throws a not supported exception.
/// </summary>
private void ThrowNotSupportedException()
{
throw new ExternalException(METHOD_NOT_SUPPORTED, STG_E_INVALIDFUNCTION);
}
/// <summary>
/// Sets the stream length to the current index position.
/// </summary>
private void SetSizeToPosition()
{
if (indexPosition != POSITION_NOT_SET)
{
// position requested greater than current length?
if (indexPosition > stream.Length)
{
// expand stream
stream.SetLength(indexPosition);
}
// set new position
stream.Position = indexPosition;
indexPosition = POSITION_NOT_SET;
}
}
/// <summary>
/// Closes this instance.
/// </summary>
public void Close()
{
stream.Close();
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
stream.Dispose();
}
}
}

Просмотреть файл

@ -0,0 +1,50 @@
using System;
using System.Runtime.InteropServices;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Native
{
/// <summary>
/// Exposes PInvoke method wrappers for functions in dwmapi.dll.
/// </summary>
public static partial class NativeMethods
{
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmRegisterThumbnail(IntPtr dest, IntPtr src, out IntPtr thumb);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmUnregisterThumbnail(IntPtr HThumbnail);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmUpdateThumbnailProperties(IntPtr hThumbnail, ref DWM_THUMBNAIL_PROPERTIES props);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmQueryThumbnailSourceSize(IntPtr hThumbnail, out SIZE size);
[DllImport("dwmapi.dll")]
public static extern Int32 DwmExtendFrameIntoClientArea(IntPtr hWnd, ref MARGINS pMarInset);
[DllImport("dwmapi.dll", PreserveSig = true)]
public static extern Int32 DwmSetWindowAttribute(IntPtr hwnd, Int32 attr, ref Int32 attrValue, Int32 attrSize);
}
[StructLayout(LayoutKind.Sequential)]
public struct DWM_THUMBNAIL_PROPERTIES
{
public ThumbnailFlags dwFlags;
public RECT rcDestination;
public RECT rcSource;
public byte opacity;
public bool fVisible;
public bool fSourceClientAreaOnly;
}
[Flags]
public enum ThumbnailFlags
{
DWM_TNP_RECTDESTINATION = 0x00000001,
DWM_TNP_RECTSOURCE = 0x00000002,
DWM_TNP_OPACITY = 0x00000004,
DWM_TNP_VISIBLE = 0x00000008,
DWM_TNP_SOURCECLIENTAREAONLY = 0x00000010
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -0,0 +1,102 @@
using System;
using System.Runtime.InteropServices;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Native
{
/// <summary>
/// Exposes PInvoke method wrappers for functions in gdi32.dll.
/// </summary>
public static partial class NativeMethods
{
[DllImport("gdi32.dll", SetLastError = true)]
public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[DllImport("gdi32.dll")]
public static extern bool DeleteDC(IntPtr hdc);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, RasterOperations dwRop);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateDC(string lpszDriver, string lpszDevice, string lpszOutput, IntPtr lpInitData);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateRectRgn(int nLeftRect, int nTopRect, int nRightRect, int nBottomRect);
[DllImport("gdi32.dll")]
public static extern bool StretchBlt(IntPtr hdcDest, int nXOriginDest, int nYOriginDest,
int nWidthDest, int nHeightDest,
IntPtr hdcSrc, int nXOriginSrc, int nYOriginSrc, int nWidthSrc, int nHeightSrc,
RasterOperations dwRop);
[DllImport("gdi32.dll")]
public static extern bool SetWorldTransform(IntPtr hdc, [In] ref XFORM lpXform);
[DllImport("gdi32.dll")]
public static extern int SetGraphicsMode(IntPtr hdc, GM iMode);
[DllImport("gdi32.dll")]
public static extern int SetStretchBltMode(IntPtr hdc, STRETCH iStretchMode);
/// <summary>
/// The GetDeviceCaps function retrieves device-specific information for the specified device.
/// </summary>
/// <param name="hdc">A handle to the DC.</param>
/// <param name="nIndex">The item to be returned.</param>
/// <returns>The return value specifies the value of the desired item.</returns>
[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
/// <summary>
/// Gets the current system DPI setting.
/// </summary>
/// <returns>The system DPI setting.</returns>
public static void GetSystemDpi(out int dpiX, out int dpiY)
{
IntPtr hDC = GetDC(IntPtr.Zero);
try
{
dpiX = GetDeviceCaps(hDC, (int) SystemMetric.SM_LOGPIXELSX);
dpiY = GetDeviceCaps(hDC, (int) SystemMetric.SM_LOGPIXELSY);
}
finally
{
ReleaseDC(IntPtr.Zero, hDC);
}
}
}
public struct XFORM
{
public float eM11;
public float eM12;
public float eM21;
public float eM22;
public float eDx;
public float eDy;
}
public enum GM : uint
{
GM_COMPATIBLE = 1,
GM_ADVANCED = 2,
}
public enum STRETCH
{
STRETCH_ANDSCANS = 1,
STRETCH_ORSCANS = 2,
STRETCH_DELETESCANS = 3,
STRETCH_HALFTONE = 4,
}
}

Просмотреть файл

@ -0,0 +1,57 @@
using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Native
{
/// <summary>
/// Exposes PInvoke method wrappers for functions in kernel32.dll.
/// </summary>
public static partial class NativeMethods
{
[DllImport("kernel32.dll")]
public static extern uint GetCurrentThreadId();
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
public static extern bool CloseHandle(HandleRef handle);
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool FreeLibrary(IntPtr hModule);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern SafeFileHandle CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
uint SecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
int hTemplateFile
);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern SafeFileHandle CreateMailslot(string lpName, uint nMaxMessageSize,
int lReadTimeout, SECURITY_ATTRIBUTES lpSecurityAttributes);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
public static extern bool GetMailslotInfo(SafeFileHandle hMailslot,
out int lpMaxMessageSize,
out int lpNextSize,
out int lpMessageCount,
out int lpReadTimeout);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GlobalAlloc(int uFlags, int dwBytes);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GlobalFree(HandleRef handle);
[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool GlobalMemoryStatusEx([In, Out] MEMORYSTATUSEX lpBuffer);
}
}

Просмотреть файл

@ -0,0 +1,27 @@
using System.Runtime.InteropServices;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Native
{
/// <summary>
/// Exposes PInvoke method wrappers for functions in ole32.dll.
/// </summary>
public static partial class NativeMethods
{
[DllImport("ole32.dll", CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern int StgCreateDocfile([MarshalAs(UnmanagedType.LPWStr)]string pwcsName, uint grfMode, uint reserved, out IStorage ppstgOpen);
/// <summary>
/// This function registers with OLE the instance of an EXE application's IOleMessageFilter interface,
/// which is to be used for handling concurrency issues. DLL object applications cannot register
/// a message filter.
/// </summary>
/// <param name="newFilter">IOleMessageFilter interface on the message filter supplied by the application.
/// Can be <c>null</c>, indicating that the current IOleMessageFilter registration should be revoked.</param>
/// <param name="oldFilter">Variable that receives the previously registered message filter.</param>
[DllImport("ole32.dll")]
public static extern int CoRegisterMessageFilter(IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
[DllImport("Ole32.dll", PreserveSig = false)] // returns hresult
public extern static void PropVariantClear([In, Out] PropVariant pvar);
}
}

Просмотреть файл

@ -0,0 +1,34 @@
using System;
using System.Runtime.InteropServices;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Native
{
/// <summary>
/// Exposes PInvoke method wrappers for functions in OleAut32.dll.
/// </summary>
public static partial class NativeMethods
{
[DllImport("OleAut32.dll", PreserveSig = true)] // psa is actually returned, not hresult
public extern static IntPtr SafeArrayCreateVector(ushort vt, int lowerBound, uint cElems);
[DllImport("OleAut32.dll", PreserveSig = false)] // returns hresult
public extern static IntPtr SafeArrayAccessData(IntPtr psa);
[DllImport("OleAut32.dll", PreserveSig = false)] // returns hresult
public extern static void SafeArrayUnaccessData(IntPtr psa);
[DllImport("OleAut32.dll", PreserveSig = true)] // retuns uint32
public extern static uint SafeArrayGetDim(IntPtr psa);
[DllImport("OleAut32.dll", PreserveSig = false)] // returns hresult
public extern static int SafeArrayGetLBound(IntPtr psa, uint nDim);
[DllImport("OleAut32.dll", PreserveSig = false)] // returns hresult
public extern static int SafeArrayGetUBound(IntPtr psa, uint nDim);
// This decl for SafeArrayGetElement is only valid for cDims==1!
[DllImport("OleAut32.dll", PreserveSig = false)] // returns hresult
[return: MarshalAs(UnmanagedType.IUnknown)]
public extern static object SafeArrayGetElement(IntPtr psa, ref int rgIndices);
}
}

Просмотреть файл

@ -0,0 +1,805 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.InteropServices;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Native
{
/// <summary>
/// Represents the OLE struct PROPVARIANT.
/// This class is intended for internal use only.
/// </summary>
/// <remarks>
/// Originally sourced from http://blogs.msdn.com/adamroot/pages/interop-with-propvariants-in-net.aspx
/// and modified to support additional types including vectors and ability to set values
/// </remarks>
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Portability", "CA1900:ValueTypeFieldsShouldBePortable", MessageId = "_ptr2")]
[StructLayout(LayoutKind.Explicit)]
public sealed class PropVariant : IDisposable
{
#region Vector Action Cache
// A static dictionary of delegates to get data from array's contained within PropVariants
private static Dictionary<Type, Action<PropVariant, Array, uint>> _vectorActions = null;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
private static Dictionary<Type, Action<PropVariant, Array, uint>> GenerateVectorActions()
{
Dictionary<Type, Action<PropVariant, Array, uint>> cache = new Dictionary<Type, Action<PropVariant, Array, uint>>();
cache.Add(typeof(Int16), (pv, array, i) =>
{
short val;
NativeMethods.PropVariantGetInt16Elem(pv, i, out val);
array.SetValue(val, i);
});
cache.Add(typeof(UInt16), (pv, array, i) =>
{
ushort val;
NativeMethods.PropVariantGetUInt16Elem(pv, i, out val);
array.SetValue(val, i);
});
cache.Add(typeof(Int32), (pv, array, i) =>
{
int val;
NativeMethods.PropVariantGetInt32Elem(pv, i, out val);
array.SetValue(val, i);
});
cache.Add(typeof(UInt32), (pv, array, i) =>
{
uint val;
NativeMethods.PropVariantGetUInt32Elem(pv, i, out val);
array.SetValue(val, i);
});
cache.Add(typeof(Int64), (pv, array, i) =>
{
long val;
NativeMethods.PropVariantGetInt64Elem(pv, i, out val);
array.SetValue(val, i);
});
cache.Add(typeof(UInt64), (pv, array, i) =>
{
ulong val;
NativeMethods.PropVariantGetUInt64Elem(pv, i, out val);
array.SetValue(val, i);
});
cache.Add(typeof(DateTime), (pv, array, i) =>
{
System.Runtime.InteropServices.ComTypes.FILETIME val;
NativeMethods.PropVariantGetFileTimeElem(pv, i, out val);
long fileTime = GetFileTimeAsLong(ref val);
array.SetValue(DateTime.FromFileTime(fileTime), i);
});
cache.Add(typeof(Boolean), (pv, array, i) =>
{
bool val;
NativeMethods.PropVariantGetBooleanElem(pv, i, out val);
array.SetValue(val, i);
});
cache.Add(typeof(Double), (pv, array, i) =>
{
double val;
NativeMethods.PropVariantGetDoubleElem(pv, i, out val);
array.SetValue(val, i);
});
cache.Add(typeof(Single), (pv, array, i) => // float
{
float[] val = new float[1];
Marshal.Copy(pv._ptr2, val, (int)i, 1);
array.SetValue(val[0], (int)i);
});
cache.Add(typeof(Decimal), (pv, array, i) =>
{
int[] val = new int[4];
for (int a = 0; a < val.Length; a++)
{
val[a] = Marshal.ReadInt32(pv._ptr2,
(int)i * sizeof(decimal) + a * sizeof(int)); //index * size + offset quarter
}
array.SetValue(new decimal(val), i);
});
cache.Add(typeof(String), (pv, array, i) =>
{
string val = string.Empty;
NativeMethods.PropVariantGetStringElem(pv, i, ref val);
array.SetValue(val, i);
});
return cache;
}
#endregion
#region Dynamic Construction / Factory (Expressions)
/// <summary>
/// Attempts to create a PropVariant by finding an appropriate constructor.
/// </summary>
/// <param name="value">Object from which PropVariant should be created.</param>
public static PropVariant FromObject(object value)
{
if (value == null)
{
return new PropVariant();
}
else
{
var func = GetDynamicConstructor(value.GetType());
return func(value);
}
}
// A dictionary and lock to contain compiled expression trees for constructors
private static Dictionary<Type, Func<object, PropVariant>> _cache = new Dictionary<Type, Func<object, PropVariant>>();
private static object _padlock = new object();
// Retrieves a cached constructor expression.
// If no constructor has been cached, it attempts to find/add it. If it cannot be found
// an exception is thrown.
// This method looks for a public constructor with the same parameter type as the object.
private static Func<object, PropVariant> GetDynamicConstructor(Type type)
{
lock (_padlock)
{
// initial check, if action is found, return it
Func<object, PropVariant> action;
if (!_cache.TryGetValue(type, out action))
{
// iterates through all constructors
ConstructorInfo constructor = typeof(PropVariant)
.GetConstructor(new Type[] { type });
if (constructor == null)
{ // if the method was not found, throw.
throw new ArgumentException("This Value type is not supported.");
}
else // if the method was found, create an expression to call it.
{
// create parameters to action
var arg = Expression.Parameter(typeof(object), "arg");
// create an expression to invoke the constructor with an argument cast to the correct type
var create = Expression.New(constructor, Expression.Convert(arg, type));
// compiles expression into an action delegate
action = Expression.Lambda<Func<object, PropVariant>>(create, arg).Compile();
_cache.Add(type, action);
}
}
return action;
}
}
#endregion
#region Fields
[FieldOffset(0)]
decimal _decimal;
// This is actually a VarEnum value, but the VarEnum type
// requires 4 bytes instead of the expected 2.
[FieldOffset(0)]
ushort _valueType;
// Reserved Fields
//[FieldOffset(2)]
//ushort _wReserved1;
//[FieldOffset(4)]
//ushort _wReserved2;
//[FieldOffset(6)]
//ushort _wReserved3;
// In order to allow x64 compat, we need to allow for
// expansion of the IntPtr. However, the BLOB struct
// uses a 4-byte int, followed by an IntPtr, so
// although the valueData field catches most pointer values,
// we need an additional 4-bytes to get the BLOB
// pointer. The valueDataExt field provides this, as well as
// the last 4-bytes of an 8-byte value on 32-bit
// architectures.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
[FieldOffset(12)]
IntPtr _ptr2;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
[FieldOffset(8)]
IntPtr _ptr;
[FieldOffset(8)]
Int32 _int32;
[FieldOffset(8)]
UInt32 _uint32;
[FieldOffset(8)]
byte _byte;
[FieldOffset(8)]
sbyte _sbyte;
[FieldOffset(8)]
short _short;
[FieldOffset(8)]
ushort _ushort;
[FieldOffset(8)]
long _long;
[FieldOffset(8)]
ulong _ulong;
[FieldOffset(8)]
double _double;
[FieldOffset(8)]
float _float;
#endregion // struct fields
#region Constructors
/// <summary>
/// Default constrcutor
/// </summary>
public PropVariant()
{
// left empty
}
/// <summary>
/// Set a string value
/// </summary>
public PropVariant(string value)
{
if (value == null)
{
throw new ArgumentException("String argument cannot be null or empty.", "value");
}
_valueType = (ushort)VarEnum.VT_LPWSTR;
_ptr = Marshal.StringToCoTaskMemUni(value);
}
/// <summary>
/// Set a string vector
/// </summary>
public PropVariant(string[] value)
{
if (value == null) { throw new ArgumentNullException("value"); }
NativeMethods.InitPropVariantFromStringVector(value, (uint)value.Length, this);
}
/// <summary>
/// Set a bool vector
/// </summary>
public PropVariant(bool[] value)
{
if (value == null) { throw new ArgumentNullException("value"); }
NativeMethods.InitPropVariantFromBooleanVector(value, (uint)value.Length, this);
}
/// <summary>
/// Set a short vector
/// </summary>
public PropVariant(short[] value)
{
if (value == null) { throw new ArgumentNullException("value"); }
NativeMethods.InitPropVariantFromInt16Vector(value, (uint)value.Length, this);
}
/// <summary>
/// Set a short vector
/// </summary>
public PropVariant(ushort[] value)
{
if (value == null) { throw new ArgumentNullException("value"); }
NativeMethods.InitPropVariantFromUInt16Vector(value, (uint)value.Length, this);
}
/// <summary>
/// Set an int vector
/// </summary>
public PropVariant(int[] value)
{
if (value == null) { throw new ArgumentNullException("value"); }
NativeMethods.InitPropVariantFromInt32Vector(value, (uint)value.Length, this);
}
/// <summary>
/// Set an uint vector
/// </summary>
public PropVariant(uint[] value)
{
if (value == null) { throw new ArgumentNullException("value"); }
NativeMethods.InitPropVariantFromUInt32Vector(value, (uint)value.Length, this);
}
/// <summary>
/// Set a long vector
/// </summary>
public PropVariant(long[] value)
{
if (value == null) { throw new ArgumentNullException("value"); }
NativeMethods.InitPropVariantFromInt64Vector(value, (uint)value.Length, this);
}
/// <summary>
/// Set a ulong vector
/// </summary>
public PropVariant(ulong[] value)
{
if (value == null) { throw new ArgumentNullException("value"); }
NativeMethods.InitPropVariantFromUInt64Vector(value, (uint)value.Length, this);
}
/// <summary>>
/// Set a double vector
/// </summary>
public PropVariant(double[] value)
{
if (value == null) { throw new ArgumentNullException("value"); }
NativeMethods.InitPropVariantFromDoubleVector(value, (uint)value.Length, this);
}
/// <summary>
/// Set a DateTime vector
/// </summary>
public PropVariant(DateTime[] value)
{
if (value == null) { throw new ArgumentNullException("value"); }
System.Runtime.InteropServices.ComTypes.FILETIME[] fileTimeArr =
new System.Runtime.InteropServices.ComTypes.FILETIME[value.Length];
for (int i = 0; i < value.Length; i++)
{
fileTimeArr[i] = DateTimeToFileTime(value[i]);
}
NativeMethods.InitPropVariantFromFileTimeVector(fileTimeArr, (uint)fileTimeArr.Length, this);
}
/// <summary>
/// Set a bool value
/// </summary>
public PropVariant(bool value)
{
_valueType = (ushort)VarEnum.VT_BOOL;
_int32 = (value == true) ? -1 : 0;
}
/// <summary>
/// Set a DateTime value
/// </summary>
public PropVariant(DateTime value)
{
_valueType = (ushort)VarEnum.VT_FILETIME;
System.Runtime.InteropServices.ComTypes.FILETIME ft = DateTimeToFileTime(value);
NativeMethods.InitPropVariantFromFileTime(ref ft, this);
}
/// <summary>
/// Set a byte value
/// </summary>
public PropVariant(byte value)
{
_valueType = (ushort)VarEnum.VT_UI1;
_byte = value;
}
/// <summary>
/// Set a sbyte value
/// </summary>
public PropVariant(sbyte value)
{
_valueType = (ushort)VarEnum.VT_I1;
_sbyte = value;
}
/// <summary>
/// Set a short value
/// </summary>
public PropVariant(short value)
{
_valueType = (ushort)VarEnum.VT_I2;
_short = value;
}
/// <summary>
/// Set an unsigned short value
/// </summary>
public PropVariant(ushort value)
{
_valueType = (ushort)VarEnum.VT_UI2;
_ushort = value;
}
/// <summary>
/// Set an int value
/// </summary>
public PropVariant(int value)
{
_valueType = (ushort)VarEnum.VT_I4;
_int32 = value;
}
/// <summary>
/// Set an unsigned int value
/// </summary>
public PropVariant(uint value)
{
_valueType = (ushort)VarEnum.VT_UI4;
_uint32 = value;
}
/// <summary>
/// Set a decimal value
/// </summary>
public PropVariant(decimal value)
{
_decimal = value;
// It is critical that the value type be set after the decimal value, because they overlap.
// If valuetype is written first, its value will be lost when _decimal is written.
_valueType = (ushort)VarEnum.VT_DECIMAL;
}
/// <summary>
/// Create a PropVariant with a contained decimal array.
/// </summary>
/// <param name="value">Decimal array to wrap.</param>
public PropVariant(decimal[] value)
{
if (value == null) { throw new ArgumentNullException("value"); }
_valueType = (ushort)(VarEnum.VT_DECIMAL | VarEnum.VT_VECTOR);
_int32 = value.Length;
// allocate required memory for array with 128bit elements
_ptr2 = Marshal.AllocCoTaskMem(value.Length * sizeof(decimal));
for (int i = 0; i < value.Length; i++)
{
int[] bits = decimal.GetBits(value[i]);
Marshal.Copy(bits, 0, _ptr2, bits.Length);
}
}
/// <summary>
/// Create a PropVariant containing a float type.
/// </summary>
public PropVariant(float value)
{
_valueType = (ushort)VarEnum.VT_R4;
_float = value;
}
/// <summary>
/// Creates a PropVariant containing a float[] array.
/// </summary>
public PropVariant(float[] value)
{
if (value == null) { throw new ArgumentNullException("value"); }
_valueType = (ushort)(VarEnum.VT_R4 | VarEnum.VT_VECTOR);
_int32 = value.Length;
_ptr2 = Marshal.AllocCoTaskMem(value.Length * sizeof(float));
Marshal.Copy(value, 0, _ptr2, value.Length);
}
/// <summary>
/// Set a long
/// </summary>
public PropVariant(long value)
{
_long = value;
_valueType = (ushort)VarEnum.VT_I8;
}
/// <summary>
/// Set a ulong
/// </summary>
public PropVariant(ulong value)
{
_valueType = (ushort)VarEnum.VT_UI8;
_ulong = value;
}
/// <summary>
/// Set a double
/// </summary>
public PropVariant(double value)
{
_valueType = (ushort)VarEnum.VT_R8;
_double = value;
}
#endregion
#region Uncalled methods - These are currently not called, but I think may be valid in the future.
/// <summary>
/// Set an IUnknown value
/// </summary>
/// <param name="value">The new value to set.</param>
internal void SetIUnknown(object value)
{
_valueType = (ushort)VarEnum.VT_UNKNOWN;
_ptr = Marshal.GetIUnknownForObject(value);
}
/// <summary>
/// Set a safe array value
/// </summary>
/// <param name="array">The new value to set.</param>
internal void SetSafeArray(Array array)
{
if (array == null) { throw new ArgumentNullException("array"); }
const ushort vtUnknown = 13;
IntPtr psa = NativeMethods.SafeArrayCreateVector(vtUnknown, 0, (uint)array.Length);
IntPtr pvData = NativeMethods.SafeArrayAccessData(psa);
try // to remember to release lock on data
{
for (int i = 0; i < array.Length; ++i)
{
object obj = array.GetValue(i);
IntPtr punk = (obj != null) ? Marshal.GetIUnknownForObject(obj) : IntPtr.Zero;
Marshal.WriteIntPtr(pvData, i * IntPtr.Size, punk);
}
}
finally
{
NativeMethods.SafeArrayUnaccessData(psa);
}
_valueType = (ushort)VarEnum.VT_ARRAY | (ushort)VarEnum.VT_UNKNOWN;
_ptr = psa;
}
#endregion
#region public Properties
/// <summary>
/// Gets or sets the variant type.
/// </summary>
public VarEnum VarType
{
get { return (VarEnum)_valueType; }
set { _valueType = (ushort)value; }
}
/// <summary>
/// Checks if this has an empty or null value
/// </summary>
/// <returns></returns>
public bool IsNullOrEmpty
{
get
{
return (_valueType == (ushort)VarEnum.VT_EMPTY || _valueType == (ushort)VarEnum.VT_NULL);
}
}
/// <summary>
/// Gets the variant value.
/// </summary>
public object Value
{
get
{
switch ((VarEnum)_valueType)
{
case VarEnum.VT_I1:
return _sbyte;
case VarEnum.VT_UI1:
return _byte;
case VarEnum.VT_I2:
return _short;
case VarEnum.VT_UI2:
return _ushort;
case VarEnum.VT_I4:
case VarEnum.VT_INT:
return _int32;
case VarEnum.VT_UI4:
case VarEnum.VT_UINT:
return _uint32;
case VarEnum.VT_I8:
return _long;
case VarEnum.VT_UI8:
return _ulong;
case VarEnum.VT_R4:
return _float;
case VarEnum.VT_R8:
return _double;
case VarEnum.VT_BOOL:
return _int32 == -1;
case VarEnum.VT_ERROR:
return _long;
case VarEnum.VT_CY:
return _decimal;
case VarEnum.VT_DATE:
return DateTime.FromOADate(_double);
case VarEnum.VT_FILETIME:
return DateTime.FromFileTime(_long);
case VarEnum.VT_BSTR:
return Marshal.PtrToStringBSTR(_ptr);
case VarEnum.VT_BLOB:
return GetBlobData();
case VarEnum.VT_LPSTR:
return Marshal.PtrToStringAnsi(_ptr);
case VarEnum.VT_LPWSTR:
return Marshal.PtrToStringUni(_ptr);
case VarEnum.VT_UNKNOWN:
return Marshal.GetObjectForIUnknown(_ptr);
case VarEnum.VT_DISPATCH:
return Marshal.GetObjectForIUnknown(_ptr);
case VarEnum.VT_DECIMAL:
return _decimal;
case VarEnum.VT_ARRAY | VarEnum.VT_UNKNOWN:
return CrackSingleDimSafeArray(_ptr);
case (VarEnum.VT_VECTOR | VarEnum.VT_LPWSTR):
return GetVector<string>();
case (VarEnum.VT_VECTOR | VarEnum.VT_I2):
return GetVector<Int16>();
case (VarEnum.VT_VECTOR | VarEnum.VT_UI2):
return GetVector<UInt16>();
case (VarEnum.VT_VECTOR | VarEnum.VT_I4):
return GetVector<Int32>();
case (VarEnum.VT_VECTOR | VarEnum.VT_UI4):
return GetVector<UInt32>();
case (VarEnum.VT_VECTOR | VarEnum.VT_I8):
return GetVector<Int64>();
case (VarEnum.VT_VECTOR | VarEnum.VT_UI8):
return GetVector<UInt64>();
case (VarEnum.VT_VECTOR | VarEnum.VT_R4):
return GetVector<float>();
case (VarEnum.VT_VECTOR | VarEnum.VT_R8):
return GetVector<Double>();
case (VarEnum.VT_VECTOR | VarEnum.VT_BOOL):
return GetVector<Boolean>();
case (VarEnum.VT_VECTOR | VarEnum.VT_FILETIME):
return GetVector<DateTime>();
case (VarEnum.VT_VECTOR | VarEnum.VT_DECIMAL):
return GetVector<Decimal>();
default:
// if the value cannot be marshaled
return null;
}
}
}
#endregion
#region Private Methods
private static long GetFileTimeAsLong(ref System.Runtime.InteropServices.ComTypes.FILETIME val)
{
return (((long)val.dwHighDateTime) << 32) + val.dwLowDateTime;
}
private static System.Runtime.InteropServices.ComTypes.FILETIME DateTimeToFileTime(DateTime value)
{
long hFT = value.ToFileTime();
System.Runtime.InteropServices.ComTypes.FILETIME ft =
new System.Runtime.InteropServices.ComTypes.FILETIME();
ft.dwLowDateTime = (int)(hFT & 0xFFFFFFFF);
ft.dwHighDateTime = (int)(hFT >> 32);
return ft;
}
private object GetBlobData()
{
byte[] blobData = new byte[_int32];
IntPtr pBlobData = _ptr2;
Marshal.Copy(pBlobData, blobData, 0, _int32);
return blobData;
}
private Array GetVector<T>()
{
int count = NativeMethods.PropVariantGetElementCount(this);
if (count <= 0) { return null; }
lock (_padlock)
{
if (_vectorActions == null)
{
_vectorActions = GenerateVectorActions();
}
}
Action<PropVariant, Array, uint> action;
if (!_vectorActions.TryGetValue(typeof(T), out action))
{
throw new InvalidCastException("Cannot be cast to unsupported type.");
}
Array array = new T[count];
for (uint i = 0; i < count; i++)
{
action(this, array, i);
}
return array;
}
private static Array CrackSingleDimSafeArray(IntPtr psa)
{
uint cDims = NativeMethods.SafeArrayGetDim(psa);
if (cDims != 1)
throw new ArgumentException("Multi-dimensional SafeArrays not supported.", "psa");
int lBound = NativeMethods.SafeArrayGetLBound(psa, 1U);
int uBound = NativeMethods.SafeArrayGetUBound(psa, 1U);
int n = uBound - lBound + 1; // uBound is inclusive
object[] array = new object[n];
for (int i = lBound; i <= uBound; ++i)
{
array[i] = NativeMethods.SafeArrayGetElement(psa, ref i);
}
return array;
}
#endregion
#region IDisposable Members
/// <summary>
/// Disposes the object, calls the clear function.
/// </summary>
public void Dispose()
{
NativeMethods.PropVariantClear(this);
GC.SuppressFinalize(this);
}
/// <summary>
/// Finalizer
/// </summary>
~PropVariant()
{
Dispose();
}
#endregion
/// <summary>
/// Provides an simple string representation of the contained data and type.
/// </summary>
/// <returns></returns>
public override string ToString()
{
return string.Format(System.Globalization.CultureInfo.InvariantCulture,
"{0}: {1}", Value, VarType.ToString());
}
}
}

Просмотреть файл

@ -0,0 +1,149 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
using System;
using System.Runtime.InteropServices;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Native
{
/// <summary>
/// Defines a unique key for a Shell Property
/// </summary>
[StructLayout(LayoutKind.Sequential, Pack = 4)]
public struct PropertyKey : IEquatable<PropertyKey>
{
#region Private Fields
private Guid formatId;
private Int32 propertyId;
#endregion
#region Public Properties
/// <summary>
/// A unique GUID for the property
/// </summary>
public Guid FormatId
{
get
{
return formatId;
}
}
/// <summary>
/// Property identifier (PID)
/// </summary>
public Int32 PropertyId
{
get
{
return propertyId;
}
}
#endregion
#region Public Construction
/// <summary>
/// PropertyKey Constructor
/// </summary>
/// <param name="formatId">A unique GUID for the property</param>
/// <param name="propertyId">Property identifier (PID)</param>
public PropertyKey(Guid formatId, Int32 propertyId)
{
this.formatId = formatId;
this.propertyId = propertyId;
}
/// <summary>
/// PropertyKey Constructor
/// </summary>
/// <param name="formatId">A string represenstion of a GUID for the property</param>
/// <param name="propertyId">Property identifier (PID)</param>
public PropertyKey(string formatId, Int32 propertyId)
{
this.formatId = new Guid(formatId);
this.propertyId = propertyId;
}
#endregion
#region IEquatable<PropertyKey> Members
/// <summary>
/// Returns whether this object is equal to another. This is vital for performance of value types.
/// </summary>
/// <param name="other">The object to compare against.</param>
/// <returns>Equality result.</returns>
public bool Equals(PropertyKey other)
{
return other.Equals((object)this);
}
#endregion
#region equality and hashing
/// <summary>
/// Returns the hash code of the object. This is vital for performance of value types.
/// </summary>
/// <returns></returns>
public override int GetHashCode()
{
return formatId.GetHashCode() ^ propertyId;
}
/// <summary>
/// Returns whether this object is equal to another. This is vital for performance of value types.
/// </summary>
/// <param name="obj">The object to compare against.</param>
/// <returns>Equality result.</returns>
public override bool Equals(object obj)
{
if (obj == null)
return false;
if (!(obj is PropertyKey))
return false;
PropertyKey other = (PropertyKey)obj;
return other.formatId.Equals(formatId) && (other.propertyId == propertyId);
}
/// <summary>
/// Implements the == (equality) operator.
/// </summary>
/// <param name="propKey1">First property key to compare.</param>
/// <param name="propKey2">Second property key to compare.</param>
/// <returns>true if object a equals object b. false otherwise.</returns>
public static bool operator ==(PropertyKey propKey1, PropertyKey propKey2)
{
return propKey1.Equals(propKey2);
}
/// <summary>
/// Implements the != (inequality) operator.
/// </summary>
/// <param name="propKey1">First property key to compare</param>
/// <param name="propKey2">Second property key to compare.</param>
/// <returns>true if object a does not equal object b. false otherwise.</returns>
public static bool operator !=(PropertyKey propKey1, PropertyKey propKey2)
{
return !propKey1.Equals(propKey2);
}
/// <summary>
/// Override ToString() to provide a user friendly string representation
/// </summary>
/// <returns>String representing the property key</returns>
public override string ToString()
{
return string.Format(System.Globalization.CultureInfo.InvariantCulture,
"{0}, {1}",
formatId.ToString("B"), propertyId);
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,81 @@
using System;
using System.Runtime.InteropServices;
namespace Microsoft.Internal.Tools.TeamMate.Foundation.Native
{
/// <summary>
/// Exposes PInvoke method wrappers for functions in propsys.dll.
/// </summary>
public static partial class NativeMethods
{
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void InitPropVariantFromPropVariantVectorElem([In] PropVariant propvarIn, uint iElem, [Out] PropVariant ppropvar);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void InitPropVariantFromFileTime([In] ref System.Runtime.InteropServices.ComTypes.FILETIME pftIn, [Out] PropVariant ppropvar);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true)]
[return: MarshalAs(UnmanagedType.I4)]
public static extern int PropVariantGetElementCount([In] PropVariant propVar);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void PropVariantGetBooleanElem([In] PropVariant propVar, [In]uint iElem, [Out, MarshalAs(UnmanagedType.Bool)] out bool pfVal);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void PropVariantGetInt16Elem([In] PropVariant propVar, [In] uint iElem, [Out] out short pnVal);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void PropVariantGetUInt16Elem([In] PropVariant propVar, [In] uint iElem, [Out] out ushort pnVal);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void PropVariantGetInt32Elem([In] PropVariant propVar, [In] uint iElem, [Out] out int pnVal);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void PropVariantGetUInt32Elem([In] PropVariant propVar, [In] uint iElem, [Out] out uint pnVal);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void PropVariantGetInt64Elem([In] PropVariant propVar, [In] uint iElem, [Out] out Int64 pnVal);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void PropVariantGetUInt64Elem([In] PropVariant propVar, [In] uint iElem, [Out] out UInt64 pnVal);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void PropVariantGetDoubleElem([In] PropVariant propVar, [In] uint iElem, [Out] out double pnVal);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void PropVariantGetFileTimeElem([In] PropVariant propVar, [In] uint iElem, [Out, MarshalAs(UnmanagedType.Struct)] out System.Runtime.InteropServices.ComTypes.FILETIME pftVal);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void PropVariantGetStringElem([In] PropVariant propVar, [In] uint iElem, [MarshalAs(UnmanagedType.LPWStr)] ref string ppszVal);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void InitPropVariantFromBooleanVector([In, MarshalAs(UnmanagedType.LPArray)] bool[] prgf, uint cElems, [Out] PropVariant ppropvar);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void InitPropVariantFromInt16Vector([In, Out] Int16[] prgn, uint cElems, [Out] PropVariant ppropvar);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void InitPropVariantFromUInt16Vector([In, Out] UInt16[] prgn, uint cElems, [Out] PropVariant ppropvar);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void InitPropVariantFromInt32Vector([In, Out] Int32[] prgn, uint cElems, [Out] PropVariant propVar);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void InitPropVariantFromUInt32Vector([In, Out] UInt32[] prgn, uint cElems, [Out] PropVariant ppropvar);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void InitPropVariantFromInt64Vector([In, Out] Int64[] prgn, uint cElems, [Out] PropVariant ppropvar);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void InitPropVariantFromUInt64Vector([In, Out] UInt64[] prgn, uint cElems, [Out] PropVariant ppropvar);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void InitPropVariantFromDoubleVector([In, Out] double[] prgn, uint cElems, [Out] PropVariant propvar);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void InitPropVariantFromFileTimeVector([In, Out] System.Runtime.InteropServices.ComTypes.FILETIME[] prgft, uint cElems, [Out] PropVariant ppropvar);
[DllImport("propsys.dll", CharSet = CharSet.Unicode, SetLastError = true, PreserveSig = false)]
public static extern void InitPropVariantFromStringVector([In, Out] string[] prgsz, uint cElems, [Out] PropVariant ppropvar);
}
}

Просмотреть файл

@ -0,0 +1,38 @@
using System;
using System.Runtime.InteropServices;
namespace Microsoft.Internal.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);
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше