5

First of all I know there are many questions that look like this one but I couldn't really get an answer for my problem.

So in general, I am running a program that needs to get a path to a solution of another visual studio project solution file and I only have the name of the file itself.

For example, my program is running in the background and there is a visual studio project currently being coded, I need to get the path to the solution of this project. The project wasn't compiled yet, it's a new project that was just created. For example MyProject.sln is the file and the directory I am looking for is C:\Users\MyUser\Documents\Visual Studio 2015\Projects\MyProject\MyProject.sln. Of course the project can be anywhere on the computer, like a different drive, or not in the visual studio folder.

I tried using methods such as Path.GetDirectoryName(filename) which returns an empty string, or Path.GetFullPath(path) which returns a wrong path (the one of the program that searches for the path), or Directory.GetDirectories(path,searchPattern) some with the SearchOptions, and then I get authorization errors for SearchOption.AllDirectories on a lot of files.

I am really lost here, I hope someone can help!

Søren D. Ptæus
  • 4,176
  • 1
  • 26
  • 28
Ron Bitterman
  • 131
  • 1
  • 6
  • So, you want to find the path to the project that is currently open in Visual Studio?... I'm not sure you'll be able to do this - not easily anyway – Sayse Nov 30 '16 at 08:52
  • 2
    if you have the name, you could of course do an iterative search across the drives available, but that could take a long time depending on the drives.. alternatively you could see if you can interrogate the process and find out which files it has open – BugFinder Nov 30 '16 at 08:54
  • @BugFinder what does it mean to interogate the process? – Ron Bitterman Nov 30 '16 at 09:24
  • 1
    http://stackoverflow.com/questions/860656/using-c-how-does-one-figure-out-what-process-locked-a-file – BugFinder Nov 30 '16 at 09:29

5 Answers5

1

I don't think you'll be able to get the projects path in visual studio easily.

It would be much easier if your own program was the one to open visual studio and the project - which of course would require some user cooperation

I haven't tried it myself but you'd need to use the devenv command in your own program

Devenv /edit [file1[ file2]]  
Sayse
  • 42,633
  • 14
  • 77
  • 146
0

Use

    var ProjectLocation = Path.GetDirectoryName(Path.GetDirectoryName(System.IO.Directory.GetCurrentDirectory()));
    var SlnLocation = (ProjectLocation + "\\" + "SolutionName.sln");

this will give you the full directory.

Bernard Walters
  • 391
  • 1
  • 4
  • 16
  • 1
    this one gives me the path of my programs location. i need the get the path of another visual studio program that is being coded – Ron Bitterman Nov 30 '16 at 09:13
  • You could just always hardcode the directory...but use the Projects name as a variable in the string. – Bernard Walters Nov 30 '16 at 09:15
  • i can't hardcode the directory since the project can be created anywhere in the computer. i need to find it's path when it is created. – Ron Bitterman Nov 30 '16 at 09:30
  • I know exactly what you can do, You can create a file(xml) that stores the location of the other project...basically, all you do is, every time the other project is rebuilt...the OTHER project updates the path that is stored in the xml file...so every time you need the location of the other project....you can just read the xml file in YOUR project and bam, you have the location. – Bernard Walters Nov 30 '16 at 09:36
  • thats the only way i know how, BECAUSE it can change locations, its really hard to do what you want and you can always just use a simpler fix – Bernard Walters Nov 30 '16 at 09:37
0

