C# 如何从外部64位进程自动化Visual Studio?
我想从一个外部C#程序自动化Visual Studio。如前所述,我获取给定processId的DTE对象。然后我从DTE对象中获取一个ServiceProvider和IVsActivityLog,如前所述 作为C# 如何从外部64位进程自动化Visual Studio?,c#,visual-studio,automation,64-bit,C#,Visual Studio,Automation,64 Bit,我想从一个外部C#程序自动化Visual Studio。如前所述,我获取给定processId的DTE对象。然后我从DTE对象中获取一个ServiceProvider和IVsActivityLog,如前所述 作为x86,所有这些都可以正常工作,但一旦我构建为x64(对于任何CPU,当且仅当它作为32位进程的一部分运行时,它才能工作)。在状态栏中设置文本是可行的,但我在转换为IVsActivityLog时遇到一个异常: Unhandled Exception: System.InvalidCast
x86
,所有这些都可以正常工作,但一旦我构建为x64
(对于任何CPU
,当且仅当它作为32位进程的一部分运行时,它才能工作)。在状态栏中设置文本是可行的,但我在转换为IVsActivityLog
时遇到一个异常:
Unhandled Exception: System.InvalidCastException: Unable to cast COM object of type 'System.__ComObject' to interface type 'Microsoft.VisualStudio.Shell.Interop.IVsActivityLog'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{76AF73F9-A322-42B0-A515-D4D7553508FE}' failed due to the following error: Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).
这是一个简化的例子:
static void Main(string[] args)
{
int processID = 42; // well... replace by the correct PID
_DTE dte = GetDTE(processID);
dte.StatusBar.Text = $"Hello World!";
var serviceProvider = new ServiceProvider((Microsoft.VisualStudio.OLE.Interop.IServiceProvider)dte.DTE);
var log = (IVsActivityLog)serviceProvider.GetService(typeof(SVsActivityLog));
log.LogEntry((uint)__ACTIVITYLOG_ENTRYTYPE.ALE_WARNING, typeof(Program).ToString(), "Test");
}
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
public static _DTE GetDTE(int processId)
{
IntPtr numFetched = IntPtr.Zero;
IRunningObjectTable runningObjectTable;
IEnumMoniker monikerEnumerator;
IMoniker[] monikers = new IMoniker[1];
GetRunningObjectTable(0, out runningObjectTable);
runningObjectTable.EnumRunning(out monikerEnumerator);
monikerEnumerator.Reset();
while (monikerEnumerator.Next(1, monikers, numFetched) == 0)
{
IBindCtx ctx;
CreateBindCtx(0, out ctx);
string runningObjectName;
monikers[0].GetDisplayName(ctx, null, out runningObjectName);
object runningObjectVal;
runningObjectTable.GetObject(monikers[0], out runningObjectVal);
if (runningObjectVal is _DTE && runningObjectName.StartsWith("!VisualStudio"))
{
int currentProcessId = int.Parse(runningObjectName.Split(':')[1]);
if (currentProcessId == processId)
{
return (_DTE)runningObjectVal;
}
}
}
return null;
}
有人有想法吗?从技术上讲,这是可能的。实际上并非如此,VS安装程序会写入大量注册表项。它们只对32位进程可见。嗯:-/谢谢,这是可能的。实际上并非如此,VS安装程序会写入大量注册表项。它们只对32位进程可见。嗯:-/谢谢,汉斯