Execute macro only for one solution

B

Bob Altman

Hi all,

I have a solution that contains a bunch of projects. When I save a file in any
of the projects in this solution, I want to execute a macro that updates the
project's assembly version. But I only want this behavior for this one
solution. Is there a way to have a Macro that fires for environment events only
for a particular solution? (I guess I could have the event handler check to see
if this is the desired solution before doing anything, but that's kind of a
backward way of going about it. But maybe that's the Zen of macros.)

On a related subject: Optimally, I would like to have the macro use some
constants defined in an assembly in the solution when it updates the assembly
version numbers. This means that the macro needs to have a reference to
assemblies in this one solution, which is really tacky. Any thoughts or
suggestions?

Bob
 
B

Bob Altman

Bob Altman said:
Hi all,

I have a solution that contains a bunch of projects. When I save a file
in any of the projects in this solution, I want to update the project's
assembly version.

I forgot to add that I would like this behavior of automatically updating
the project's assembly version to extend to other developers on my team who
might touch this code. Creating and subsequently maintaining a macro to do
this, and, in particular, distributing that macro to the rest of my team,
doesn't strike me as a particularly palatable task. We have the VS 2005
team suite server stuff, but we've never turned on the server or
investigated what it can do for us. Can it help with this sort of
collaboration?

TIA - Bob
 
S

Steve Gerrard

Bob said:
I forgot to add that I would like this behavior of automatically
updating the project's assembly version to extend to other developers
on my team who might touch this code.

It doesn't make sense to me to update a project's assembly version every time a
file is saved, especially in a team environment.

First of all, it would mean that only one developer could work on a project at a
time, since making any changes would require them to also have checked out the
project file. That seems too limiting.

Second, updating the assembly number after every file change doesn't make sense
to me. Someone may have changed the caption on a label, or changed the text of
an error message, or some other minor tweak. I save changes to files dozens of
times a day, and build several times a day at least. Mulitply by the number of
developes, and you have 50 new revisions a day possible.

Why not make a macro that updates all the project assembly numbers for the
solution on demand, that is, from an explicit menu command. Then, when you are
ready to do a new release, meaning a real production release build of the entire
solution, you can run the macro to update the revision numbers.
 
B

Bob Altman

Good questions...

First, a little background. The project in question produces a bunch of
assemblies that are installed in the GAC on customer machines. The
application supports side-by-side installations, and we often have several
versions of the application (and these assemblies) installed on customer
machines at the same time. Each time we create a new release I need to
ensure that assemblies that change get a new version number, but I don't
want to change the version numbers on unchanged assemblies.
First of all, it would mean that only one developer could work on a
project at a time, since making any changes would require them to also
have checked out the project file. That seems too limiting.

Not the project file (that only changes if project settings change or if
files are added or removed from the project), but, yes, we might have to
coordinate changes to the AssemblyInfo.vb file. Realistically, it's very
rare in our shop for more than one developer to have his or her fingers in
the same project at the same time. Even if this were to happen, we could
just let the first developer get the exclusive checkout (the default
behavior) and prevent subsequent developers from modifying the version
number (at least until the first developer checks it back in). In any
event, the version number gets changed, which is all I care about.
Second, updating the assembly number after every file change doesn't make
sense to me. Someone may have changed the caption on a label, or changed
the text of an error message, or some other minor tweak. I save changes to
files dozens of times a day, and build several times a day at least.
Mulitply by the number of developes, and you have 50 new revisions a day
possible.

Numbers are cheap. Even if I my algorithm incremented the version number
each time someone updated a file, I'd be surprised if we could manage to get
65,535 file updates in one release cycle.

But that gets me back to the issue of accessing constants in one of my
assemblies as part of the version number fabrication exercise. Each time I
start working on a new version of the product, I update some constants that
identify the product version. These constants drive the version number that
is displayed in Help|About (among other places). When I detect a change to
a file in an assembly, I set the assembly version number using these
constants. In other words, an assembly's version number reflects the
product version in which the assembly was modified. This means that I
really only change the version number once per project per release cycle.
Subsequent changes to a project's files (during a release cycle) would
detect that the version number doesn't need to be modified.
Why not make a macro that updates all the project assembly numbers for the
solution on demand, that is, from an explicit menu command. Then, when you
are ready to do a new release, meaning a real production release build of
the entire solution, you can run the macro to update the revision numbers.

That would work, but it doesn't solve any of my problems. Wiring up events
so that the version number updates automatically is the easy part. But
macros are localized to each developer's computer. The tough part is
setting up a work environment where anyone who works on this particular
project has access to the magic version updating mechanism, preferably
without having to add some steps where any developer who works on this
project first needs to import some macro (and hope that nothing in the macro
conflicts with or breaks any of the developers existing macros).
 
W

Wen Yuan Wang [MSFT]

Hello Bob,
Is there a way to have a Macro that fires for environment events only for
a particular solution?

You can add check if current soluion is your particular solution in related
event.
For example:
Private Sub DocumentEvents_DocumentSaved(ByVal Document As EnvDTE.Document)
Handles DocumentEvents.DocumentSaved
Dim currentSolution As Solution
currentSolution = Document.DTE.Solution
If currentSolution.FullName =
"C:\Users\v-wywang\Documents....\WebApplication34.sln" Then
System.Windows.Forms.MessageBox.Show("Save File Name:" &
Document.Name)
End If
This means that the macro needs to have a reference to assemblies in this one solution, which is really
tacky. Any thoughts or suggestions?

In Marco IDE, I'm afraid to say we cannot add reference to assemblies in
solution. You may consider using system.Reflection namespace to load dll,
and get some information from assemble.
We have the VS 2005 team suite server stuff, but we've never turned on the
server or investigated what it can do for us.
I'm afraid to say you may have to do that by yourself. As far as I know,
TFS doesn't help on distribute macro to each one of your team.

Hope this helps. Please feel free to let me know if there is anything
unclear. We are glad to assist you.
Have a great day,
Best regards,
Wen Yuan

Microsoft Online Community Support
Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).
==================================================
Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.

Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
B

