Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / Visual Studio.NET / Extensibility / May 2006

Tip: Looking for answers? Try searching our database.

Enterprise Templates Properties and commandbars problem

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Shai - 25 Apr 2006 12:55 GMT
We are experiencing two issues using C# to extend Visual Studio 2003.

The solution being extended contains multiple Enterprise Templates (ETP)
that each contain one or more projects of various types.

The first problem is that we need to extend the properties displayed in the
property browser when an ETP is selected in the Solution Explorer. We found
the CatID “{3B6A4DE6-2332-42b7-B6F6-0AF06993FFA2}” to extend the ETP when
referencing it in our code. However, we have been unable to find the CatID we
need to use when it is selected in the Solution Explorer.

The second extension issue we are having (and much more critical )  is in
adding a menu option to the context menu activated when an ETP is right
clicked in the Solution Explorer. For this we need to know the name of the
command bars to extend, so we can create an instance of it:

CommandBar oCommandBar = applicationObject.CommandBars["Project"];

We’ve tried extending the following command bars: “Project”, “Item”,
“Folder”, “Project Node”, “Root”, “Solution Items Project”, but the
Enterprise Template does not fall into any of these categories. We actually
wrote small util that display all possible applicationObject.CommandBars and
there sub commandbars but couldn't find anything that match the ET node.

TIA
Shai
Carlos J. Quintero [VB MVP] - 25 Apr 2006 15:07 GMT
Hi Shai,

About the second issue, see if this article of mine helps:

HOWTO: Guessing the name of a command bar to add a custom menu entry in
Visual Studio .NET add-ins
http://www.mztools.com/articles/2004/MZ002.htm

Signature

Best regards,

Carlos J. Quintero

MZ-Tools: Productivity add-ins for Visual Studio
You can code, design and document much faster:
http://www.mztools.com

> We are experiencing two issues using C# to extend Visual Studio 2003.
>
[quoted text clipped - 27 lines]
> TIA
> Shai
Shai - 25 Apr 2006 16:35 GMT
Hi Carlos !
Thanks for the replay. Actually the little util we wrote was based on your
article, only on c# but it didn't help. We got list of more then 2500
commandbar, but none of them where what we are looking for.
Here is the snip of code.
foreach (CommandBar cmdbar in applicationObject.CommandBars)
{
outputWindowPane.OutputString("----------------------------------------"+"\n");
outputWindowPane.OutputString("Candidate CommandBar Name: "+ cmdbar.Name
+"\n" );
outputWindowPane.OutputString("Captions on this command bar:"+"\n");
    foreach ( CommandBarControl objCommandBarControl1 in cmdbar.Controls)
    {
    outputWindowPane.OutputString("  " + objCommandBarControl1.Caption +"\n" );
    }
}

I hope someone from the VS.net team will take a look at this issue.

TIA
Shai

> Hi Shai,
>
[quoted text clipped - 35 lines]
> > TIA
> > Shai
"Gary Chang[MSFT]" - 26 Apr 2006 10:34 GMT
Hi Shai,

This is a quick note to let you know that I am performing research on this
issue and will get back to you as soon as possible. I appreciate your
patience.

Thanks for your understanding.

Best regards,

Gary Chang
Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
"Ed Dore [MSFT]" - 28 Apr 2006 01:00 GMT
Hi Shai,

I've only had limited exposure to those old Enterprise Template projects.
This took a bit of time to track down, but I think I've found a way to
retrieve the particular CommandBar you're looking for.

The guid:id pair for the context menu you are interested in is:

  {FE3BBBB7-72D5-11D2-9ACE-00C04F79A2A4}:1

From a VSIP package this would be pretty easy to manipulate. But  from an
addin, the problem is that the DTE automation model doesn't really allow
for retrieving the CommandBar with just this info. And the CommandBar name
is "Root", which isn't exactly unique. We could try to test a few of the
commands in the CommandBar's Controls collection to see if we retreive the
right CommandBar, but that seems rather ugly.

