VS.NET Toolbar

I've created a VS.NET Add-in, pretty easy, but is there an easy way to create a VS.NET Toolbar? Is it even possible? Thanx
[123 byte] By [codefund.com] at [2008-2-6]
# 1
It is possible but it requires that you purchase the VSIP SDK. This is an SDK that allows you to plug in very deeply into Visual Studio.NET. However, it doesn't come cheap (or simple!). It's typically sold to language vendors who want to write their own project systems, debuggers, etc.
codefund.com at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Designer...
# 2
Can it be sold to entrepreneurs? ;) Got any info on it?
codefund.com at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Designer...
# 3
Nevermind, found it...

<a href=" http://msdn.microsoft.com/vstudio/vsip/default.asp">Visual Studio .NET Integration Program</a>

codefund.com at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Designer...
# 4
You dont need VSIP. Here is some code I used in a macro to create toolbars. I think you can do the same in an add-in. It should not be hard to convert to C#, if you need to (macros only support VB). There is a yahoo group for VS.net add-ins. I think the bug with removing the old toolbar would not exist in an add-in.

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

codefund.com at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Designer...
# 5
cool, thanx a lot, i'll give it a go. It's fine that it's in VB, that's what i usually use anyway ;)

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 :(

codefund.com at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Designer...
# 6
It is possible to navigate through the code and insert text using the EnvDTE namespace. First you have to find the designer host for the doc. Here is a class I created for injecting a member -- it is only a test, I never used it. You have to paste into a .cs file to get the formatting back.

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);
}
}
}

codefund.com at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Designer...
# 7
awesome! thanx so much! I'm actually on my way out of town, but when I get back, I will definitely be giving that a try...thanx again :)
codefund.com at 2007-9-8 > top of Msdn Tech,Windows Forms,Windows Forms Designer...