none
Include existing folder path as project item RRS feed

  • Question

  • Hi,

    I'm trying to add files to projects organizing them in folders before adding. The scenarios:

    1. Before adding the file check if the folder exists as a project item. If so, the project item is used to add the file.

    2. Otherwise check if the folder path exists. If so, include folder path as project item and use to add the file.

    3. Otherwise the folder is unknown. Add the folder as project item and use to add the file.

    Scenario 1 and 3 work, but I can't get scenario 2 to work. The code:

    var service = package.GetService<SDTE, EnvDTE80.DTE2>(); foreach (Project project in service.Solution.Projects) { var folder = project.AddFolderIfNotExists("Folder"); var file = folder.ProjectItems.AddFromFileCopy(@"c:\temp\somefile.cs"); }

    public static class ProjectItemsExtensions
    {
        public static Guid ProjectItemKindFolder = new Guid("{6BB5F8EF-4483-11D3-8BCF-00C04F8EC28C}");
        public static ProjectItem GetFolder(this Project project, string folderName)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            foreach (ProjectItem item in project.ProjectItems)
            {
                var kind = new Guid(item.Kind);
                if (kind != ProjectItemKindFolder) continue;
                if (item.Name.ToLowerInvariant().Equals(folderName.ToLowerInvariant())) return item;
            }
            return null;
        }
        public static ProjectItem AddFolderIfNotExists(this Project project, string folderName)
        {
            //*****
            ThreadHelper.ThrowIfNotOnUIThread();
            //***** Determine if folder is included in the project;
            var folder = GetFolder(project, folderName);
            if (folder != null) return folder;
            //***** Determine if the folder path exists. If so include in the project;
            var projectPath = Path.GetDirectoryName(project.FileName);
            var folderPath = Path.Combine(projectPath, folderName);
            if (Directory.Exists(folderPath)) return project.ProjectItems.AddFolder(folderPath);
            //***** Else add folder;
            folder = project.ProjectItems.AddFolder(folderName);
            return folder;
        }
    }

    The AddFolder methods throws an exception that the folder already exists.

    When adding the file I need the folder first as project item to add it in context. No luck with the AddFile* methods as well.

    Any ideas on how I can include the folder in the project?

    Cheers,

    Peter

    Thursday, September 5, 2019 11:52 AM

