views:

1142

answers:

4

I can start a new hidden Visual Studio process from VBScript, and drive it programmatically, by doing this:

Set DTE = CreateObject("VisualStudio.DTE.8.0")
DTE.DoStuff()

How do I do that in C#? (Edit: using the correct types, not generic COM objects as used by that VBScript code.)

I've tried this:

using EnvDTE;
...
DTE dte = new DTE();

but I get "Retrieving the COM class factory for component with CLSID {3C9CFE1E-389F-4118-9FAD-365385190329} failed".

A: 

Simple answer: write it in VB, compile it, open it with Reflector, and decompile it in c# mode!

Chris
Nice idea, but the VB code is using late binding (ie. `DTE` is just a generic COM object) and I want the C# to use early binding.
RichieHindle
Instead of using Reflector, why not just view the source provided by Microsoft?
AMissico
+3  A: 

I don't know how start a new instance of Visual Studio, but I use an existing instance by calling:

EnvDTE.DTE dte = (EnvDTE.DTE)System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.8.0");

Maybe creating a new instance is something similar? Hope this helps a bit.

Regards,

Sebastiaan

Sebastiaan Megens
+1 for putting me on the right track - Googling for your code led me to http://msdn.microsoft.com/en-us/library/68shb4dw%28VS.80%29.aspx which contains both your code for connecting to an existing instance *and* code for creating a new one.
RichieHindle
+1  A: 

I found the answer (thanks to Sebastiaan Megens for putting me on the right track):

[STAThread]
static void Main(string[] args)
{
    System.Type t = System.Type.GetTypeFromProgID("VisualStudio.DTE.8.0", true);
    DTE2 dte = (EnvDTE80.DTE2)System.Activator.CreateInstance(t, true);

    // See http://msdn.microsoft.com/en-us/library/ms228772.aspx for the
    // code for MessageFilter - just paste it in.
    MessageFilter.Register();

    dte.DoStuff();
    dte.Quit();
}

public class MessageFilter : IOleMessageFilter
{
   ... Continues at http://msdn.microsoft.com/en-us/library/ms228772.aspx

(The nonsense with STAThread and MessageFilter is "due to threading contention issues between external multi-threaded applications and Visual Studio", whatever that means. Pasting in the code from http://msdn.microsoft.com/en-us/library/ms228772.aspx makes it work.)

RichieHindle
Ah, cool to hear! Interesting to see, I'll probably need it myself sometime in the future. :)Regards,Sebastiaan
Sebastiaan Megens
A: 

Micrisoft souce code for VB's CreateObject.

    <HostProtection(Resources:=HostProtectionResource.ExternalProcessMgmt)> _ 
    <SecurityPermissionAttribute(SecurityAction.Demand, Flags:=SecurityPermissionFlag.UnmanagedCode)> _
    Public Function CreateObject(ByVal ProgId As String, Optional ByVal ServerName As String = "") As Object
        'Creates local or remote COM2 objects.  Should not be used to create COM+ objects.
        'Applications that need to be STA should set STA either on their Sub Main via STAThreadAttribute 
        'or through Thread.CurrentThread.ApartmentState - the VB runtime will not change this.
        'DO NOT SET THREAD STATE - Thread.CurrentThread.ApartmentState = ApartmentState.STA 

        Dim t As Type

        If ProgId.Length = 0 Then
            Throw VbMakeException(vbErrors.CantCreateObject)
        End If

        If ServerName Is Nothing OrElse ServerName.Length = 0 Then
            ServerName = Nothing 
        Else 
            'Does the ServerName match the MachineName?
            If String.Compare(Environment.MachineName, ServerName, StringComparison.OrdinalIgnoreCase) = 0 Then 
                ServerName = Nothing
            End If
        End If

        Try
            If ServerName Is Nothing Then 
                t = Type.GetTypeFromProgID(ProgId) 
            Else
                t = Type.GetTypeFromProgID(ProgId, ServerName, True) 
            End If

            Return System.Activator.CreateInstance(t)
        Catch e As COMException 
            If e.ErrorCode = &H800706BA Then                    '&H800706BA = The RPC Server is unavailable
                Throw VbMakeException(vbErrors.ServerNotFound) 
            Else 
                Throw VbMakeException(vbErrors.CantCreateObject)
            End If 
        Catch ex As StackOverflowException
            Throw ex
        Catch ex As OutOfMemoryException
            Throw ex 
        Catch ex As System.Threading.ThreadAbortException
            Throw ex 
        Catch e As Exception 
            Throw VbMakeException(vbErrors.CantCreateObject)
        End Try 
    End Function
AMissico