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:
| DWORD ProcessId = GetProcessId("foobar.exe");
AttachToVS(ProcessId);
|
Pretty ugly but I hope this crap code can help someone.