6

I followed this Stack Overflow post regarding how to create a project for VS2010, hoping that it would point me in the correct direction, but it doesn't cover creating a VS2012 project or solution.

I also explored using SLNTools, but I don't see how to create a new solution from scratch.

Ultimately, I would like to create 3-4 VS2012 projects programmatically and then add them to a solution which is also created programmatically.


I attempted a solution based on this Stack Overflow post, but I get an odd error. Here is the code:

    Type typeDTE = Type.GetTypeFromProgID("VisualStudio.DTE.11.0");
    var dte = (DTE)Activator.CreateInstance(typeDTE, true);
    var sln = (Solution2)dte.Solution;
    sln.Create(@"D:\Visual Studio\Projects","Test");

And here is the error:

enter image description here

Community
  • 1
  • 1
Matt Cashatt
  • 23,490
  • 28
  • 78
  • 111
  • Out of curiosity, why? This seems like something you would do so rarely, why create a program for it? – Kaizen Programmer Jan 02 '14 at 22:01
  • I have a bit of a specific set of requirements which actually will be repeated often, but to simplify using an abstract example, say I have 20 different developers all working for me--I would like them to fill out a simple winform with basic project info and then have the solution generated automatically (consistently) with the correct layers, utility classes, save locations, publish settings, etc. It gets more complicated than that actually so just let me know off line if you want more detail. – Matt Cashatt Jan 02 '14 at 22:05
  • Possible duplicate of http://stackoverflow.com/questions/12119667/envdte-substitute-in-visual-studio-2012 – Xenolightning Jan 02 '14 at 22:05
  • @Xenolightning--thanks, I actually looked at that one earlier, but it doesn't provide a complete example for creating and saving the solution. – Matt Cashatt Jan 02 '14 at 22:07
  • @MatthewPatrickCashatt Ahh sorry you're after creating a solution. Both don't cover that. [This](http://msdn.microsoft.com/en-us/library/vstudio/envdte100.solution4.aspx) may help you. `Solution4.SaveAs` looks like the candidate for creating the solution file. – Xenolightning Jan 02 '14 at 22:08
  • @MatthewPatrickCashatt The COM type created is `DTE2` not `DTE`, see my answer below for the code that worked for me. Cheers. – Xenolightning Jan 02 '14 at 22:29

3 Answers3

11

This works for me (VS2012 Ultimate):

static void Main(string[] args)
{
    System.Type type = System.Type.GetTypeFromProgID("VisualStudio.DTE.11.0");
    Object obj = System.Activator.CreateInstance(type, true);
    EnvDTE.DTE dte = (EnvDTE.DTE)obj;
    dte.MainWindow.Visible = true; // optional if you want to See VS doing its thing

    // create a new solution
    dte.Solution.Create(@"C:\NewSolution\", "NewSolution");
    var solution = dte.Solution;

    // create a C# WinForms app
    solution.AddFromTemplate(@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ProjectTemplatesCache\CSharp\Windows\1033\WindowsApplication\csWindowsApplication.vstemplate",
        @"C:\NewSolution\WinFormsApp", "WinFormsApp");

    // create a C# class library
    solution.AddFromTemplate(@"C:\Program Files (x86)\Microsoft Visual Studio 11.0\Common7\IDE\ProjectTemplatesCache\CSharp\Windows\1033\ClassLibrary\csClassLibrary.vstemplate",
        @"C:\NewSolution\ClassLibrary", "ClassLibrary");

    // save and quit
    dte.ExecuteCommand("File.SaveAll");
    dte.Quit();
}

[Edit:] Looking under HKCR, it looks like there's a VisualStudio.DTE (without the .11.0) that will point to the latest version of VS. So on my machine with VS2012 and VS2013, it will use the latter.

Jimmy
  • 27,142
  • 5
  • 87
  • 100
2

Tested and working using .NET4 Winforms, and a reference to EnvDTE100.dll (which should also add references to EnvDTE90.dll, EnvDTE80.dll, and EnvDTE.dll)

Type type = Type.GetTypeFromProgID("VisualStudio.DTE.11.0");
Object obj = System.Activator.CreateInstance(type, true);
EnvDTE80.DTE2 dte = (EnvDTE80.DTE2)obj;
EnvDTE100.Solution4 _solution = (EnvDTE100.Solution4)dte.Solution;
_solution.Create(@"C:\Test\", "Test");
_solution.SaveAs(@"C:\Test\Test.sln");
Xenolightning
  • 4,140
  • 1
  • 26
  • 34
1

Both solutions below by Jimmy and Xenolightining work, however, I still had the problem of the aforementioned error. So, in case anyone else encounters that error, see this link:

http://msdn.microsoft.com/en-us/library/ms228772(v=vs.80).aspx

To summarize the link above (or in case it is ever broken), here is what you do. Add this class to your solution:

 public class MessageFilter : IOleMessageFilter
    {
        //
        // Class containing the IOleMessageFilter
        // thread error-handling functions.

        // Start the filter.
        public static void Register()
        {
            IOleMessageFilter newFilter = new MessageFilter(); 
            IOleMessageFilter oldFilter = null; 
            CoRegisterMessageFilter(newFilter, out oldFilter);
        }

        // Done with the filter, close it.
        public static void Revoke()
        {
            IOleMessageFilter oldFilter = null; 
            CoRegisterMessageFilter(null, out oldFilter);
        }

        //
        // IOleMessageFilter functions.
        // Handle incoming thread requests.
        int IOleMessageFilter.HandleInComingCall(int dwCallType, 
          System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr 
          lpInterfaceInfo) 
        {
            //Return the flag SERVERCALL_ISHANDLED.
            return 0;
        }

        // Thread call was rejected, so try again.
        int IOleMessageFilter.RetryRejectedCall(System.IntPtr 
          hTaskCallee, int dwTickCount, int dwRejectType)
        {
            if (dwRejectType == 2)
            // flag = SERVERCALL_RETRYLATER.
            {
                // Retry the thread call immediately if return >=0 & 
                // <100.
                return 99;
            }
            // Too busy; cancel call.
            return -1;
        }

        int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee, 
          int dwTickCount, int dwPendingType)
        {
            //Return the flag PENDINGMSG_WAITDEFPROCESS.
            return 2; 
        }

        // Implement the IOleMessageFilter interface.
        [DllImport("Ole32.dll")]
        private static extern int 
          CoRegisterMessageFilter(IOleMessageFilter newFilter, out 
          IOleMessageFilter oldFilter);
    }

    [ComImport(), Guid("00000016-0000-0000-C000-000000000046"), 
    InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
    interface IOleMessageFilter 
    {
        [PreserveSig]
        int HandleInComingCall( 
            int dwCallType, 
            IntPtr hTaskCaller, 
            int dwTickCount, 
            IntPtr lpInterfaceInfo);

        [PreserveSig]
        int RetryRejectedCall( 
            IntPtr hTaskCallee, 
            int dwTickCount,
            int dwRejectType);

        [PreserveSig]
        int MessagePending( 
            IntPtr hTaskCallee, 
            int dwTickCount,
            int dwPendingType);
    }

Now wrap the code-generation code (from answers below) with these statements:

MessageFilter.Register();
//INSERT YOUR CODE HERE
MessageFilter.Revoke();
gunr2171
  • 16,104
  • 25
  • 61
  • 88