Visual Studio 2003上で選択されたテキストでGoogle検索するAddin


Officeのリサーチサービスが便利だったので、同じようなものをVisual Studioで実現するためのアドインを作ってみた。
同様の方法で、Search ServerやMOSSの検索サービスとも連携できる。


まずは、新規プロジェクトで「その他のプロジェクト」-> 「機能拡張プロジェクト」-> 「Visual Studio.NETアドイン」を選択。
Wizardに従って設定すると、プロトタイプとセットアッププロジェクトが作成されるのでこれを編集する

Visual Studioオートメーションについてはここを参照
http://msdn2.microsoft.com/ja-jp/library/1xt0ezx9.aspx

namespace Zero
{
	using System;
	using Microsoft.Office.Core;
	using Extensibility;
	using System.Runtime.InteropServices;
	using EnvDTE;
	using System.Windows.Forms;
	using System.Diagnostics;
	using System.Web;

	#region Read me for Add-in installation and setup information.
	// When run, the Add-in wizard prepared the registry for the Add-in.
	// At a later time, if the Add-in becomes unavailable for reasons such as:
	//   1) You moved this project to a computer other than which is was originally created on.
	//   2) You chose 'Yes' when presented with a message asking if you wish to remove the Add-in.
	//   3) Registry corruption.
	// you will need to re-register the Add-in by building the MyAddin21Setup project 
	// by right clicking the project in the Solution Explorer, then choosing install.
	#endregion
	
	/// <summary>
	///   The object for implementing an Add-in.
	/// </summary>
	/// <seealso class='IDTExtensibility2' />
	[GuidAttribute("2F376233-B246-43BF-A08A-7EC7AF013393"), ProgId("Zero.Connect")]
	public class Connect : Object, Extensibility.IDTExtensibility2, IDTCommandTarget
	{
		/// <summary>
		///		Implements the constructor for the Add-in object.
		///		Place your initialization code within this method.
		/// </summary>
		public Connect()
		{
		}

		/// <summary>
		///      Implements the OnConnection method of the IDTExtensibility2 interface.
		///      Receives notification that the Add-in is being loaded.
		/// </summary>
		/// <param term='application'>
		///      Root object of the host application.
		/// </param>
		/// <param term='connectMode'>
		///      Describes how the Add-in is being loaded.
		/// </param>
		/// <param term='addInInst'>
		///      Object representing this Add-in.
		/// </param>
		/// <seealso class='IDTExtensibility2' />
		public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
		{
			applicationObject = (_DTE)application;
			addInInstance = (AddIn)addInInst;
			if(connectMode == Extensibility.ext_ConnectMode.ext_cm_UISetup)
			{
				object []contextGUIDS = new object[] { };
				Commands commands = applicationObject.Commands;
				_CommandBars commandBars = applicationObject.CommandBars;

				// When run, the Add-in wizard prepared the registry for the Add-in.
				// At a later time, the Add-in or its commands may become unavailable for reasons such as:
				//   1) You moved this project to a computer other than which is was originally created on.
				//   2) You chose 'Yes' when presented with a message asking if you wish to remove the Add-in.
				//   3) You add new commands or modify commands already defined.
				// You will need to re-register the Add-in by building the ZeroSetup project,
				// right-clicking the project in the Solution Explorer, and then choosing install.
				// Alternatively, you could execute the ReCreateCommands.reg file the Add-in Wizard generated in
				// the project directory, or run 'devenv /setup' from a command prompt.
				try
				{
					Command command = commands.AddNamedCommand(addInInstance, "GoogleSearch", "GoogleSearch", "GoogleSearch", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.vsCommandStatusEnabled);
					CommandBar commandBar = (CommandBar)commandBars["Tools"];
					CommandBarControl commandBarControl = command.AddControl(commandBar, 1);
				}
				catch(System.Exception /*e*/)
				{
				}
			}
			
		}

		/// <summary>
		///     Implements the OnDisconnection method of the IDTExtensibility2 interface.
		///     Receives notification that the Add-in is being unloaded.
		/// </summary>
		/// <param term='disconnectMode'>
		///      Describes how the Add-in is being unloaded.
		/// </param>
		/// <param term='custom'>
		///      Array of parameters that are host application specific.
		/// </param>
		/// <seealso class='IDTExtensibility2' />
		public void OnDisconnection(Extensibility.ext_DisconnectMode disconnectMode, ref System.Array custom)
		{
		}

