<a href=" http://msdn.microsoft.com/vstudio/vsip/default.asp">Visual Studio .NET Integration Program</a>
The main diff with an add-in: here all the command names are in fact function names in a macro module. I think there is a way to expose the add-in functions as commands without writing stub macros, but I am not sure. Seems stupid if MS allowed macros to generate commands, but not add-ins. I don't have experience with add-ins, but I think in the yahoo group they spoke of toolbars, so there must be a way.
Sub aaAddToolbarAndButtons()
Dim commandBar As CommandBar
Dim cmds As Commands
cmds = DTE.Commands
' Create a toolbar if it does not exist
' Unfortunately, catch does not work, nor the is condition, so there is no way to tell
'Try
' commandBar = DTE.CommandBars("Editing Macros")
'Catch e As System.Exception
'End Try
'If Not commandBar Is GetType(CommandBar) Then
commandBar = cmds.AddCommandBar("Editing Macros", vsCommandBarType.vsCommandBarTypeToolbar)
'End If
Dim menu As CommandBar
menu = cmds.AddCommandBar("etc", vsCommandBarType.vsCommandBarTypeMenu, commandBar)
AddToolbarButton(menu, "TypeDouble", "double")
AddToolbarButton(menu, "TypeFloat", "float")
AddToolbarButton(menu, "TypeInt", "int")
AddToolbarButton(menu, "TypeBool", "bool")
AddToolbarButton(menu, "TypeString", "string")
AddToolbarButton(menu, "TypeObject", "object")
AddToolbarButton(menu, "TypeVoid", "void")
AddToolbarButton(menu, "LiteralThis", "this")
AddToolbarButton(menu, "LiteralString", """""")
AddToolbarButton(menu, "LiteralNull", "null")
' a lot more menus added here ...
End Sub
Private Sub AddToolbarButton(ByVal commandBar As CommandBar, ByVal macroName As String, ByVal caption As String)
Dim cmds As Commands
Dim ctl As CommandBarControl
cmds = DTE.Commands
ctl = cmds.Item("Macros.Frank.Editing." & macroName).AddControl(commandBar)
ctl.Caption = caption
ctl.TooltipText = macroName
End Sub
Sub aaRemoveToolbar()
Dim cmds As Commands
Dim cmdbar As CommandBar
cmds = DTE.Commands
cmdbar = DTE.CommandBars("Editing Macros")
cmds.RemoveCommandBar(cmdbar)
End Sub
the other part of this project though involves navigating around in VS.NET and putting code where the cursor is, etc...i'm guessing i won't be able to do that without VSIP though :(
internal class CodeInjector
{
public static void InsertCode(DTE dte, IDesignerHost host, string code)
{
Document ourDoc = FindOurDocument(dte, host);
//OpenCodeDoc(dte, ourDoc);// may not be necessary
// find our class
string className = host.RootComponentClassName;
FileCodeModel cm = ourDoc.ProjectItem.FileCodeModel;
CodeClass cc = null;
foreach (CodeElement ce in cm.CodeElements)
{
cc = FindClass(ce, className);
if (cc != null)
break;
}
if (cc != null)
{
// first create codedom
CodeCommentStatement comment = new CodeCommentStatement(code);
// cannot generate code from a method -- have to use a type, or
// hope the method is already there
//CodeMemberMethod method = new CodeMemberMethod();
//method.Name = "test";
//method.Comments.Add(comment);
// generate a string from the codedom
CodeDomProvider provider;
if (ourDoc.Language == "CSharp")
provider = new Microsoft.CSharp.CSharpCodeProvider();
// TODO: need to test this -- don't know which string to use
else if (ourDoc.Language == "VB")
provider = new Microsoft.VisualBasic.VBCodeProvider();
else
return;
ICodeGenerator generator = provider.CreateGenerator();
StringBuilder sb = new StringBuilder();
TextWriter writer = new IndentedTextWriter(new StringWriter(sb));
generator.GenerateCodeFromStatement(comment, writer, null);
writer.Flush();
// if the method already exists, delete body
EditPoint start = null;
foreach (CodeElement ce in cc.Members)
{
CodeFunction cf = ce as CodeFunction;
if (cf != null && cf.Name == "test")
{
start = cf.StartPoint.CreateEditPoint();
start.LineDown(2);
start.StartOfLine();
EditPoint end = cf.EndPoint.CreateEditPoint();
end.LineUp(1);
end.EndOfLine();
start.Delete(end);
break;
}
}
if (start == null)
{
if (ourDoc.Language == "CSharp")
{
CodeFunction cf = cc.AddFunction("test", vsCMFunction.vsCMFunctionFunction,
vsCMTypeRef.vsCMTypeRefInt, -1, vsCMAccess.vsCMAccessPrivate, null);
start = cf.StartPoint.CreateEditPoint();
start.LineDown(2);
start.StartOfLine();
}
else
{
// TODO: here error message
}
}
// insert the string into the function
start.Insert(sb.ToString());
}
}
private static CodeClass FindClass(CodeElement root, string className)
{
CodeClass cc = root as CodeClass;
if (cc != null)
{
if (cc.FullName == className)
return cc;
foreach (CodeElement ce in cc.Members)
{
if (ce is EnvDTE.CodeNamespace || ce is CodeClass)
{
cc = FindClass(ce, className);
if (cc != null)
return cc;
}
}
}
else
{
EnvDTE.CodeNamespace cn = root as EnvDTE.CodeNamespace;
if (cn != null)
{
foreach (CodeElement ce in cn.Members)
{
if (ce is EnvDTE.CodeNamespace || ce is CodeClass)
{
cc = FindClass(ce, className);
if (cc != null)
return cc;
}
}
}
}
return null;
}
private static Document FindOurDocument(DTE dte, IDesignerHost host)
{
foreach (Document doc in dte.Documents)
{
if (doc.Kind != Constants.vsDocumentKindText)
continue;
foreach (Window window in doc.Windows)
{
// right now, hook to all -- later only certain ones?
IDesignerHost windowHost = window.Object as IDesignerHost;
if (windowHost != null && windowHost == host)
return doc;
}
}
return null;
}
private static void OpenCodeDoc(DTE dte, Document document)
{
bool codeOpen = dte.get_IsOpenFile(Constants.vsViewKindCode, document.FullName);
if (!codeOpen)
{
ItemOperations ItemOp = dte.ItemOperations;
ItemOp.OpenFile(document.FullName, Constants.vsViewKindCode);
}
}
}