Question

I'm writing a VSIX package to allow the user to bulk-edit the OutputPath property of all the active configurations of projects in the currently loaded solution (see the incredibly annoying step #4 here).

I ran into a very specific problem: when setting the property to a value containing macros (e.g. "$(SolutionDir)\bin\Debug" the value written into the .csproj is escaped as follows:

<OutputPath>%24%28SolutionDir%29\bin\Debug\</OutputPath>

Which, rather than letting MSBuild expand the macro, creates an actual physical folder named $(SolutionDir). I'd like to somehow bypass this escaping.

The MSDN documentation is unsurprisingly lacking in that area.

My initial code is as follows:

private void MenuItemCallback(object sender, EventArgs e)
{
    SolutionWideOutputDialogWindow dialog = new SolutionWideOutputDialogWindow();
    dialog.ShowModal();
    if (!dialog.DialogResult.HasValue || !dialog.DialogResult.Value)
    {
        return;
    }

    string requestedOutputPath = dialog.outputPathTextBox.Text;
    Solution2 solution = _dte2.Solution as Solution2;
    if (solution == null)
    {
        return;
    }

    Projects projects = solution.Projects;
    foreach (Project project in projects)
    {
        Property outputPath = project.ConfigurationManager.ActiveConfiguration.Properties.Item("OutputPath");
        outputPath.Value = requestedOutputPath;
        project.Save();
    }
}

Greatly appreciate anyone's help.

Was it helpful?

Solution 2

Here's what I ended up doing:

The problem I was trying to solve is not repeating myself (D.R.Y.) and specifying a solution-wide output directory (in a solution with a lot of projects) - that is, when compiling a solution, all projects would have their output directory set to something like $(SolutionDir)bin\Debug or $(SolutionDir)bin\Release. It is worth mentioning that some projects are included across repositories and in more than one solution.

At first, I created an MSBuild file (a <Project> XML - called it MySolution.sln.targets). In it, I defined a <PropertyGroup> that overrode the <OutputPath> property to:

$(SolutionDir)bin\$(Platform)\$(Configuration)

Then I added the following import to all the relevant projects, before the build targets import:

<Import Project="$(SolutionPath).targets" />

That way, each solution has an accompanying .targets file defining such things that I want to be solution-wide.

This worked well, but then I encountered the following problem: The abovementioned $(Platform) and $(Configuration) macros refer to the project's properties, not the solution-wide ones. What would happen if my solution's Debug/Any CPU configuration still built some very specific project in its Release configuration? As far as I'm aware, after thoroughly examining the documentation, no such macros are exported that have a solution-wide granularity.

I found ceztko's Visual Studio extension which made Visual Studio export exactly the macros that I was looking for - but after some experimentation and fiddling, I discovered that this extension set them too late - only upon building the solution. This caused issues with Visual Studio's Incremental Build feature - It kept thinking that the projects were out of date because it was looking in the wrong place - it wasn't aware of the variables, but MSBuild.exe was.

I started fiddling with the IVsUpdateSolutionEvents interface, tracing when each method is called - and then discovered that IVsUpdateSolutionEvents.OnActiveProjectCfgChange is called twice when opening a 1-project solution in a fresh Visual Studio, or when changing the solution's configuration from Debug to Release. Further fiddling revealed that if I set the project to compile in Release in both solution configurations, this method now got called once instead of twice when changing solution configurations.

I forked the extension's repository and amended the issue by moving the macro-setting logic to the above-mentioned method. You can find it here.

Disclaimer: this may not interact so well with batch-build operations from the IDE, and requires you to export these properties yourself when building from MSBuild.exe's command-line.

Good luck in your travels.

OTHER TIPS

Visual Studio will unfortunately escape special characters when editing from project properties.

To fix this, edit your .csproj file directly in a text editor.

For example, change:

<OutputPath>%24%28SolutionDir%29\bin\Debug\</OutputPath>

to:

<OutputPath>$(SolutionDir)\bin\Debug\</OutputPath>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top