		/// <summary>
		///      Implements the OnAddInsUpdate method of the IDTExtensibility2 interface.
		///      Receives notification that the collection of Add-ins has changed.
		/// </summary>
		/// <param term='custom'>
		///      Array of parameters that are host application specific.
		/// </param>
		/// <seealso class='IDTExtensibility2' />
		public void OnAddInsUpdate(ref System.Array custom)
		{
		}

		/// <summary>
		///      Implements the OnStartupComplete method of the IDTExtensibility2 interface.
		///      Receives notification that the host application has completed loading.
		/// </summary>
		/// <param term='custom'>
		///      Array of parameters that are host application specific.
		/// </param>
		/// <seealso class='IDTExtensibility2' />
		public void OnStartupComplete(ref System.Array custom)
		{
		}

		/// <summary>
		///      Implements the OnBeginShutdown method of the IDTExtensibility2 interface.
		///      Receives notification that the host application is being unloaded.
		/// </summary>
		/// <param term='custom'>
		///      Array of parameters that are host application specific.
		/// </param>
		/// <seealso class='IDTExtensibility2' />
		public void OnBeginShutdown(ref System.Array custom)
		{
		}
		
		/// <summary>
		///      Implements the QueryStatus method of the IDTCommandTarget interface.
		///      This is called when the command's availability is updated
		/// </summary>
		/// <param term='commandName'>
		///		The name of the command to determine state for.
		/// </param>
		/// <param term='neededText'>
		///		Text that is needed for the command.
		/// </param>
		/// <param term='status'>
		///		The state of the command in the user interface.
		/// </param>
		/// <param term='commandText'>
		///		Text requested by the neededText parameter.
		/// </param>
		/// <seealso class='Exec' />
		public void QueryStatus(string commandName, EnvDTE.vsCommandStatusTextWanted neededText, ref EnvDTE.vsCommandStatus status, ref object commandText)
		{
			if(neededText == EnvDTE.vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
			{
				if(commandName == "Zero.Connect.GoogleSearch")
				{
					status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported|vsCommandStatus.vsCommandStatusEnabled;
				}
			}
		}

		/// <summary>
		///      Implements the Exec method of the IDTCommandTarget interface.
		///      This is called when the command is invoked.
		/// </summary>
		/// <param term='commandName'>
		///		The name of the command to execute.
		/// </param>
		/// <param term='executeOption'>
		///		Describes how the command should be run.
		/// </param>
		/// <param term='varIn'>
		///		Parameters passed from the caller to the command handler.
		/// </param>
		/// <param term='varOut'>
		///		Parameters passed from the command handler to the caller.
		/// </param>
		/// <param term='handled'>
		///		Informs the caller if the command was handled or not.
		/// </param>
		/// <seealso class='Exec' />
		public void Exec(string commandName, EnvDTE.vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
		{
#if DEBUG
			MessageBox.Show("Exec Start");
#endif
			handled = false;
			if(executeOption == EnvDTE.vsCommandExecOption.vsCommandExecOptionDoDefault)
			{
#if DEBUG
				MessageBox.Show("Execute Option Match");
				MessageBox.Show("CommandName is " + commandName);//CommandNameはnamespace.classname.<AddNamedCommandで指定した名称>
#endif
				if(commandName == "Zero.Connect.GoogleSearch")
				{
#if DEBUG
					MessageBox.Show("Command Name Match");
#endif
					string selected = GetSelectedString();
					if(selected != null && selected != string.Empty)
					{
						selected = HttpUtility.UrlEncode(selected);
					
						ProcessStartInfo pi = new ProcessStartInfo(@"C:\Program Files\Internet Explorer\iexplore.exe","http://www.google.co.jp/search?sourceid=navclient&hl=ja&ie=UTF-8&rlz=1T4GFRC_jaJP205JP205&q=" + selected);
						pi.UseShellExecute = false;

						System.Diagnostics.Process p = new System.Diagnostics.Process();
						p.StartInfo = pi;
						p.Start();
					}

					handled = true;
					return;
				}
			}
#if DEBUG
			MessageBox.Show("Exec End");
#endif
		}
		private _DTE applicationObject;
		private AddIn addInInstance;

		private string GetSelectedString()
		{
			string selectedString = null;

			if(applicationObject.ActiveDocument.Selection != null)
			{
				TextDocument textDocument = applicationObject.ActiveDocument.Object("TextDocument") as TextDocument;
				if(textDocument != null)
				{
					TextSelection selection = textDocument.Selection;
					if(selection != null)
					{
						selectedString = selection.Text;
					}
				}
			}

			return selectedString;

		}
		
	}
}