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 / February 2005

Tip: Looking for answers? Try searching our database.

connectionMode == ext_cm_Startup on OnConnection

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Bruce E. Stemplewski - 05 Feb 2005 23:39 GMT
I am writing my very first addin.  What causes connectMode to be set?
When OnConnection is being called it is being called with connectMode ==
ext_cm_Startup therefore the menu does not get created.  How can I
change this?

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)

Signature

Bruce E. Stemplewski
GarXface OCX and C++ Class Library for the Garmin GPS
www.stempsoft.com

Anna-Jayne Metcalfe - 06 Feb 2005 11:09 GMT
Hi Bruce,

>I am writing my very first addin.  What causes connectMode to be set? When
>OnConnection is being called it is being called with connectMode ==
>ext_cm_Startup therefore the menu does not get created.  How can I change
>this?

To cause OnConnection to be called with ext_cm_UISetup set, you need to add
the following key to the registry:

HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\x.y\PreloadAddinState\<YourAddInName>
= 1

where x.y is the version of Visual Studio (7.0 for .NET 2002, 7.1 for .NET
2003 and 8.0 for .NET 2005). If you're targetting multiple versions you'll
need to add the key for each of them (as you will for the other keys VS
needs to know about your add-in).

Having never written an add-in in C# or VB.NET I'm unsure what options
you'll have for placing this key - it can be set by the installer, or (in
the case of C++/COM add-ins) by the add-in itself when it self registers.
I've personally found the second approach to be more reliable.

If you're new to add-in development you may want to buy a book or two to
help you long. My personal favourite is Inside Microsoft Visual Studio .NET
2003 (http://www.microsoft.com/MSPress/books/6425.asp).

Good luck! Add-in development is difficult, challenging and ultimately very
rewarding. :)

Kind Regards,

   Anna-Jayne Metcalfe

   Software/Product Development Consultant,
   Riverblade Limited.
   http://www.riverblade.co.uk
Bruce E. Stemplewski - 06 Feb 2005 14:25 GMT
> Hi Bruce,
>
[quoted text clipped - 33 lines]
>     Riverblade Limited.
>     http://www.riverblade.co.uk 

Thanks for the tips Anna!

Signature

Bruce E. Stemplewski
GarXface OCX and C++ Class Library for the Garmin GPS
www.stempsoft.com

Bruce E. Stemplewski - 06 Feb 2005 14:43 GMT
> Hi Bruce,
>
[quoted text clipped - 28 lines]
>     Riverblade Limited.
>     http://www.riverblade.co.uk 

Is that the best way to add the menu item?  Is there a way for me to
detect if it is already there or not?

Signature

Bruce E. Stemplewski
GarXface OCX and C++ Class Library for the Garmin GPS
www.stempsoft.com

Anna-Jayne Metcalfe - 06 Feb 2005 19:16 GMT
Hi Bruce,

> Is that the best way to add the menu item?  Is there a way for me to
> detect if it is already there or not?

There is. Personally I tend to delete all the add-in commands before
attempting to add them, as that way the add-in will cope with upgrades (in
the course of which the available commands may have changed) better.

In our current project we create a class to handle each add-in command. The
base class for these provides the framework, which includes the capability
to remove the corresponding command:

Here's the relevant method. Note that bsCommandName is the full name of the
command, e.g. "MyAddIn.Command1":

HRESULT CVsCommandHandler::RemoveCommand(CComPtr<EnvDTE::_DTE> pDTE, _bstr_t
bsCommandName)
{
   try
   {
       EnvDTE::CommandsPtr ptrCommands = pDTE->GetCommands();

       EnvDTE::CommandPtr ptrCommand = ptrCommands->Item( CComVariant(
CComBSTR(bsCommandName.GetBSTR() ) ), 0);
       IfNullIssueError(ptrCommand);

       ptrCommand->Delete();
   }
   catch (_com_error& e)
   {
        return e.Error();
   }
   return S_OK;
}

I hope that helps! Good luck.

BTW I couldn't help noticing your sig! In my last job (a member of the
software team responsible for developing Sonardyne's Fusion acoustic
navigation suite) GPS devices were among those we interfaced with...

Kind Regards,

   Anna-Jayne Metcalfe

   Software/Product Development Consultant,
   Riverblade Limited.
   http://www.riverblade.co.uk