Bob Altman

It turns out that VS 2005 supports "Solution Add-Ins", which are add-ins that
are only loaded for a specific solution. By creating such an add-in, I can
extend the IDE to implement my custom version policy only for solutions that
reference the add-in.

The MSDN help topic is at this URL:

ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_extcore/html/46c7aa5d-6cec-4723-bca2-4b20699cfc55.htm

Bob
 
W

Wen Yuan Wang [MSFT]

Hello Bob,
Thanks for your reply.
I agree with you. Add-in should be the best solution in this scenario. :)

Have a great day. Please feel free to let us know if you have any more
concern. We are glad to assist you.
Best regards,
Wen Yuan

Microsoft Online Community Support
Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
B

Bob Altman

Bob Altman said:
It turns out that VS 2005 supports "Solution Add-Ins", which are add-ins
that are only loaded for a specific solution. By creating such an add-in,
I can extend the IDE to implement my custom version policy only for
solutions that reference the add-in.

The MSDN help topic is at this URL:

ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.VisualStudio.v80.en/dv_extcore/html/46c7aa5d-6cec-4723-bca2-4b20699cfc55.htm

Just one little itsy bitsy minor problem... Like almost all of the online
documentation covering IDE extensibility, the help topic referenced above is
misleading, incomplete, and just plain wrong. The supplied example doesn't
compile. Fundamental concepts of how to register a "solution add-in" and
how to reference one are either missing altogether or are only hinted at.

If someone in this group can come up with a decent explanation of how to get
a "Solution Add-In" wired up and working I'd be forever grateful. In the
mean time, I'm asking this same question in the microsoft.public.vsnet.ide
newsgroup.

Bob
 
B

Bob Altman

It turns out that VS 2005 supports "Solution Add-Ins", which are add-ins that
Just one little itsy bitsy minor problem... Like almost all of the online
documentation covering IDE extensibility, the help topic referenced above is
misleading, incomplete, and just plain wrong.

FYI, I burned an MSDN tech support issue and started a support case. After a
few minutes of looking at the documentation and looking at the code produced by
the Add-in wizard, the support engineer came to the conclusion that the
documentation makes absolutely no sense at all. He's off trying to find out if
the IDE actually supports the concept of a "solution" add-in.

Bob
 
W

Wen Yuan Wang [MSFT]

Hello Bob,
Thanks for your reply.

I'm not sure why they said it is wrong, but I think the method described on
MSDN website should work. Moreover, I tried it on my machine, and it works.
VS IDE only loads add-in for my specified solution.

Below is the steps which I tried and it works fine on my side.

1) Create a VS add-in project named : MyAddin
2) We need to know if VS will load our add-in for specified solution.
Thereby, I prompt a messagebox in its OnConnection method.

public void OnConnection(object application, ext_ConnectMode connectMode,
object addInInst, ref Array custom)
{
_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;
System.Windows.Forms.MessageBox.Show("Loaded");
}

3) Right-click the project and select Properties. Click the Build tab and
check the Register for COM interop box.
4) Complie your add-in project.
5) Then, start VS command prompt and enter" regasm /codebase
SolutionAddinName.dll" to register it with Windows.
6) Close your add-in project and open the particular solution which you
want to be bound with previous add-in.
7) Open Marco IDE. Run the following code. (Note: this steps is different
from MSDN document, but it also could be done in OnConnection event as
well.)

DTE.Solution.AddIns.Add("MyAddin.Connect", "MyAddin - No Description
provided.", "MyAddin - No Name provided.", True)

8) Close your solution and open it again.
9) You will get a messagebox said "Loaded".

