Sample Code to programmatically attach Visual Studio to a process

Hi folks, a while ago I was playing around with DLL injection and needed a way to programmatically attach Visual Studio to a process. The following code is the solution I came up with. NOTE: annoyingly you will need to change the ProgID variable to match your version of Visual Studio. Here is a table of corresponding versions and ProgIDs


Visual Studio .NET 2002 ======== VisualStudio.DTE.7
Visual Studio .NET 2003 ======== VisualStudio.DTE.7.1
Visual Studio 2005 ============ VisualStudio.DTE.8.0
Visual Studio 2008 ============ VisualStudio.DTE.9.0
Visual Studio 2010 ============ VisualStudio.DTE.10.0
Visual Studio 2012 ============ VisualStudio.DTE.11.0
Visual Studio 2013 ============ VisualStudio.DTE.12.0
Visual Studio 2015 ============ VisualStudio.DTE.14.0

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
#include <tlhelp32.h>
#include <atlbase.h>
#import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("8.0") lcid("0") raw_interfaces_only named_guids

DWORD
GetProcessId(char ExeName[])
{    
    DWORD Result = 0;
    
    HANDLE Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    
    PROCESSENTRY32 Entry = {};
    Entry.dwSize = sizeof(PROCESSENTRY32);
    
    if(Process32First(Snapshot, &Entry) == TRUE)
    {
        do 
        {
            if(stricmp(Entry.szExeFile, ExeName) == 0)
            {
                Result = Entry.th32ProcessID;
                break;
            }
        } while(Process32Next(Snapshot, &Entry) == TRUE);
    }
    CloseHandle(Snapshot);
    
    return(Result);
}


EnvDTE::Process * 
FindVSProcess(DWORD TargetPID)
{
    CoInitialize(0);
    
    HRESULT hr;
    
    static wchar_t *ProgID = L"VisualStudio.DTE";
    
    CLSID Clsid;
    CLSIDFromProgID(ProgID, &Clsid);
        
    IUnknown *Unknown;
    hr = GetActiveObject(Clsid, 0, &Unknown);
    Assert(SUCCEEDED(hr));
    
    EnvDTE::_DTE *Interface;
    hr = Unknown->QueryInterface(&Interface);
    Assert(SUCCEEDED(hr));

    
    EnvDTE::Debugger *Debugger;
    hr = Interface->get_Debugger(&Debugger);
    Assert(SUCCEEDED(hr));
    
    EnvDTE::Processes *Processes;
    hr = Debugger->get_LocalProcesses(&Processes);
    Assert(SUCCEEDED(hr));

    long Count = 0;
    hr = Processes->get_Count(&Count);
    Assert(SUCCEEDED(hr));

    EnvDTE::Process *Result = 0;
    
    for(int i = 0; i < Count; i++)
    {
        EnvDTE::Process *Process;
        hr = Processes->Item(variant_t(i), &Process);
        if(FAILED(hr)) 
            continue;
        
        long ProcessID;
        hr = Process->get_ProcessID(&ProcessID);
        Assert(SUCCEEDED(hr));

        if(ProcessID == TargetPID)
        {
            Result = Process;

            break;
        }
    }
    
    return(Result);
}


void AttachToVS(DWORD TargetPID)
{
    EnvDTE::Process *Process = FindVSProcess(TargetPID);
    
    if(Process)
    {
        Process->Attach();
    }
    CoUninitialize();
}

void DetachToVS(DWORD TargetPID)
{
    EnvDTE::Process *Process = FindVSProcess(TargetPID);
    
    if(Process)
    {
        VARIANT_BOOL Bool = variant_t(false);
        
        HRESULT hr = Process->Detach(Bool);
    }
    CoUninitialize();
}


Usage:
1
2
DWORD ProcessId = GetProcessId("foobar.exe");
AttachToVS(ProcessId);   


Pretty ugly but I hope this crap code can help someone.

Edited by jimmyjimbo on
I am using just "VisualStudio.DTE": https://git.handmade.network/mmoz.../master/CxxProfiler/Utils.cpp#L89
Afaik it opens whatever studio you have installed.
Oh that's good! I just tested with VS 2013 and it works for that version so I changed the example code above :-). Also, windows COM stuff is a bloody nightmare :-(.

Edited by jimmyjimbo on