Bruce E. Stemplewski - 07 Feb 2005 04:00 GMT
> Hi Bruce,
>
[quoted text clipped - 42 lines]
>     Riverblade Limited.
>     http://www.riverblade.co.uk

Thanks again Anna,

Sounds like a really interesting former job.  I love writing programs
that interface to hardware.

I was going to write this plugin in C# but I guess I shouldn't try to
learn plugins along with C#!

What is the base class of CVsCommandHandler?

What calls CVsCommandHandler::RemoveCommand?  Do I do it directly or
does the framework call it?  If I call it directly what do I supply for
CComPtr<EnvDTE::_DTE> pDTE?

Is all of this in the book you recommended?   Does it cover ATL?

Signature

Bruce E. Stemplewski
GarXface OCX and C++ Class Library for the Garmin GPS
www.stempsoft.com

Anna-Jayne Metcalfe - 07 Feb 2005 11:13 GMT
Hi Bruce,

> Thanks again Anna,
>
> Sounds like a really interesting former job.  I love writing programs that
> interface to hardware.

It was...I was there for 6 years, which says something! In the end my
circumstances changed unexpectedly, an opportunity presented itself, and the
rest is now rapidly becoming history. Before that I was working for Racal
Instruments developing C++ Virtual Instrument and Virtual Super Instrument
software (my concept, BTW) for VXIbus avionic test systems.

The hardware bias shouldn't be too surprising as my first foray into
industry was as an RF design engineer and I've spent most of my working
career working with instrumentation of one form or another. <grin>

> I was going to write this plugin in C# but I guess I shouldn't try to
> learn plugins along with C#!

Actually I think there's no reason not to. Although you'll be learning a new
language, the majority of add-in examples and tutorials are in either C# or
VB.NET. Writing in C++ (especially unmanaged) brings additional complexity,
but also flexibility and power.

Besides, if you know C++ already I think you'll find C# a pleasant surprise.
:)

