Browse Source

Commit

master
vitaliiy@outlook.com 8 years ago
parent
commit
17883e16e1
  1. 14
      IntegrationTests.testsettings
  2. 9
      UnitTests.testsettings
  3. 11
      VSPackageInstall/GlobalSuppressions.cs
  4. 15
      VSPackageInstall/Guids.cs
  5. BIN
      VSPackageInstall/Key.snk
  6. 17
      VSPackageInstall/MyControl.xaml
  7. 35
      VSPackageInstall/MyControl.xaml.cs
  8. 47
      VSPackageInstall/MyToolWindow.cs
  9. 13
      VSPackageInstall/PkgCmdID.cs
  10. 36
      VSPackageInstall/Properties/AssemblyInfo.cs
  11. 81
      VSPackageInstall/Resources.Designer.cs
  12. 135
      VSPackageInstall/Resources.resx
  13. BIN
      VSPackageInstall/Resources/Images.png
  14. BIN
      VSPackageInstall/Resources/Package.ico
  15. 143
      VSPackageInstall/VSPackage.resx
  16. 193
      VSPackageInstall/VSPackageInstall.csproj
  17. 125
      VSPackageInstall/VSPackageInstall.vsct
  18. 147
      VSPackageInstall/VSPackageInstallPackage.cs
  19. 359
      VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/DialogboxPurger.cs
  20. 154
      VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/NativeMethods.cs
  21. 401
      VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/Utils.cs
  22. BIN
      VSPackageInstall/VSPackageInstall_IntegrationTests/Key.snk
  23. 66
      VSPackageInstall/VSPackageInstall_IntegrationTests/MenuItemTest.cs
  24. 59
      VSPackageInstall/VSPackageInstall_IntegrationTests/PackageTest.cs
  25. 109
      VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/CPPProjectTests.cs
  26. 83
      VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/CSharpProjectTests.cs
  27. 55
      VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/SolutionTests.cs
  28. 101
      VSPackageInstall/VSPackageInstall_IntegrationTests/SignOff-Tests/VBProjectTests.cs
  29. 56
      VSPackageInstall/VSPackageInstall_IntegrationTests/ToolWindowTest.cs
  30. 91
      VSPackageInstall/VSPackageInstall_IntegrationTests/VSPackageInstall_IntegrationTests.csproj
  31. BIN
      VSPackageInstall/VSPackageInstall_UnitTests/Key.snk
  32. 80
      VSPackageInstall/VSPackageInstall_UnitTests/MenuItemTests/MenuItemCallback.cs
  33. 76
      VSPackageInstall/VSPackageInstall_UnitTests/MenuItemTests/UIShellServiceMock.cs
  34. 58
      VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/MyToolWindow.cs
  35. 77
      VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/ShowToolWindow.cs
  36. 84
      VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/UIShellServiceMock.cs
  37. 39
      VSPackageInstall/VSPackageInstall_UnitTests/MyToolWindowTest/WindowFrameMock.cs
  38. 56
      VSPackageInstall/VSPackageInstall_UnitTests/PackageTest.cs
  39. 84
      VSPackageInstall/VSPackageInstall_UnitTests/VSPackageInstall_UnitTests.csproj
  40. 18
      VSPackageInstall/source.extension.vsixmanifest
  41. 46
      VsDingExtension.sln

14
IntegrationTests.testsettings

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<TestSettings
id="85f80678-5acf-4267-a4f8-e5bf47bd5e87"
name="Integration Tests"
enableDefaultDataCollectors="false"
xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Description>This test run configuration uses the VS IDE host type in the test run.</Description>
<Deployment enabled="false" />
<Execution>
<Hosts>
<VSSDKTestHostRunConfig name="VS IDE" HiveName="12.0Exp" xmlns="http://microsoft.com/schemas/VisualStudio/SDK/Tools/IdeHostAdapter/2006/06" />
</Hosts>
</Execution>
</TestSettings>

9
UnitTests.testsettings

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<TestSettings
id="906380a7-c058-43a6-8f36-966013e5a9eb"
name="Unit Tests"
enableDefaultDataCollectors="false"
xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010">
<Deployment enabled="false" />
<Description>This test run configuration is used for running the unit tests</Description>
</TestSettings>

11
VSPackageInstall/GlobalSuppressions.cs