All replies

  • Hi soep666,

    Welcome to MSDN forum.

    Based on your description, the first parameters of AddFolder() is the name of the folder node in Solution Explorer. It should be a "name" instead of "directory". Please refer more: ProjectItems.AddFolder

    And in my opinion,  the situations which are "check if the folder path exists..." and "the folder is unknown....", are the same for project, because the folder doesn't existed in project, so maybe you just need to judge if folder is included in the project.

    Any feedback will be expected.

    Best Regards,

    Dylan


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com

    Friday, September 6, 2019 9:36 AM
  • Hi Dylan,

    Thanks for your reply.

    I know AddFolder requires a name instead of path, but I was desperate ;).

    I've commented out the check for existing folder paths, resulting the AddFolder method to be called. 

    Calling AddFolder results in "Folder already exists"-exception:

    System.InvalidOperationException
      HResult=0x80131509
      Message=Folder already exists with the name 'Aggregates'
      Source=Microsoft.VisualStudio.ProjectSystem.VS.Implementation
      StackTrace:
       at Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAProjectItems.<>c__DisplayClass2_0.<<AddFolder>b__0>d.MoveNext()
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAProject.<>c__DisplayClass68_0`1.<<Mutate>b__0>d.MoveNext()
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.ProjectNode.<>c__DisplayClass576_0.<<Mutate>b__0>d.MoveNext()
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at Microsoft.VisualStudio.Threading.JoinableTask.CompleteOnCurrentThread()
       at Microsoft.VisualStudio.ProjectSystem.ProjectMultiThreadedService.ExecuteSynchronously(Func`1 asyncAction)
       at Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.ProjectNode.Mutate(Func`1 asyncAction, Boolean includesFileSystemChange, String telemetryActivity)
       at Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAProject.Mutate[T](Func`1 asyncAction, Boolean includesFileSystemChange, String telemetryActivity)
       at Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAProjectItems.AddFolder(String name, String kind)

    As folders can contains other items while being excluded from the project I can't simply delete the folder and re-add. I really need something like a "Include in project"-method.

    Cheers,

    Peter

    Friday, September 6, 2019 1:34 PM
  • Hi soep666,

    Sorry for delay in reply.

    Did you mean the existing folder has located in the project directory? If so, I'm sorry for misunderstanding it.

    The "Add folder" will create a new folder in solution explorer and project directory, and it will be a conflict with existing folder, so it will throw a exception.

    Please try to use "AddFromDirectory" to add your folder to project, then reload your project in VS IDE.

    NOTE: the folder path should be the previous level of the destination folder,for example: D:\\test\\Aggregates

    if (Directory.Exists(folderPath))   project.ProjectItems.AddFromDirectory("D:\\test");

    The interface will add all of the items in the specified directory (and subdirectories) .

    Hope it could help you.

    Best Regards,

    Dylan


    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com

    Monday, September 9, 2019 9:49 AM
  • Hi Dylan,

    No worries, happy with your help!

    I've tried your proposed workaround, but no luck unfortunately… The path it would be adding is the project path resulting in the exception:

    Cannot add directory to its own item collection.

    Which actually makes sense when you think about it. To be sure I've tried the specific directory as well. This resulted in an exception as well:

    Destination directory already exists.

    Strange right? Including and excluding project items should be quite basic functionality?!

    Cheers,

    Peter

    Monday, September 9, 2019 10:29 AM
  • Hi soep666,

    Thank you for forgiveness.

    I have tried to check other api interface, for example solution explorer, but I couldn't still find related interface about including and exculding. 

    And for this requirement, I think out a little sumbersome methods: you could move the existing folder to other directory, then use "AddFolder()" to create a new folder in your project, then copy the items from older to the new one. It is like deleting it then re-add it. Sorry for this inconvenience.

    The below samples are about copying and how to add existing folder with items into solution explorer.

    Copy sub-folders and files:

    var SourceFolderPath = "...";
    var projectPath = Directory.GetDirectoryName(project.FileName);
    project.ProjectItems.AddFolder(folderName);
    var DestinationFolderPath = Path.Combine(projectPath, folderName);
    
    //*** copy sub folder with files to destination
    foreach (var dir in System.IO.Directory.GetDirectories(SourceFolderPath))
    {
        var dirInfo = new System.IO.DirectoryInfo(dir);
        System.IO.Directory.CreateDirectory(System.IO.Path.Combine(targetPath, dirInfo.Name));
        foreach (var file in System.IO.Directory.GetFiles(dir))
        {
            var fileInfo = new System.IO.FileInfo(file);
            // true means if the file exists, it will overwrite
            fileInfo.CopyTo(System.IO.Path.Combine(DestinationFolderPath, dirInfo.Name, fileInfo.Name),true);
        }
    };
    
    //*** copy files to destination
    foreach (var file in System.IO.Directory.GetFiles(SourceFolderPath))
    {
        var fileInfo = new System.IO.FileInfo(file);
        // true means if the file exists, it will overwrite
        fileInfo.CopyTo(System.IO.Path.Combine(DestinationFolderPath, fileInfo.Name), true);
    }

    Add folder with items into solution explorer, which is from this thread.

    DTE2 dte;
    EnvDTE.Project project;
    dte = ...
    project = dte.Solution.Projects.Item(1);
    
    AddFolderAndFiles(project, "My Folder");
    private void CreateFiles(string folderFullName)
    {
      System.IO.File.AppendAllText(System.IO.Path.Combine(folderFullName, "dummy1.cs"), "using System;");
      System.IO.File.AppendAllText(System.IO.Path.Combine(folderFullName, "dummy2.cs"), "using System.Windows.Forms;");
    }
    
    private void AddFolderAndFiles(EnvDTE.Project project, string folderName)
    {
       EnvDTE.ProjectItem folder;
       string folderFullName;
       string[] fileFullNames;
    
       try
       {
          folder = project.ProjectItems.AddFolder(folderName);
    
          folderFullName = folder.FileNames[0];
    
          CreateFiles(folderFullName);
    
          fileFullNames = System.IO.Directory.GetFiles(folderFullName);
    
          foreach (string fileFullName in fileFullNames)
          {
             folder.ProjectItems.AddFromFile(fileFullName);
          }
       }
       catch (Exception ex)
       {
          System.Windows.Forms.MessageBox.Show(ex.ToString());
       }
    }

    BTW, I recommend you could provide a suggestion about this interface to developer community, then share the link here, and other community members who are interested will help you vote it.

    Hope it could help you.

    Best Regards,

    Dylan



    MSDN Community Support Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com

    Tuesday, September 10, 2019 10:00 AM