10) If you look into this solution file, you will notice the following line
has been added.

GlobalSection(ExtensibilityAddIns) = postSolution
MyAddin.Connect = 1;MyAddin - No Description provided.;MyAddin - No Name
provided.
EndGlobalSection

Hope this helps. Please feel free to let me know if there is anything
unclear. We are glad to assist you.
Have a great day,
Best regards,
Wen Yuan

Microsoft Online Community Support
Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
B

Bob Altman

I'm not sure why they said it is wrong, but I think the method described
on
MSDN website should work. Moreover, I tried it on my machine, and it
works.
VS IDE only loads add-in for my specified solution.
-- snip --
7) Open Marco IDE. Run the following code. (Note: this steps is different
from MSDN document, but it also could be done in OnConnection event as
well.)

Actually, it works from a macro but it not in OnConnection (at least not the
way the code sample is written). In addition to the fact that the VB code
sample is just plain bogus (it calls a non-existent "Solution2" method), it
turns out that calling the Solution.AddIns.Add method causes OnConnection to
be recursively called. Unless you add some code to prevent the second
invocation of OnConnection from calling Solution.AddIns.Add, the second call
to Solution.AddIns.Add fails and the changes made to the solution file are
thrown away.

I have a complete write-up of how to get a solution add-in wired up and
working. I'm just waiting for the tech support guy to proof it before I
post it here.

Bob
 
B

Bob Altman

It turns out that VS 2005 supports "Solution Add-Ins", which are add-ins
FYI, I burned an MSDN tech support issue and started a support case.

That was one of the most productive and fulfilling support contacts I've ever
had. It turns out that, yes, the documentation is bogus. Here is how to wire
up a "solution add-in":

To begin, create a new Add-in project. Make sure you tell the wizard not to
automatically load your add-in.

Now, in order to work, this add-in must be registered with COM. This is because
this add-in is going to call the AddIns.Add method, which requires the target of
the method to be an add-in registered with COM. The "easy" way to register your
assembly with COM is to check the "Register for COM interop" check box on the
Compile tab of the project properties. However, this requires that you run with
admin privileges, because VS will try to fiddle with the registry every time you
build or clean your project. We're going to set things up so that we can
manually register the assembly (with admin privileges) but otherwise we can
build and test without admin privileges.

In order to register your assembly with COM (via regasm) you need to strong-name
sign it. The process to do this is well documented.

You also need to hard-code the assembly version so that the version number
registered with COM agrees with the version number you're actually deploying and
running.

In AssemblyInfo.vb (sorry C# folks, you need to translate this yourselves ;-)
' Hard-code the assembly version because
' we are going to strong-name sign the assembly
<Assembly: AssemblyVersion("1.0.0.0")>

' Specify a TypeLib GUID to expose this assembly to COM
<Assembly: GuidAttribute("your TypeLib GUID here")>

In Connect.vb, add the following lines before the class declaration:
<ClassInterface(ClassInterfaceType.None)> _
<Guid("your class GUID here")> _
<ComVisible(True)> _

This magic provides the metadata that regasm uses to expose your class to COM.
(Note that the two GUID values above must be different!) After you've built
your assembly, you need to run regasm as administrator. Right-click on the
shortcut to the VS 2005 command prompt and select "Run As..." and run the
command prompt as administrator. Then type in:

regasm /codebase <path to your dll>

Now, in the OnConnection routine, we're going to add code that recognizes when
the user selects our add-in in the add-in manager. When that happens then we're
going to persist the selection in the current solution (.sln file). Thereafter,
whenever the user opens this solution, our add-in will automatically load and
run.

Public Sub OnConnection(...) _
Implements IDTExtensibility2.OnConnection
_applicationObject = CType(application, DTE2)
_addInInstance = CType(addInInst, AddIn)

' If the user enables this add-in via the Add-In Manager then
' add this add-in to the solution's set of "registered" add-ins
If connectMode = ext_ConnectMode.ext_cm_AfterStartup Then
With _addInInstance
_applicationObject.Solution.AddIns.Add(
.ProgID, .Description, .Name, .Connected)
End With
End If
End Sub

(Note that you probably need to add error handling code. For example, the user
may select the add-in without first loading a solution.)

Finally, despite what the documentation says, you need to retain the ".AddIn"
files so that your add-in shows up in the Add-In Manager.

Good luck...

Robert Altman
 
W

Wen Yuan Wang [MSFT]

Hello Robert,

Thanks for sharing this great article with us. :)

Have a great day,
Best regards,
Wen Yuan

Microsoft Online Community Support
Delighting our customers is our #1 priority. We welcome your comments and
suggestions about how we can improve the support we provide to you. Please
feel free to let my manager know what you think of the level of service
provided. You can send feedback directly to my manager at:
(e-mail address removed).
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top