0

I have created a Visual Studio multi-project template in which one is a 'Shared' project, and another is a normal project for common 'Resources'. The other 5 normal projects each need to reference both the 'Shared' and the 'Resources' projects.

Template Project

On a separate solution I then create a VISX extension to implement a wizard, but instead of pointing the .vsixmanifest Asset to "A project in current solution", I point to the .zip multi-project template I created.

My intent is to then use the vsix wizard to add the necessary project references. I've already done so with envDTE, and it works beautifully... mostly.

A reference to the 'Resources' project is added without a problem. The issue is when trying to add a "shared" project as a reference. I've tried using both the (Project) and the (Filename.shproj) arguments.

    DTE VS = automationObject as DTE;

    // This method is called after the solution is created.
    public void RunFinished()
        DTE VS = automationObject as DTE;
    {
        Microsoft.VisualStudio.Shell.ThreadHelper.ThrowIfNotOnUIThread();

        Project sharedProj = null;
        Project resourceProj = null;
        List<Project> versionProjs = new List<Project>();
        foreach (Project project in VS.Solution.Projects)
        {
            if (project.Name.Contains("Resources")) { resourceProj = project; }
            else if (project.Name.Contains("Shared")) { sharedProj = project; }
            else { versionProjs.Add(project); }
        }

        foreach (Project version in versionProjs)
        {
            // Add reference to shared project
            VSProject vsProj = (VSProject)version.Object;
            if (sharedProj != null)
            {
                // !!! Shared project should be added as a reference here, but it is causing a critical error. !!!

                //BuildDependency bldDepends = VS.Solution.SolutionBuild.BuildDependencies.Item(version.UniqueName);
                //bldDepends.AddProject(sharedProj.FileName);
                //vsProj.References.Add(sharedProj.FileName);

                //vsProj.References.AddProject(sharedProj);
            }

            // Add reference to the Resources project
            if (resourceProj != null) { vsProj.References.AddProject(resourceProj); }
        }
    }

AddProject(Project) results in:

Exception thrown:'System.Runtime.InteropServices.COMException' in TemplateExtension.dll

Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))

AddProject(Filename.shproj) results in:

Exception thrown: 'System.Runtime.InteropServices.COMException' in TemplateExtension.dll

Please make sure that the file is accessible, and that it is a valid assembly or COM component.


EDIT 1

I have decided to make my project open to the public. The source code to this problem can be found here: https://github.com/theBIMdev/RevitExtension

The offending code specifically is in the Wizard.cs file. The commented out section represents 3 different attempts.

  • Adding the project to the dependencies
  • vsProj.References.Add(sharedProj.FileName);
  • vsProj.References.AddProject(sharedProj);

EDIT 2

This problem has received some attention and been escalated by Microsoft here.

Leetheus
  • 56
  • 8

1 Answers1

0

Without debugging through a repro, my initial suspicion is that the shared project type probably doesn't support that particular operation.

That being said, instead of programmatically trying to add the reference, you could just add the project reference to the templatized project files that need them.

I did something similar a number of years ago, where I leveraged the ReplacementsDictionary to swap in the custom project name(s) I needed into, the various project files. Sadly, I lost that code some time back, but this might give you an optional solution to pursue. Namely, think about adding the reference to the shared project via the templatized project files.

Sincerely,

Ed Dore
  • 2,013
  • 1
  • 10
  • 8
  • This solution is one of the things I considered. I can easily add $sharedprojname$ to the ReplacementsDictionary, but back in the template of each 'real' project, I don't see how I can replace the reference to the shared project with $sharedprojname$. I have even tried creating a new shared project NAMED $sharedprojname$, but even then, the import fails to find "AppData/Temp/somefolder/SharedProjectName.projitems". This would be a great workaround, if you could remember what you had to do to make it work. – Leetheus Aug 04 '21 at 21:21
  • I associated the same IWizard to all the templates, and used the customParams[0] argument to figure out which template myIWizard.RunStarted was being invoked with. Based on the filename of the .vstemplate, I'd store the desired projectname in a private static string, and retrieve it and swap into the replacements dictionary when invoked by the other .vstemplate. – Ed Dore Aug 05 '21 at 21:08
  • In you solution, then, does the user have several templates to pick from when creating a new project? I'm not including the template projects individually in the vsix solution. I'm creating a multi-project template, and adding that zip file to the vsix solution. My thinking was that if I added each template individually to the vsix project (and select "Project in Solution" in .vsixmanifest Assets tab), I would end up with multiple separate templates for the user to pick from, which I don't want. Retrieving the project name itself is not a problem, it's telling the nested template ref. – Leetheus Aug 06 '21 at 05:56
  • I opted to just make one template visible, and programmatically add the other projects via hidden templates, as mentioned here : https://learn.microsoft.com/en-us/archive/blogs/vsx/the-vsx-template-wizard#a-multi-project-template-that-isnt – Ed Dore Aug 11 '21 at 01:12