So you'll need to use IServiceProvider::QueryService on the DTE object to
retrieve the IVsProfferCommands service. Once you have this interface, you
can invoke it's FindCommandBar method to retrieve the context menu used by
Solution Explorer for ETP nodes.

The IServiceProvider is the COM version and not the .Net version, so you'll
need to either use the interop DLL's provided with the VSIP Extra's SDK. Or
define the interface yourself. I chose the latter, because using the
interop assemblies that ship with the VSIP Extras SDK, means deploying the
interop assemblies. With VS 2005 this isn't an issue as the interop
assemblies in question actually ship with VS 2005.

Anyway, below is a quick and dirty example of how you can use
IVsProfferCommands::FindCommandBar to retrieve and add a new menu item to
the ETP project node's context menu.

  // defines COM version of IServiceProvider, which is different from
  // the .NET version.
  [ ComImport, Guid("6D5140C1-7436-11CE-8034-00AA006009FA"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)    ]
  public interface IOleServiceProvider
  {
     [PreserveSig]
     int QueryService([In]ref Guid guidService, [In]ref Guid riid, out
IntPtr ppvObject);
  }

  [GuidAttribute("76B3EBA5-07E4-4772-BD88-A8D6AC5BCBC4"),
ProgId("ETPMenu.Connect")]
  public class Connect : Object, Extensibility.IDTExtensibility2
  {
     public Connect()
     {
     }

     public void OnConnection(object application,
Extensibility.ext_ConnectMode connectMode, object addInInst, ref
System.Array custom)
     {
        applicationObject = (_DTE)application;
        addInInstance = (AddIn)addInInst;
        CommandBarButton btnTest;

        // retrieve IServiceProvider from DTE object
        IOleServiceProvider sp = (IOleServiceProvider)applicationObject;
        Guid guidSvc = new
Guid(typeof(IVsProfferCommands).GUID.ToString());
        IntPtr service;
        sp.QueryService(ref guidSvc, ref guidSvc, out service);
        IVsProfferCommands vsProfferCmds =
(IVsProfferCommands)Marshal.GetObjectForIUnknown(service);
        Marshal.Release(service);
           
        Guid guidCmdGroup = new
Guid("{FE3BBBB7-72D5-11D2-9ACE-00C04F79A2A4}");
        uint menuId = 1;
        CommandBar cmdBar =
(CommandBar)vsProfferCmds.FindCommandBar(IntPtr.Zero, ref guidCmdGroup,
menuId);
           
        try
        {
           Object objMissing = System.Reflection.Missing.Value;
           btnTest =
(CommandBarButton)cmdBar.Controls.Add(MsoControlType.msoControlButton,
objMissing, objMissing, objMissing, objMissing);
           btnTest.Caption = "ETP Test";
           btnTest.Click +=new
_CommandBarButtonEvents_ClickEventHandler(btnTest_Click);
        }
        catch(Exception e)
        {
           Debug.WriteLine(e.Message);
        }
}

One caveat is that I noticed the FindCommandBar call does fail if an ETP
project hasn't been loaded first. But if you're attempting to do this from
a project or solution extender, then I suspect this probably won't be an
issue.

Concerning the CatID problem, are you creating a solution or project
extender to add the additional properties to the ETP projects? Can you
provide some additional details as to what exactly you're trying to do
there. I'm didn't quite follow what you're trying to do with regards to
your CATID question.

Sincerely,
Ed Dore [MSFT]

This post is 'AS IS' with no warranties, and confers no rights.
Carlos J. Quintero [VB MVP] - 28 Apr 2006 13:01 GMT
Hi Ed,

I am interested about some ideas of your post (inline):

> The IServiceProvider is the COM version and not the .Net version,

Which is the difference between the .NET version and the COM version?
When do you use each one?
Also, you talk about IServiceProvider but the code uses IOleServiceProvider,
are they the same?

> so you'll  need to either use the interop DLL's provided with the VSIP
> Extra's SDK. Or
> define the interface yourself. I chose the latter, because using the
> interop assemblies that ship with the VSIP Extras SDK, means deploying the
> interop assemblies.

This is very interesting news. I am using an add-in (not a package) and I
have tried to define the IOleServiceProvider in my VB.NET code following
your sample, and I get an invalid cast exception when casting
applicationObject to IOleServiceProvider, which makes sense since the type
IOleServiceProvider defined in my assembly is not the same than the type
IOleServiceProvider defined in the interop assemblies (since the assemblies
are not the same). So, can you really avoid using the interop assemblies to
retrieve IOleServiceProvider? Does your code execute without that exception?

> With VS 2005 this isn't an issue as the interop assemblies in question
> actually ship with VS 2005.

This is good news...

Thanks in advance for any info,

Carlos
"Ed Dore [MSFT]" - 28 Apr 2006 21:28 GMT
Hi Carlos,

I tested the code in a simple C# addin before posting, so I'm pretty sure
it works.

The IServiceProvider defined in the .Net runtime, is not the same as the
original IServiceProvider interface defined by COM.

Win32 defines IServiceProvider (in the Platform SDK's ServProv.idl file)
with the guid 6d5140c1-7436-11ce-8034-00aa006009fa, whereas .Net defines
IServiceProvider in it's framework with the guid
8f10f540-7f5d-3f37-8d79-1e0aeb074aa0.

So there are really two different interfaces here. Most VSIP samples (and
even the package wizard generated code) will redefine the Win32 version of
IServiceProvider to IOleServiceProvider so that it's more readily
identifiable as the Win32 COM interface, and not the .NET interface. The
IServiceProvider in the code snippet in my previous post uses the Win32 COM
IServiceProvider interface (but I named the interface IOleServiceProvider
in keeping with the VSIP SDK precedent.

In the VSIP SDK, the IServiceProvider is defined in
Microsoft.VisualStudio.OLE.Interop.dll. Because this wasn't around when we
first shipped Visual Studio 2003, we provide an installer for it "VSIP
Interop Assembly Redist.msi" with the VSIP Extras. So if you use the
interop assembly, you wouldn't need to define the interface yourself. But
you would need to deploy it by way of the .msi, which is a bit of a hassle
for just one simply interface definition :-)

For VB.Net the following should work: Though it's probably not the best
written VB code, it works without throwing an exception. You might want to
compare your interface definition with the one below. In particular the
attributes it uses.

<ComVisible(True), ComImport(),
Guid("6D5140C1-7436-11CE-8034-00AA006009FA"), _
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)> _
Interface IOleServiceProvider
   Function QueryService(<InAttribute()> ByRef guidService As Guid, _
   <InAttribute()> ByRef riid As Guid, <Out()> ByRef ppvObject As IntPtr)
As Integer
End Interface

<GuidAttribute("2148639E-1683-4CE7-800D-ED8D73B8B650"),
ProgIdAttribute("Carlos.Connect")> _
Public Class Connect

   Implements Extensibility.IDTExtensibility2

   Dim applicationObject As EnvDTE.DTE
   Dim addInInstance As EnvDTE.AddIn

  <.....>

   Public Sub OnConnection(ByVal application As Object, ByVal connectMode
As Extensibility.ext_ConnectMode, _
     ByVal addInInst As Object, ByRef custom As System.Array) Implements
Extensibility.IDTExtensibility2.OnConnection

       applicationObject = CType(application, EnvDTE.DTE)
       addInInstance = CType(addInInst, EnvDTE.AddIn)

       Dim sp As IOleServiceProvider = CType(applicationObject,
IOleServiceProvider)
       Dim guidSvc As Guid = New
Guid(GetType(IVsProfferCommands).GUID.ToString())
       Dim pUnk As IntPtr
       sp.QueryService(guidSvc, guidSvc, pUnk)
       Dim obj As Object = Marshal.GetObjectForIUnknown(pUnk)
       Marshal.Release(pUnk)
       Dim vsProfferCmds As IVsProfferCommands = CType(obj,
IVsProfferCommands)
       Dim menuId As UInt32 = Convert.ToUInt32(1)

       Dim guidCmdGroup = New
Guid("{FE3BBBB7-72D5-11D2-9ACE-00C04F79A2A4}")
       obj = vsProfferCmds.FindCommandBar(IntPtr.Zero, guidCmdGroup,
menuId)

       Dim cmdBar As CommandBar = CType(obj, CommandBar)
       Debug.WriteLine(cmdBar.Name)

   End Sub

  <....>

End Class

Sincerely,
Ed Dore [MSFT]

This post is 'AS IS' with no warranties, and confers no rights
Carlos J. Quintero [VB MVP] - 03 May 2006 16:16 GMT
Thanks Ed, it was a problem in my code.

Carlos

> Hi Carlos,
>
[quoted text clipped - 89 lines]
>
> This post is 'AS IS' with no warranties, and confers no rights
Shai - 29 Apr 2006 19:24 GMT
Hi Ed!
Thank you very much for this solution. It working and we can get the menu
for the ETP node.

The other problem we have is to be able to extend this node properties as we
did on Solution level or regular project level. Here is more detailed
description.

We think we found the CatID we needed, but there is still a problem casting
the ExtendeeObject that is being passed into the extender.

The CatID for an ETP when it is selected in the solution explorer is
“{E72203D8-B699-4723-8867-03E20F835499}”. To extend the properties of the ETP
we added a key in the registry to

“HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.1\Extenders\{E72203D8-B699-4723-8867-03E20F835499}”

Corresponding to our extender, namely “SolutionMisc”. In that key we set the
default value to “{D629F716-77FE-49cd-8F9A-564111B80AFF}”, the GUID for our
extender.

Our extender first check to make sure the object to be extended is what is
expected via the following function:

public bool CanExtend(string ExtenderCATID, string ExtenderName, object
ExtendeeObject)
{
//return true if it can extend the ExtendeeObject as an ETP
if (ExtenderCATID.ToUpper() == “{E72203D8-B699-4723-8867-03E20F835499”)
{
return true;
}
else
{
return false;
}
}

That is now returning true for Enterprise Templates. The next step is to
cast the ExtendeeObject passed as an object in to the method

public object GetExtender(string ExtenderCATID, string ExtenderName, object
ExtendeeObject, EnvDTE.IExtenderSite ExtenderSite, int Cookie)

To find out the type of the ExtendeeObject we used the following line

MessageBox.Show(Information.TypeName(ExtendeeObject));

This showed the type as being “IDispEFNode”.

The current problem is that IDispEFNode does not appear in any documentation
other than on one website
http://custom.programming-in.net/articles/art14-2.asp?Interop=EFLib”, where
it is simply listed as a member of EFLib classes.

Where can we find this type, or is there another comparable type that will
work?

TIA
Shai

> Hi Shai,
>
[quoted text clipped - 104 lines]
>
> This post is 'AS IS' with no warranties, and confers no rights.
Yan-Hong Huang[MSFT] - 02 May 2006 08:15 GMT
Hello Shai,

In order to better share the knowledge in the community and make others
search issues more efficiently, could you please post the question in a new
thread in the newsgroup? We will follow up on your new post.

Thanks very much for your understanding.

Sincerely,
Yanhong Huang
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.
Shai - 02 May 2006 08:36 GMT
Hi Yanhong Huang !

I opened anther post subject : "Problem with project extender properties for
ETP projects" ,
http://msdn.microsoft.com/newsgroups/default.aspx?&guid=&sloc=en-us&dg=microsoft
.public.vstudio.extensibility&p=1&tid=0008b5d1-2bcb-434a-a216-fafe85a3198e&mid=0
008b5d1-2bcb-434a-a216-fafe85a3198e


Please follow up  this post.

TIA
Shai

> Hello Shai,
>
[quoted text clipped - 14 lines]
>
> This posting is provided "AS IS" with no warranties, and confers no rights.
"Gary Chang[MSFT]" - 03 May 2006 03:49 GMT
That's no problem, we will follow it there.:)

Thanks!

Best regards,

Gary Chang
Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
Yan-Hong Huang[MSFT] - 03 May 2006 06:42 GMT
Thank you, Shai.

Sincerely,
Yanhong Huang
Microsoft Online Community Support

==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================

This posting is provided "AS IS" with no warranties, and confers no rights.

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.