We've chosen to stick with unmanaged code to make support of multiple
versions easier too (that's a story in its own right!). At the moment we're
also seriously considering back porting our latest add-in (Visual Lint) to
VC6 as a result of the download profile we're seeing on our ResOrg add-in -
which of course makes managed code even harder to use.

> What is the base class of CVsCommandHandler?

It's one of our own:

/////////////////////////////////////////////////////////////////////////////
// VsCommandHandler.h

#pragma once

/// CVsCommandHandler is a base class for handling adding commands in the
/// Visual Studio environment.
///
/// To add additional commands derive your own classes from this one
/// and override the QueryStatus() and Execute() methods to implement
/// the command actions required.
///
/// The add-in's CConnect class is responsible for maintaining a map
/// (command name => CVsCommandHandler pointer) of command handler objects
/// and routing QueryStatus() and Execute() calls to the correct one.
///
class CVsCommandHandler
{
// Construction/destruction
public:
   CVsCommandHandler( CComPtr<EnvDTE::_DTE> pDTE,
        _bstr_t bsCommandName);

 virtual ~CVsCommandHandler(void);

// Data members
protected:
   CComPtr<EnvDTE::_DTE> m_pDTE;
   _bstr_t     m_bsCommandName;

// Operations
public:
   _bstr_t     GetCommandName(void) const
          { return m_bsCommandName; }

   HRESULT     RemoveCommand(void);

 static HRESULT     RemoveCommand(CComPtr<EnvDTE::_DTE> pDTE, _bstr_t
bsCommandName);

// Virtual overrides
public:
 virtual HRESULT     QueryStatus(BSTR bstrCmdName,
            EnvDTE::vsCommandStatusTextWanted NeededText,
            EnvDTE::vsCommandStatus* pStatusOption,
            VARIANT* pvarCommandText);

 virtual HRESULT     Exec(  BSTR bstrCmdName,
            EnvDTE::vsCommandExecOption ExecuteOption,
            VARIANT* pvarVariantIn,
            VARIANT* pvarVariantOut,
            VARIANT_BOOL* pvbHandled);

};

typedef std::map<_bstr_t, CVsCommandHandler*> CVsCommandHandlerMap;
typedef std::pair<_bstr_t, CVsCommandHandler*> CVsCommandHandlerMapPair;
typedef std::vector<CVsCommandHandler*>   CVsCommandHandlerVector;

/////////////////////////////////////////////////////////////////////////////
// VsCommandHandler.cpp

#include "StdAfx.h"

#include "VsCommandHandler.h"

/////////////////////////////////////////////////////////////////////////////
// CVsCommandHandler construction/destruction

CVsCommandHandler::CVsCommandHandler(CComPtr<EnvDTE::_DTE> pDTE,
         _bstr_t bsCommandName)
{
m_pWindowManager = NULL;

m_pDTE    = pDTE;
ATLASSERT(m_pDTE != NULL);

m_bsCommandName = bsCommandName;
ATLASSERT(m_bsCommandName.length() > 0);
}

CVsCommandHandler::~CVsCommandHandler(void)
{
m_pDTE     = NULL;
}

/////////////////////////////////////////////////////////////////////////////
// CVsCommandHandler operations

HRESULT CVsCommandHandler::RemoveCommand(void)
{
return RemoveCommand(m_pDTE, m_bsCommandName);
}

HRESULT CVsCommandHandler::RemoveCommand(CComPtr<EnvDTE::_DTE> pDTE, _bstr_t
bsCommandName)
{
try
{
 EnvDTE::CommandsPtr ptrCommands = pDTE->GetCommands();

 EnvDTE::CommandPtr ptrCommand = ptrCommands->Item( CComVariant(
CComBSTR(bsCommandName.GetBSTR() ) ), 0);
 IfNullIssueError(ptrCommand);

 ptrCommand->Delete();
}
catch (_com_error& e)
{
 return e.Error();
}
return S_OK;
}

/////////////////////////////////////////////////////////////////////////////
// CVsCommandHandler virtual overrides

HRESULT CVsCommandHandler::QueryStatus( BSTR bstrCmdName,
         EnvDTE::vsCommandStatusTextWanted NeededText,
         EnvDTE::vsCommandStatus* pStatusOption,
         VARIANT* pvarCommandText)
{
UNREFERENCED_PARAMETER(bstrCmdName);
UNREFERENCED_PARAMETER(NeededText);
UNREFERENCED_PARAMETER(pStatusOption);
UNREFERENCED_PARAMETER(pvarCommandText);

return E_NOTIMPL;
}

HRESULT CVsCommandHandler::Exec(BSTR bstrCmdName,
       EnvDTE::vsCommandExecOption ExecuteOption,
       VARIANT* pvarVariantIn,
       VARIANT* pvarVariantOut,
       VARIANT_BOOL* pvbHandled)
{
UNREFERENCED_PARAMETER(bstrCmdName);
UNREFERENCED_PARAMETER(ExecuteOption);
UNREFERENCED_PARAMETER(pvarVariantIn);
UNREFERENCED_PARAMETER(pvarVariantOut);
UNREFERENCED_PARAMETER(pvbHandled);

return E_NOTIMPL;
}

> What calls CVsCommandHandler::RemoveCommand?  Do I do it directly or does
> the framework call it?  If I call it directly what do I supply for
> CComPtr<EnvDTE::_DTE> pDTE?

There are actually two overloads of RemoveCommand() - one of which is a
static, so it needs the DTE pointer to be specified. The other one is a
class member and takes its DTE pointer from member data supplied by CConnect
during construction. The static version is pretty erroneous now and we'll
probably remove it shortly.

RemoveCommand() should be called for each command supported by your add-in
by your CConnect::OnConnection()  immediately before trying to add commands
when the connect mode is ext_cm_UISetup.

Pointers to all of the CVsCommandHandler objects are stored in a
name=>pointer map within CConnect, so it just iterates through them all and
removes the command for each (as well as removing the add-ins toolbar and
menubar of course).

Then it adds its commands as usual. We're left that at a higher level for
now, which keeps the command handler classes simple.

> Is all of this in the book you recommended?   Does it cover ATL?

The book covers all of these concepts, as well as the project/soluton model,
macros, the code model, installers, help integration etc. It's pretty good.
:)

All the examples are in C# which is another reason to learn the language. ;)

Incidentally we're seriously considering writing an article on
codeproject.com using some of the code I've described. The premise is that
the code generated by the add-in wizard is ghastly, and since we have a
better (read: more OO) design for a skeleton C++ add-in we'd like to share,
what better way to do that than to show others how to change the code
generated by the wizard to something more friendly and maintainable?

As ever, the one thing in the way is time. I am quite keen to do this one
though, so hopefully we'll find time to do it in the near future.

Kind Regards,

   Anna-Jayne Metcalfe

   Software/Product Development Consultant,
   Riverblade Limited.
   http://www.riverblade.co.uk

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.