Here is the code that searches for the file name of the file throughout the file system, I hope this will help you.

    static void Main(string[] args)
    {
        Console.WriteLine("Enter file name...");
        string fileName = Console.ReadLine();
        var result = FindFile(fileName);
        foreach (var files in result)
        {
            foreach (var file in files)
            {
                Console.WriteLine(file);
            }
        }
    }

    public static List<string[]> FindFile(string fileName)
    {
        string[] drives = Environment.GetLogicalDrives();
        List<string[]> findedFiles = new List<string[]>();
        foreach (string dr in drives)
        {
            Console.WriteLine($"Start looking in {dr}");
            System.IO.DriveInfo di = new System.IO.DriveInfo(dr);
            if (!di.IsReady)
            {
                Console.WriteLine("The drive {0} could not be read", di.Name);
                continue;
            }
            DirectoryInfo rootDir = di.RootDirectory;
            var findedFiletmp = Directory.GetFiles(rootDir.Name, fileName, SearchOption.TopDirectoryOnly);
            if (findedFiletmp.Length > 0)
            {
                findedFiles.Add(findedFiletmp);
                Console.WriteLine("Finded file.Continue search?(Y/N)");
                string answer = Console.ReadLine();
                if (answer.ToLower().Equals("n"))
                {
                    break;
                }
            }
            var subDirectories = Directory.GetDirectories(rootDir.Name);
            bool breaked = false;
            foreach (var subDirectory in subDirectories)
            {
                try
                {
                    var findedFiletmp1 = Directory.GetFiles(subDirectory, fileName, SearchOption.AllDirectories);
                    if (findedFiletmp1.Length > 0)
                    {
                        findedFiles.Add(findedFiletmp1);
                        Console.WriteLine("Finded file.Continue search?(Y/N)");
                        string answer = Console.ReadLine();
                        if (answer.ToLower().Equals("n"))
                        {
                            breaked = true;
                            break;
                        }
                    }
                }
                catch (Exception exc)
                {
                    Console.WriteLine(exc.Message);
                }
            }
            Console.WriteLine($"Finished looking in {dr}");
            if (breaked)
                break;
        }
        return findedFiles;
    }
Samvel Petrosov
  • 7,580
  • 2
  • 22
  • 46
  • it seems to iterate only threw the first directories under the drives. how can i get deeper without getting the unauthorized exception? – Ron Bitterman Nov 30 '16 at 10:21
  • @RonBitterman it iterates the first directory files and go to other directories if you have rights to access that folders. You can't access to them without rights. – Samvel Petrosov Nov 30 '16 at 10:28
0

Here's a solution for you. It parses all open processes to find any open in Visual Studio (even files not running still create a vshost process). Then it checks the process module name against your provided name and finally returns the path to the solution file. The example in button1_click shows how to retrieve the actual solution file name (not sure if it would ever differ from the directory name anyways):

    public string GetVSProgramPath(string filename)
    {
        Process[] plist = Process.GetProcesses();

        foreach (Process theprocess in plist)
        {
            try
            {
                ProcessModule pm = theprocess.MainModule;
                if (theprocess.MainModule.ModuleName.Contains("vshost") && theprocess.MainModule.ModuleName.ToLower().Contains(filename.ToLower()))
                {
                    string path = theprocess.MainModule.FileName;
                    int loc = path.IndexOf(@"\Projects\");
                    return path.Substring(0, path.IndexOf(@"\", loc + 10));                        
                }
            }
            catch (Exception ex)
            {
            }
        }
        return string.Empty;
    }

An example of usage:

    private void button1_Click(object sender, EventArgs e)
    {
        string path = GetVSProgramPath("MyProject");
        string solutionFile = System.IO.Directory.GetFiles(path, "*.sln")[0];

    }

I know the search is not optimized, but I'll leave that part to you ;)

Troy Mac1ure
  • 637
  • 4
  • 9
  • This will give you the Project path, not the solution one. And it probably won't work if "Enable the Visual Studio hosting process" is not flagged in the project properties – Matteo Umili Nov 30 '16 at 10:40
0

Using the code suggested by @BugFinder you can do something like this:

static void Main(string[] args)
{
    try
    {
        foreach (var proc in Process.GetProcessesByName("devenv"))
        {
            var files = Win32Processes.GetFilesLockedBy(proc);
            Regex rgxDbFile = new Regex("\\.opendb$", RegexOptions.IgnoreCase);
            foreach (var item in files.Where(f => rgxDbFile.IsMatch(f)))
            {
                Console.WriteLine(item);
            }
        }
        Console.ReadKey(true);
    }
    catch (Exception ex)
    {
        ex.ToString();
    }
}

We filter the returned values with the regex \\.opendb$ because VS opens a lot of files and the one which reference the opened solution ends with opendb:

enter image description here

Given that path it will be trivial to detect the .sln name.

Note: if VS runs as admin, also your process will need to run with that permissions...

Community
  • 1
  • 1
Matteo Umili
  • 3,412
  • 1
  • 19
  • 31
  • im getting `System.AccessViolationException` for this line `var strObjectTypeName = Marshal.PtrToStringUni(ipTemp, objObjectType.Name.Length >> 1);` and i cant find an answer in that post, any suggestions? – Ron Bitterman Nov 30 '16 at 10:56
  • @RonBitterman What is the full message of the exception? Are you running x64? – Matteo Umili Nov 30 '16 at 11:09
  • yes i am running x64. the full exception: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. – Ron Bitterman Nov 30 '16 at 11:14