@ -0,0 +1,11 @@
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project. Project-level
// suppressions either have no target or are given a specific target
// and scoped to a namespace, type, member, etc.
//
// To add a suppression to this file, right-click the message in the
// Error List, point to "Suppress Message(s)", and click "In Project
// Suppression File". You do not need to add suppressions to this
// file manually.
[assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1017:MarkAssembliesWithComVisible")]

15
VSPackageInstall/Guids.cs

@ -0,0 +1,15 @@
// Guids.cs
// MUST match guids.h
using System;
namespace VitaliiGanzha.VSPackageInstall
{
static class GuidList
{
public const string guidVSPackageInstallPkgString = "a527a9c1-ec2f-46a0-a6e3-371859c5845b";
public const string guidVSPackageInstallCmdSetString = "4fddc919-41be-47b6-ae59-7125c75d1f1e";
public const string guidToolWindowPersistanceString = "a6862923-42ae-438f-ac76-7a68be1011e3";
public static readonly Guid guidVSPackageInstallCmdSet = new Guid(guidVSPackageInstallCmdSetString);
};
}

BIN
VSPackageInstall/Key.snk

Binary file not shown.

17
VSPackageInstall/MyControl.xaml

@ -0,0 +1,17 @@
<UserControl x:Class="VitaliiGanzha.VSPackageInstall.MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
Background="{DynamicResource VsBrush.Window}"
Foreground="{DynamicResource VsBrush.WindowText}"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Name="MyToolWindow">
<Grid>
<StackPanel Orientation="Vertical">
<TextBlock Margin="10" HorizontalAlignment="Center">VS Ding</TextBlock>
<Button Content="_Click Me!" Click="button1_Click" Width="120" Height="80" Name="button1"/>
</StackPanel>
</Grid>
</UserControl>

35
VSPackageInstall/MyControl.xaml.cs

@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace VitaliiGanzha.VSPackageInstall
{
/// <summary>
/// Interaction logic for MyControl.xaml
/// </summary>
public partial class MyControl : UserControl
{
public MyControl()
{
InitializeComponent();
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1300:SpecifyMessageBoxOptions")]
private void button1_Click(object sender, RoutedEventArgs e)
{
MessageBox.Show(string.Format(System.Globalization.CultureInfo.CurrentUICulture, "We are inside {0}.button1_Click()", this.ToString()),
"VS Ding");
}
}
}

47
VSPackageInstall/MyToolWindow.cs

@ -0,0 +1,47 @@
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Windows;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;
namespace VitaliiGanzha.VSPackageInstall
{
/// <summary>
/// This class implements the tool window exposed by this package and hosts a user control.
///
/// In Visual Studio tool windows are composed of a frame (implemented by the shell) and a pane,
/// usually implemented by the package implementer.
///
/// This class derives from the ToolWindowPane class provided from the MPF in order to use its
/// implementation of the IVsUIElementPane interface.
/// </summary>
[Guid("a6862923-42ae-438f-ac76-7a68be1011e3")]
public class MyToolWindow : ToolWindowPane
{
/// <summary>
/// Standard constructor for the tool window.
/// </summary>
public MyToolWindow() :
base(null)
{
// Set the window title reading it from the resources.
this.Caption = Resources.ToolWindowTitle;
// Set the image that will appear on the tab of the window frame
// when docked with an other window
// The resource ID correspond to the one defined in the resx file
// while the Index is the offset in the bitmap strip. Each image in
// the strip being 16x16.
this.BitmapResourceID = 301;
this.BitmapIndex = 1;
// This is the user control hosted by the tool window; Note that, even if this class implements IDisposable,
// we are not calling Dispose on this object. This is because ToolWindowPane calls Dispose on
// the object returned by the Content property.
base.Content = new MyControl();
}
}
}

13
VSPackageInstall/PkgCmdID.cs

@ -0,0 +1,13 @@
// PkgCmdID.cs
// MUST match PkgCmdID.h
using System;
namespace VitaliiGanzha.VSPackageInstall
{
static class PkgCmdIDList
{
public const uint cmdidVsDing = 0x100;
public const uint cmdidVsDingWnd = 0x101;
};
}

36
VSPackageInstall/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@
using System;
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: AssemblyTitle("VSPackageInstall")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Vitalii Ganzha")]
[assembly: AssemblyProduct("VSPackageInstall")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
[assembly: CLSCompliant(false)]
[assembly: NeutralResourcesLanguage("en-US")]
// 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 Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: InternalsVisibleTo("VSPackageInstall_IntegrationTests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004bcbc34c62abe4c7cbb70dd208ebb4958e5f0fa40d49b5cb7745114737e7deba8e9227e32bb0c06fba88912c428184c837e96865ef4f98d7302d5f9f184a93906e2fdd69f9defe190ad7605078c48a780222cd33b3655512d71febdf8bfcf755ccb9037b9369939cd85bcc0b1ef12938bd1b6802f9284e657dd7d386555209b5")]
[assembly: InternalsVisibleTo("VSPackageInstall_UnitTests, PublicKey=00240000048000009400000006020000002400005253413100040000010001004bcbc34c62abe4c7cbb70dd208ebb4958e5f0fa40d49b5cb7745114737e7deba8e9227e32bb0c06fba88912c428184c837e96865ef4f98d7302d5f9f184a93906e2fdd69f9defe190ad7605078c48a780222cd33b3655512d71febdf8bfcf755ccb9037b9369939cd85bcc0b1ef12938bd1b6802f9284e657dd7d386555209b5")]

81
VSPackageInstall/Resources.Designer.cs

@ -0,0 +1,81 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.42
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace VitaliiGanzha.VSPackageInstall {
using System;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("VitaliiGanzha.VSPackageInstall.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// Looks up a localized string similar to Can not create tool window..
/// </summary>
internal static string CanNotCreateWindow {
get {
return ResourceManager.GetString("CanNotCreateWindow", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to My Tool Window.
/// </summary>
internal static string ToolWindowTitle {
get {
return ResourceManager.GetString("ToolWindowTitle", resourceCulture);
}
}
}
}

135
VSPackageInstall/Resources.resx

@ -0,0 +1,135 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
VS SDK Notes: This resx file contains the resources that will be consumed directly by your package.
For example, if you chose to create a tool window, there is a resource with ID 'CanNotCreateWindow'. This
is used in VsPkg.cs to determine the string to show the user if there is an error when attempting to create
the tool window.
Resources that are accessed directly from your package *by Visual Studio* are stored in the VSPackage.resx
file.
-->
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="CanNotCreateWindow" xml:space="preserve">
<value>Can not create tool window.</value>
</data>
<data name="ToolWindowTitle" xml:space="preserve">
<value>VS Ding</value>
</data>
</root>

BIN
VSPackageInstall/Resources/Images.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 994 B

BIN
VSPackageInstall/Resources/Package.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

143
VSPackageInstall/VSPackage.resx

@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
VS SDK Notes: This resx file contains the resources that will be consumed from your package by Visual Studio.
For example, Visual Studio will attempt to load resource '400' from this resource stream when it needs to
load your package's icon. Because Visual Studio will always look in the VSPackage.resources stream first for
resources it needs, you should put additional resources that Visual Studio will load directly into this resx
file.
Resources that you would like to access directly from your package in a strong-typed fashion should be stored
in Resources.resx or another resx file.
-->
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="110" xml:space="preserve">
<value>VSPackageInstall</value>
</data>
<data name="112" xml:space="preserve">
<value>Visual Studio sound notifications</value>
</data>
<data name="400" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\Package.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="301" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>Resources\Images.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
</root>

193
VSPackageInstall/VSPackageInstall.csproj

@ -0,0 +1,193 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="12.0">
<PropertyGroup>
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">12.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
</PropertyGroup>
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')"/>
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{20191d13-7cc1-4f9b-9cb8-42f22ace4ca6}</ProjectGuid>
<ProjectTypeGuids>{82b43b9b-a64c-4715-b499-d71e9ca2bd60};{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>VitaliiGanzha.VSPackageInstall</RootNamespace>
<AssemblyName>VSPackageInstall</AssemblyName>
<SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>Key.snk</AssemblyOriginatorKeyFile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<RunCodeAnalysis>true</RunCodeAnalysis>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.VisualStudio.OLE.Interop" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop.8.0" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop.9.0" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop.10.0" />
<Reference Include="Microsoft.VisualStudio.Shell.Interop.11.0">
<EmbedInteropTypes>true</EmbedInteropTypes>
</Reference>
<Reference Include="Microsoft.VisualStudio.Shell.Interop.12.0">
<EmbedInteropTypes>true</EmbedInteropTypes>
</Reference>
<Reference Include="Microsoft.VisualStudio.TextManager.Interop" />
<Reference Include="Microsoft.VisualStudio.Shell.12.0" />
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.10.0" />
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.11.0" />
<Reference Include="Microsoft.VisualStudio.Shell.Immutable.12.0" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Data" />
<Reference Include="System.Design" />
<Reference Include="System.Drawing" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="WindowsBase" />
<Reference Include="System.Xaml" />
</ItemGroup>
<ItemGroup>
<COMReference Include="EnvDTE">
<Guid>{80CC9F66-E7D8-4DDD-85B6-D9E6CD0E93E2}</Guid>
<VersionMajor>8</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
<COMReference Include="EnvDTE100">
<Guid>{26AD1324-4B7C-44BC-84F8-B86AED45729F}</Guid>
<VersionMajor>10</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
<COMReference Include="EnvDTE80">
<Guid>{1A31287A-4D7D-413E-8E32-3B374931BD89}</Guid>
<VersionMajor>8</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
<COMReference Include="EnvDTE90">
<Guid>{2CE2370E-D744-4936-A090-3FFFE667B0E1}</Guid>
<VersionMajor>9</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
<COMReference Include="Microsoft.VisualStudio.CommandBars">
<Guid>{1CBA492E-7263-47BB-87FE-639000619B15}</Guid>
<VersionMajor>8</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
<COMReference Include="stdole">
<Guid>{00020430-0000-0000-C000-000000000046}</Guid>
<VersionMajor>2</VersionMajor>
<VersionMinor>0</VersionMinor>
<Lcid>0</Lcid>
<WrapperTool>primary</WrapperTool>
<Isolated>False</Isolated>
<EmbedInteropTypes>False</EmbedInteropTypes>
</COMReference>
</ItemGroup>
<ItemGroup>
<Compile Include="MyControl.xaml.cs">
<DependentUpon>MyControl.xaml</DependentUpon>
</Compile>
<Compile Include="MyToolWindow.cs" />
<Compile Include="Guids.cs" />
<Compile Include="Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="GlobalSuppressions.cs" />
<Compile Include="VSPackageInstallPackage.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="PkgCmdID.cs" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="VSPackage.resx">
<MergeWithCTO>true</MergeWithCTO>
<ManifestResourceName>VSPackage</ManifestResourceName>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="source.extension.vsixmanifest">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<None Include="Key.snk" />
</ItemGroup>
<ItemGroup>
<VSCTCompile Include="VSPackageInstall.vsct">
<ResourceName>Menus.ctmenu</ResourceName>
</VSCTCompile>
</ItemGroup>
<ItemGroup>
<None Include="Resources\Images.png" />
</ItemGroup>
<ItemGroup>
<Content Include="Resources\Package.ico" />
</ItemGroup>
<ItemGroup>
<Page Include="MyControl.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<PropertyGroup>
<UseCodebase>true</UseCodebase>
</PropertyGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(VSToolsPath)\VSSDK\Microsoft.VsSDK.targets" Condition="'$(VSToolsPath)' != ''" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

125
VSPackageInstall/VSPackageInstall.vsct

@ -0,0 +1,125 @@
<?xml version="1.0" encoding="utf-8"?>
<CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This is the file that defines the actual layout and type of the commands.
It is divided in different sections (e.g. command definition, command
placement, ...), with each defining a specific set of properties.
See the comment before each section for more details about how to
use it. -->
<!-- The VSCT compiler (the tool that translates this file into the binary
format that VisualStudio will consume) has the ability to run a preprocessor
on the vsct file; this preprocessor is (usually) the C++ preprocessor, so
it is possible to define includes and macros with the same syntax used
in C++ files. Using this ability of the compiler here, we include some files
defining some of the constants that we will use inside the file. -->
<!--This is the file that defines the IDs for all the commands exposed by VisualStudio. -->
<Extern href="stdidcmd.h"/>
<!--This header contains the command ids for the menus provided by the shell. -->
<Extern href="vsshlids.h"/>
<!--The Commands section is where we the commands, menus and menu groups are defined.
This section uses a Guid to identify the package that provides the command defined inside it. -->
<Commands package="guidVSPackageInstallPkg">
<!-- Inside this section we have different sub-sections: one for the menus, another
for the menu groups, one for the buttons (the actual commands), one for the combos
and the last one for the bitmaps used. Each element is identified by a command id that
is a unique pair of guid and numeric identifier; the guid part of the identifier is usually
called "command set" and is used to group different command inside a logically related
group; your package should define its own command set in order to avoid collisions
with command ids defined by other packages. -->
<!-- In this section you can define new menu groups. A menu group is a container for
other menus or buttons (commands); from a visual point of view you can see the
group as the part of a menu contained between two lines. The parent of a group
must be a menu. -->
<Groups>
<Group guid="guidVSPackageInstallCmdSet" id="MyMenuGroup" priority="0x0600">
<Parent guid="guidSHLMainMenu" id="IDM_VS_MENU_TOOLS"/>
</Group>
</Groups>
<!--Buttons section. -->
<!--This section defines the elements the user can interact with, like a menu command or a button
or combo box in a toolbar. -->
<Buttons>
<!--To define a menu group you have to specify its ID, the parent menu and its display priority.
The command is visible and enabled by default. If you need to change the visibility, status, etc, you can use
the CommandFlag node.
You can add more than one CommandFlag node e.g.:
<CommandFlag>DefaultInvisible</CommandFlag>
<CommandFlag>DynamicVisibility</CommandFlag>
If you do not want an image next to your command, remove the Icon node /> -->
<Button guid="guidVSPackageInstallCmdSet" id="cmdidVsDing" priority="0x0100" type="Button">
<Parent guid="guidVSPackageInstallCmdSet" id="MyMenuGroup" />
<Icon guid="guidImages" id="bmpPic1" />
<Strings>
<ButtonText>VisualStudioDing</ButtonText>
</Strings>
</Button>
<Button guid="guidVSPackageInstallCmdSet" id="cmdidVsDingWnd" priority="0x0100" type="Button">
<Parent guid="guidSHLMainMenu" id="IDG_VS_WNDO_OTRWNDWS1"/>
<Icon guid="guidImages" id="bmpPic2" />
<Strings>
<ButtonText>VS Ding</ButtonText>
</Strings>
</Button>
</Buttons>
<!--The bitmaps section is used to define the bitmaps that are used for the commands.-->
<Bitmaps>
<!-- The bitmap id is defined in a way that is a little bit different from the others:
the declaration starts with a guid for the bitmap strip, then there is the resource id of the
bitmap strip containing the bitmaps and then there are the numeric ids of the elements used
inside a button definition. An important aspect of this declaration is that the element id
must be the actual index (1-based) of the bitmap inside the bitmap strip. -->
<Bitmap guid="guidImages" href="Resources\Images.png" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows"/>
</Bitmaps>
</Commands>
<Symbols>
<!-- This is the package guid. -->
<GuidSymbol name="guidVSPackageInstallPkg" value="{a527a9c1-ec2f-46a0-a6e3-371859c5845b}" />
<!-- This is the guid used to group the menu commands together -->
<GuidSymbol name="guidVSPackageInstallCmdSet" value="{4fddc919-41be-47b6-ae59-7125c75d1f1e}">
<IDSymbol name="MyMenuGroup" value="0x1020" />
<IDSymbol name="cmdidVsDing" value="0x0100" />
<IDSymbol name="cmdidVsDingWnd" value="0x0101" />
</GuidSymbol>
<GuidSymbol name="guidImages" value="{d803fcb0-9af3-476e-a494-3dbb574f3b33}" >
<IDSymbol name="bmpPic1" value="1" />
<IDSymbol name="bmpPic2" value="2" />
<IDSymbol name="bmpPicSearch" value="3" />
<IDSymbol name="bmpPicX" value="4" />
<IDSymbol name="bmpPicArrows" value="5" />
<IDSymbol name="bmpPicStrikethrough" value="6" />
</GuidSymbol>
</Symbols>
</CommandTable>

147
VSPackageInstall/VSPackageInstallPackage.cs

@ -0,0 +1,147 @@
using System;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.ComponentModel.Design;
using EnvDTE;
using EnvDTE80;
using Microsoft.Win32;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.OLE.Interop;
using Microsoft.VisualStudio.Shell;
namespace VitaliiGanzha.VSPackageInstall
{
/// <summary>
/// This is the class that implements the package exposed by this assembly.
///
/// The minimum requirement for a class to be considered a valid package for Visual Studio
/// is to implement the IVsPackage interface and register itself with the shell.
/// This package uses the helper classes defined inside the Managed Package Framework (MPF)
/// to do it: it derives from the Package class that provides the implementation of the
/// IVsPackage interface and uses the registration attributes defined in the framework to
/// register itself and its components with the shell.
/// </summary>
// This attribute tells the PkgDef creation utility (CreatePkgDef.exe) that this class is
// a package.
[PackageRegistration(UseManagedResourcesOnly = true)]
// This attribute is used to register the information needed to show this package
// in the Help/About dialog of Visual Studio.
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
// This attribute is needed to let the shell know that this package exposes some menus.
[ProvideMenuResource("Menus.ctmenu", 1)]
// This attribute registers a tool window exposed by this package.
[ProvideToolWindow(typeof(MyToolWindow))]
[Guid(GuidList.guidVSPackageInstallPkgString)]
public sealed class VSPackageInstallPackage : Package
{
private DTE2 applicationObject;
private AddIn addInInstance;
/// <summary>
/// Default constructor of the package.
/// Inside this method you can place any initialization code that does not require
/// any Visual Studio service because at this point the package object is created but
/// not sited yet inside Visual Studio environment. The place to do all the other
/// initialization is the Initialize method.
/// </summary>
public VSPackageInstallPackage()
{
Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering constructor for: {0}", this.ToString()));
}
/// <summary>
/// This function is called when the user clicks the menu item that shows the
/// tool window. See the Initialize method to see how the menu item is associated to
/// this function using the OleMenuCommandService service and the MenuCommand class.
/// </summary>
private void ShowToolWindow(object sender, EventArgs e)
{
// Get the instance number 0 of this tool window. This window is single instance so this instance
// is actually the only one.
// The last flag is set to true so that if the tool window does not exists it will be created.
ToolWindowPane window = this.FindToolWindow(typeof(MyToolWindow), 0, true);
if ((null == window) || (null == window.Frame))
{
throw new NotSupportedException(Resources.CanNotCreateWindow);
}
IVsWindowFrame windowFrame = (IVsWindowFrame)window.Frame;
Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(windowFrame.Show());
}
/////////////////////////////////////////////////////////////////////////////
// Overridden Package Implementation
#region Package Members
/// <summary>
/// Initialization of the package; this method is called right after the package is sited, so this is the place
/// where you can put all the initialization code that rely on services provided by VisualStudio.
/// </summary>
protected override void Initialize()
{
try
{
Debug.WriteLine(string.Format(CultureInfo.CurrentCulture, "Entering Initialize() of: {0}", this.ToString()));
base.Initialize();
// Add our command handlers for menu (commands must exist in the .vsct file)
OleMenuCommandService mcs = GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
if (null != mcs)
{
// Create the command for the menu item.
CommandID menuCommandID = new CommandID(GuidList.guidVSPackageInstallCmdSet, (int)PkgCmdIDList.cmdidVsDing);
MenuCommand menuItem = new MenuCommand(MenuItemCallback, menuCommandID);
mcs.AddCommand(menuItem);
// Create the command for the tool window
CommandID toolwndCommandID = new CommandID(GuidList.guidVSPackageInstallCmdSet, (int)PkgCmdIDList.cmdidVsDingWnd);
MenuCommand menuToolWin = new MenuCommand(ShowToolWindow, toolwndCommandID);
mcs.AddCommand(menuToolWin);
}
applicationObject = (DTE2)GetService(typeof(DTE));
applicationObject.Events.BuildEvents.OnBuildDone += BuildEventsOnOnBuildDone;
}
catch (Exception e)
{
File.WriteAllText(@"c:\temp\test.txt", e.Message);
}
}
private void BuildEventsOnOnBuildDone(vsBuildScope scope, vsBuildAction action)
{
System.Media.SystemSounds.Asterisk.Play();
}
#endregion
/// <summary>
/// This function is the callback used to execute a command when the a menu item is clicked.
/// See the Initialize method to see how the menu item is associated to this function using
/// the OleMenuCommandService service and the MenuCommand class.
/// </summary>
private void MenuItemCallback(object sender, EventArgs e)
{
// Show a Message Box to prove we were here
IVsUIShell uiShell = (IVsUIShell)GetService(typeof(SVsUIShell));
Guid clsid = Guid.Empty;
int result;
Microsoft.VisualStudio.ErrorHandler.ThrowOnFailure(uiShell.ShowMessageBox(
0,
ref clsid,
"VSPackageInstall",
string.Format(CultureInfo.CurrentCulture, "Inside {0}.MenuItemCallback()", this.ToString()),
string.Empty,
0,
OLEMSGBUTTON.OLEMSGBUTTON_OK,
OLEMSGDEFBUTTON.OLEMSGDEFBUTTON_FIRST,
OLEMSGICON.OLEMSGICON_INFO,
0, // false
out result));
}
}
}

359
VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/DialogboxPurger.cs

@ -0,0 +1,359 @@

namespace Microsoft.VsSDK.IntegrationTestLibrary
{
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;
/// <summary>
/// This class is responsible to close dialog boxes that pop up during different VS Calls
/// </summary>
internal class DialogBoxPurger : IDisposable
{
/// <summary>
/// The default number of milliseconds to wait for the threads to signal to terminate.
/// </summary>
private const int DefaultMillisecondsToWait = 3500;
/// <summary>
/// Object used for synchronization between thread calls.
/// </summary>
internal static volatile object Mutex = new object();
/// <summary>
/// The IVsUIShell. This cannot be queried on the working thread from the service provider. Must be done in the main thread.!!
/// </summary>
private IVsUIShell uiShell;
/// <summary>
/// The button to "press" on the dialog.
/// </summary>
private int buttonAction;
/// <summary>
/// Thread signales to the calling thread that it is done.
/// </summary>
private bool exitThread = false;
/// <summary>
/// Calling thread signales to this thread to die.
/// </summary>
private AutoResetEvent threadDone = new AutoResetEvent(false);
/// <summary>
/// The queued thread started.
/// </summary>
private AutoResetEvent threadStarted = new AutoResetEvent(false);
/// <summary>
/// The result of the dialogbox closing for all the dialog boxes. That is if there are two of them and one fails this will be false.
/// </summary>
private bool dialogBoxCloseResult = false;
/// <summary>
/// The expected text to see on the dialog box. If set the thread will continue finding the dialog box with this text.
/// </summary>
private string expectedDialogBoxText = String.Empty;
/// <summary>
/// The number of the same dialog boxes to wait for.
/// This is for scenarios when two dialog boxes with the same text are popping up.
/// </summary>
private int numberOfDialogsToWaitFor = 1;
/// <summary>
/// Has the object been disposed.
/// </summary>
private bool isDisposed;
/// <summary>
/// Overloaded ctor.
/// </summary>
/// <param name="buttonAction">The botton to "press" on the dialog box.</param>
/// <param name="numberOfDialogsToWaitFor">The number of dialog boxes with the same message to wait for. This is the situation when the same action pops up two of the same dialog boxes</param>
/// <param name="expectedDialogMesssage">The expected dialog box message to check for.</param>
internal DialogBoxPurger(int buttonAction, int numberOfDialogsToWaitFor, string expectedDialogMesssage)
{
this.buttonAction = buttonAction;
this.numberOfDialogsToWaitFor = numberOfDialogsToWaitFor;
this.expectedDialogBoxText = expectedDialogMesssage;
}
/// <summary>
/// Overloaded ctor.
/// </summary>
/// <param name="buttonAction">The botton to "press" on the dialog box.</param>
/// <param name="numberOfDialogsToWaitFor">The number of dialog boxes with the same message to wait for. This is the situation when the same action pops up two of the same dialog boxes</param>
internal DialogBoxPurger(int buttonAction, int numberOfDialogsToWaitFor)
{
this.buttonAction = buttonAction;
this.numberOfDialogsToWaitFor = numberOfDialogsToWaitFor;
}
/// <summary>
/// Overloaded ctor.
/// </summary>
/// <param name="buttonAction">The botton to "press" on the dialog box.</param>
/// <param name="expectedDialogMesssage">The expected dialog box message to check for.</param>
internal DialogBoxPurger(int buttonAction, string expectedDialogMesssage)
{
this.buttonAction = buttonAction;
this.expectedDialogBoxText = expectedDialogMesssage;
}
/// <summary>
/// Overloaded ctor.
/// </summary>
/// <param name="buttonAction">The botton to "press" on the dialog box.</param>
internal DialogBoxPurger(int buttonAction)
{
this.buttonAction = buttonAction;
}
/// <summary>
#region IDisposable Members
void IDisposable.Dispose()
{
if (this.isDisposed)
{
return;
}
this.WaitForDialogThreadToTerminate();
this.isDisposed = true;
}
/// <summary>
/// Spawns a thread that will start listening to dialog boxes.
/// </summary>
internal void Start()
{
// We ask for the uishell here since we cannot do that on the therad that we will spawn.
IVsUIShell uiShell = Package.GetGlobalService(typeof(SVsUIShell)) as IVsUIShell;
if (uiShell == null)
{
throw new InvalidOperationException("Could not get the uiShell from the serviceProvider");
}
this.uiShell = uiShell;
System.Threading.Thread thread = new System.Threading.Thread(new ThreadStart(this.HandleDialogBoxes));
thread.Start();
// We should never deadlock here, hence do not use the lock. Wait to be sure that the thread started.
this.threadStarted.WaitOne(3500, false);
}
/// <summary>
/// Waits for the dialog box close thread to terminate. If the thread does not signal back within millisecondsToWait that it is shutting down,
/// then it will tell to the thread to do it.
/// </summary>
internal bool WaitForDialogThreadToTerminate()
{
return this.WaitForDialogThreadToTerminate(DefaultMillisecondsToWait);
}
/// <summary>
/// Waits for the dialog box close thread to terminate. If the thread does not signal back within millisecondsToWait that it is shutting down,
/// then it will tell to the thread to do it.
/// </summary>
/// <param name="millisecondsToWait">The number milliseconds to wait for until the dialog purger thread is signaled to terminate. This is just for safe precaution that we do not hang. </param>
/// <returns>The result of the dialog boxes closing</returns>
internal bool WaitForDialogThreadToTerminate(int numberOfMillisecondsToWait)
{
bool signaled = false;
// We give millisecondsToWait sec to bring up and close the dialog box.
signaled = this.threadDone.WaitOne(numberOfMillisecondsToWait, false);
// Kill the thread since a timeout occured.
if (!signaled)
{
lock (Mutex)
{
// Set the exit thread to true. Next time the thread will kill itselfes if it sees
this.exitThread = true;
}
// Wait for the thread to finish. We should never deadlock here.
this.threadDone.WaitOne();
}
return this.dialogBoxCloseResult;
}
/// <summary>
/// This is the thread method.
/// </summary>
private void HandleDialogBoxes()
{
// No synchronization numberOfDialogsToWaitFor since it is readonly
IntPtr[] hwnds = new IntPtr[this.numberOfDialogsToWaitFor];
bool[] dialogBoxCloseResults = new bool[this.numberOfDialogsToWaitFor];
try
{
// Signal that we started
lock (Mutex)
{
this.threadStarted.Set();
}
// The loop will be exited either if a message is send by the caller thread or if we found the dialog. If a message box text is specified the loop will not exit until the dialog is found.
bool stayInLoop = true;
int dialogBoxesToWaitFor = 1;
while (stayInLoop)
{
int hwndIndex = dialogBoxesToWaitFor - 1;
// We need to lock since the caller might set context to null.
lock (Mutex)
{
if (this.exitThread)
{
break;
}
// We protect the shell too from reentrency.
this.uiShell.GetDialogOwnerHwnd(out hwnds[hwndIndex]);
}
if (hwnds[hwndIndex] != IntPtr.Zero)
{
StringBuilder windowClassName = new StringBuilder(256);
NativeMethods.GetClassName(hwnds[hwndIndex], windowClassName, windowClassName.Capacity);
// The #32770 is the class name of a messagebox dialog.
if (windowClassName.ToString().Contains("#32770"))
{
IntPtr unmanagedMemoryLocation = IntPtr.Zero;
string dialogBoxText = String.Empty;
try
{
unmanagedMemoryLocation = Marshal.AllocHGlobal(10 * 1024);
NativeMethods.EnumChildWindows(hwnds[hwndIndex], new NativeMethods.CallBack(FindMessageBoxString), unmanagedMemoryLocation);
dialogBoxText = Marshal.PtrToStringUni(unmanagedMemoryLocation);
}
finally
{
if (unmanagedMemoryLocation != IntPtr.Zero)
{
Marshal.FreeHGlobal(unmanagedMemoryLocation);
}
}
lock (Mutex)
{
// Since this is running on the main thread be sure that we close the dialog.
bool dialogCloseResult = false;
if (this.buttonAction != 0)
{
dialogCloseResult = NativeMethods.EndDialog(hwnds[hwndIndex], this.buttonAction);
}
// Check if we have found the right dialog box.
if (String.IsNullOrEmpty(this.expectedDialogBoxText) || (!String.IsNullOrEmpty(dialogBoxText) && String.Compare(this.expectedDialogBoxText, dialogBoxText.Trim(), StringComparison.OrdinalIgnoreCase) == 0))
{
dialogBoxCloseResults[hwndIndex] = dialogCloseResult;
if (dialogBoxesToWaitFor++ >= this.numberOfDialogsToWaitFor)
{
stayInLoop = false;
}
}
}
}
}
}
}
finally
{
//Let the main thread run a possible close command.
System.Threading.Thread.Sleep(2000);
foreach (IntPtr hwnd in hwnds)
{
// At this point the dialog should be closed, if not attempt to close it.
if (hwnd != IntPtr.Zero)
{
NativeMethods.SendMessage(hwnd, NativeMethods.WM_CLOSE, 0, new IntPtr(0));
}
}
lock (Mutex)
{
// Be optimistic.
this.dialogBoxCloseResult = true;
for (int i = 0; i < dialogBoxCloseResults.Length; i++)
{
if (!dialogBoxCloseResults[i])
{
this.dialogBoxCloseResult = false;
break;
}
}
this.threadDone.Set();
}
}
}
/// <summary>
/// Finds a messagebox string on a messagebox.
/// </summary>
/// <param name="hwnd">The windows handle of the dialog</param>
/// <param name="unmanagedMemoryLocation">A pointer to the memorylocation the string will be written to</param>
/// <returns>True if found.</returns>
private static bool FindMessageBoxString(IntPtr hwnd, IntPtr unmanagedMemoryLocation)
{
StringBuilder sb = new StringBuilder(512);
NativeMethods.GetClassName(hwnd, sb, sb.Capacity);
if (sb.ToString().ToLower().Contains("static"))
{
StringBuilder windowText = new StringBuilder(2048);
NativeMethods.GetWindowText(hwnd, windowText, windowText.Capacity);
if (windowText.Length > 0)
{
IntPtr stringAsPtr = IntPtr.Zero;
try
{
stringAsPtr = Marshal.StringToHGlobalAnsi(windowText.ToString());
char[] stringAsArray = windowText.ToString().ToCharArray();
// Since unicode characters are copied check if we are out of the allocated length.
// If not add the end terminating zero.
if ((2 * stringAsArray.Length) + 1 < 2048)
{
Marshal.Copy(stringAsArray, 0, unmanagedMemoryLocation, stringAsArray.Length);
Marshal.WriteInt32(unmanagedMemoryLocation, 2 * stringAsArray.Length, 0);
}
}
finally
{
if (stringAsPtr != IntPtr.Zero)
{
Marshal.FreeHGlobal(stringAsPtr);
}
}
return false;
}
}
return true;
}
#endregion
}
}

154
VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/NativeMethods.cs

@ -0,0 +1,154 @@
/***************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
This code is licensed under the Visual Studio SDK license terms.
THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
***************************************************************************/
namespace Microsoft.VsSDK.IntegrationTestLibrary
{
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Threading;
using Microsoft.VisualStudio.Shell.Interop;
/// <summary>
/// Defines pinvoked utility methods and internal VS Constants
/// </summary>
internal static class NativeMethods
{
internal delegate bool CallBack(IntPtr hwnd, IntPtr lParam);
// Declare two overloaded SendMessage functions
[DllImport("user32.dll")]
internal static extern UInt32 SendMessage(IntPtr hWnd, UInt32 Msg,
UInt32 wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
internal static extern bool PeekMessage([In, Out] ref Microsoft.VisualStudio.OLE.Interop.MSG msg, HandleRef hwnd, int msgMin, int msgMax, int remove);
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
internal static extern bool TranslateMessage([In, Out] ref Microsoft.VisualStudio.OLE.Interop.MSG msg);
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
internal static extern int DispatchMessage([In] ref Microsoft.VisualStudio.OLE.Interop.MSG msg);
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
internal static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool attach);
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
internal static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("kernel32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
internal static extern uint GetCurrentThreadId();
[DllImport("user32")]
internal static extern int EnumChildWindows(IntPtr hwnd, CallBack x, IntPtr y);
[DllImport("user32")]
internal static extern bool IsWindowVisible(IntPtr hDlg);
[DllImport("user32.dll", CharSet = System.Runtime.InteropServices.CharSet.Auto)]
internal static extern IntPtr SetFocus(IntPtr hWnd);
[DllImport("user32")]
internal static extern int GetClassName(IntPtr hWnd,
StringBuilder className,
int stringLength);
[DllImport("user32")]
internal static extern int GetWindowText(IntPtr hWnd, StringBuilder className, int stringLength);
[DllImport("user32")]
internal static extern bool EndDialog(IntPtr hDlg, int result);
[DllImport("Kernel32")]
internal static extern long GetLastError();
internal const int QS_KEY = 0x0001,
QS_MOUSEMOVE = 0x0002,
QS_MOUSEBUTTON = 0x0004,
QS_POSTMESSAGE = 0x0008,
QS_TIMER = 0x0010,
QS_PAINT = 0x0020,
QS_SENDMESSAGE = 0x0040,
QS_HOTKEY = 0x0080,
QS_ALLPOSTMESSAGE = 0x0100,
QS_MOUSE = QS_MOUSEMOVE | QS_MOUSEBUTTON,
QS_INPUT = QS_MOUSE | QS_KEY,
QS_ALLEVENTS = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY,
QS_ALLINPUT = QS_INPUT | QS_POSTMESSAGE | QS_TIMER | QS_PAINT | QS_HOTKEY | QS_SENDMESSAGE;
internal const int Facility_Win32 = 7;
internal const int WM_CLOSE = 0x0010;
internal const int
S_FALSE = 0x00000001,
S_OK = 0x00000000,
IDOK = 1,
IDCANCEL = 2,
IDABORT = 3,
IDRETRY = 4,
IDIGNORE = 5,
IDYES = 6,
IDNO = 7,
IDCLOSE = 8,
IDHELP = 9,
IDTRYAGAIN = 10,
IDCONTINUE = 11;
internal static long HResultFromWin32(long error)
{
if (error <= 0)
{
return error;
}
return ((error & 0x0000FFFF) | (Facility_Win32 << 16) | 0x80000000);
}
/// <devdoc>
/// Please use this "approved" method to compare file names.
/// </devdoc>
public static bool IsSamePath(string file1, string file2)
{
if (file1 == null || file1.Length == 0)
{
return (file2 == null || file2.Length == 0);
}
Uri uri1 = null;
Uri uri2 = null;
try
{
if (!Uri.TryCreate(file1, UriKind.Absolute, out uri1) || !Uri.TryCreate(file2, UriKind.Absolute, out uri2))
{
return false;
}
if (uri1 != null && uri1.IsFile && uri2 != null && uri2.IsFile)
{
return 0 == String.Compare(uri1.LocalPath, uri2.LocalPath, StringComparison.OrdinalIgnoreCase);
}
return file1 == file2;
}
catch (UriFormatException e)
{
System.Diagnostics.Trace.WriteLine("Exception " + e.Message);
}
return false;
}
}
}

401
VSPackageInstall/VSPackageInstall_IntegrationTests/IntegrationTest Library/Utils.cs

@ -0,0 +1,401 @@
using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Runtime.InteropServices;
using Microsoft.VisualStudio.Shell.Interop;
using Microsoft.VisualStudio.Shell;
using EnvDTE;
using EnvDTE80;
using Microsoft.Win32;
using IOleServiceProvider = Microsoft.VisualStudio.OLE.Interop.IServiceProvider;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.VSSDK.Tools.VsIdeTesting;
using Microsoft.VisualStudio;
namespace Microsoft.VsSDK.IntegrationTestLibrary
{
/// <summary>
/// </summary>
public class TestUtils
{
#region Methods: Handling embedded resources
/// <summary>
/// Gets the embedded file identified by the resource name, and converts the
/// file into a string.
/// </summary>
/// <param name="resourceName">In VS, is DefaultNamespace.FileName?</param>
/// <returns></returns>
public static string GetEmbeddedStringResource(Assembly assembly, string resourceName)
{
string result = null;
// Use the .NET procedure for loading a file embedded in the assembly
Stream stream = assembly.GetManifestResourceStream(resourceName);
if (stream != null)
{
// Convert bytes to string
byte[] fileContentsAsBytes = new byte[stream.Length];
stream.Read(fileContentsAsBytes, 0, (int)stream.Length);
result = Encoding.Default.GetString(fileContentsAsBytes);
}
else
{
// Embedded resource not found - list available resources
Debug.WriteLine("Unable to find the embedded resource file '" + resourceName + "'.");
Debug.WriteLine(" Available resources:");
foreach (string aResourceName in assembly.GetManifestResourceNames())
{
Debug.WriteLine(" " + aResourceName);
}
}
return result;
}
/// <summary>
///
/// </summary>
/// <param name="embeddedResourceName"></param>
/// <param name="baseFileName"></param>
/// <param name="fileExtension"></param>
/// <returns></returns>
public static void WriteEmbeddedResourceToFile(Assembly assembly, string embeddedResourceName, string fileName)
{
// Get file contents
string fileContents = GetEmbeddedStringResource(assembly, embeddedResourceName);
if (fileContents == null)
throw new ApplicationException("Failed to get embedded resource '" + embeddedResourceName + "' from assembly '" + assembly.FullName);
// Write to file
StreamWriter sw = new StreamWriter(fileName);
sw.Write(fileContents);
sw.Close();
}
/// <summary>
/// Writes an embedded resource to a file.
/// </summary>
/// <param name="assembly">The name of the assembly that the embedded resource is defined.</param>
/// <param name="embeddedResourceName">The name of the embedded resource.</param>
/// <param name="fileName">The file to write the embedded resource's content.</param>
public static void WriteEmbeddedResourceToBinaryFile(Assembly assembly, string embeddedResourceName, string fileName)
{
// Get file contents
Stream stream = assembly.GetManifestResourceStream(embeddedResourceName);
if (stream == null)
throw new InvalidOperationException("Failed to get embedded resource '" + embeddedResourceName + "' from assembly '" + assembly.FullName);
// Write to file
BinaryWriter sw = null;
FileStream fs = null;
try
{
byte[] fileContentsAsBytes = new byte[stream.Length];
stream.Read(fileContentsAsBytes, 0, (int)stream.Length);
FileMode mode = FileMode.CreateNew;
if (File.Exists(fileName))
{
mode = FileMode.Truncate;
}
fs = new FileStream(fileName, mode);
sw = new BinaryWriter(fs);
sw.Write(fileContentsAsBytes);
}
finally
{
if (fs != null)
{
fs.Close();
}
if (sw != null)
{
sw.Close();
}
}
}
#endregion
#region Methods: Handling temporary files and directories
/// <summary>
/// Returns the first available file name on the form
/// [baseFileName]i.[extension]
/// where [i] starts at 1 and increases until there is an available file name
/// in the given directory. Also creates an empty file with that name to mark
/// that file as occupied.
/// </summary>
/// <param name="directory">Directory that the file should live in.</param>
/// <param name="baseFileName"></param>