0

I have a C# Code Analysis Application that opens C# using ProcessStartInfo And Process Start. It almost works.

I want to use two instance of VS to perform the analysis: one to Debug the Analysis App, and another to have the File that is specified in its appropriate Solution.

Currently the C# File always opens in the Analysis App Debug Session, not the Analyzed App Solution. How can I specify which Instance to use upon Process.Start(ProcessStartInfo)?

private void OpenFileExecute(string file)
{
    ProcessStartInfo psi = new ProcessStartInfo(file);   
    psi.UseShellExecute = true;
    Process.Start(psi);
}
rene
  • 41,474
  • 78
  • 114
  • 152
Mark Wardell
  • 493
  • 7
  • 25

1 Answers1

1

With the standard open method you'll not be able to control which running instance will be used. Under the hood it uses DDE and it is undetermined which instance will handle DDE requests.

The same goes for when you use Activator.GetObject.

Luckily, in ole32.dll we can call GetRunningObjectTable and from there enumerate over all instances to find all registered OLE Servers, for each instance and that includes all Visual Studio processes.

Once we found one you can obtain an instance to its OLE Automation interface, EnvDTE and use that to inspect in-depth if this is the right instance to interact with, and if yes, execute any command we're interested in, for example loading a file.

private void OpenFileExecute(string file)
{
    IRunningObjectTable ir;
    // get all OLE/COM Automation servers
    GetRunningObjectTable(0, out ir);
    if (ir != null)
    {
        IEnumMoniker moniker;
        // Get an enumerator to iterate over them
        ir.EnumRunning(out moniker);
        if (moniker != null)
        {
            moniker.Reset();
            IMoniker[] results = new IMoniker[1];
            // iterate
            while (moniker.Next(1, results, IntPtr.Zero) == 0)
            {
                // we need a Bind Context
                IBindCtx bindCtx;
                CreateBindCtx(0, out bindCtx);
                // what is the name of the OLE/COM Server
                string objName;
                results[0].GetDisplayName(bindCtx, null, out objName);
                // what have we got ...
                Trace.WriteLine(objName);
                // I test with VS2010 instances, 
                // but feel free to get rid of the .10
                if (objName.StartsWith("!VisualStudio.DTE.10"))
                {
                    object dteObj; //
                    ir.GetObject(results[0], out dteObj);
                    // now we have an OLE automation interface 
                    // to the correct instance
                    DTE dteTry = (DTE)dteObj;
                    // determine if this is indeed
                    // the one you need
                    // my naive approach is to check if
                    // there is a Document loaded
                    if (dteTry.Documents.Count == 1)
                    {
                        dteTry.ExecuteCommand(
                            "File.OpenFile",
                            String.Format("\"{0}\"", file));
                    }
                }
                bindCtx.ReleaseBoundObjects();
            }
        }
    }
}

[DllImport("ole32.dll")]
public static extern int GetRunningObjectTable(int reserved,
                            out IRunningObjectTable prot);

[DllImport("ole32.dll")]
public static extern int CreateBindCtx(int reserved,
                                out IBindCtx ppbc);

Background reading: How to use Marshal.getActiveObject() to get 2 instance of of a running process that has two processes open

Community
  • 1
  • 1
rene
  • 41,474
  • 78
  • 114
  • 152
  • Well this only gets the EXE name of the Association. Which instance is the question? And then how to associate the open operation with that Instance? So this will not in my estimation solve the problem of which Instance to open it in. – Mark Wardell Dec 29 '16 at 18:18
  • I do not want a new Visual Studio Instance each time I call, – Mark Wardell Dec 29 '16 at 18:20
  • Then your question is a bit unclear. As I understood you don't want that file to be shown in a current instance of VS. That kind of leaves you with opening it in a new one. – rene Dec 29 '16 at 18:21
  • What sets the VS instance apart then that should be chosen? If you have 2 instances running, which one should take the file you give it? – rene Dec 29 '16 at 18:21
  • I have two currenty instance 1) Which the Analysis app is running debugging and getting built. 2) The instance with the .sln that is being Analyzed (125 .csproj) I want the Click from one to open the csfile in the instance from 2. – Mark Wardell Dec 29 '16 at 18:24
  • It probably always chooses the instance that was started first, right? – rene Dec 29 '16 at 18:28
  • Rene: That is correct. Temporarily I am changing my Start Order and it will work for me. But I cannot Check the code in until I repair to be independent of Start order – Mark Wardell Dec 29 '16 at 18:29