我使用以下代码成功实例化/自动化Visual Studio:
System.Type t = System.Type.GetTypeFromProgID("VisualStudio.DTE.9.0");
object obj = Activator.CreateInstance(t, true);
dte = (DTE)obj;
Solution sln = dte.Solution;
sln.Open(SolutionFile);
System.Threading.Thread.Sleep(1000);
//Do stuff with the solution
注意Thread.Sleep(1000)
来电?如果我不包含它,代码会在它准备好之前尝试对实例进行错误处理,并且我得到一个异常:
the message filter indicated that the application is busy.
有没有办法轮询这个对象的准备情况呢?
而不是等待n秒答案 0 :(得分:32)
作为此问题的解决方案,您可以注册一个事件,通知解决方案加载何时完成。
这是一个类的示例,可让您在解决方案加载时收听事件:
public class SolutionEventsListener : IVsSolutionEvents, IDisposable
{
private IVsSolution solution;
private uint solutionEventsCookie;
public event Action AfterSolutionLoaded;
public event Action BeforeSolutionClosed;
public SolutionEventsListener(IServiceProvider serviceProvider)
{
InitNullEvents();
solution = serviceProvider.GetService(typeof (SVsSolution)) as IVsSolution;
if (solution != null)
{
solution.AdviseSolutionEvents(this, out solutionEventsCookie);
}
}
private void InitNullEvents()
{
AfterSolutionLoaded += () => { };
BeforeSolutionClosed += () => { };
}
#region IVsSolutionEvents Members
int IVsSolutionEvents.OnAfterCloseSolution(object pUnkReserved)
{
return VSConstants.S_OK;
}
int IVsSolutionEvents.OnAfterLoadProject(IVsHierarchy pStubHierarchy, IVsHierarchy pRealHierarchy)
{
return VSConstants.S_OK;
}
int IVsSolutionEvents.OnAfterOpenProject(IVsHierarchy pHierarchy, int fAdded)
{
return VSConstants.S_OK;
}
int IVsSolutionEvents.OnAfterOpenSolution(object pUnkReserved, int fNewSolution)
{
AfterSolutionLoaded();
return VSConstants.S_OK;
}
int IVsSolutionEvents.OnBeforeCloseProject(IVsHierarchy pHierarchy, int fRemoved)
{
return VSConstants.S_OK;
}
int IVsSolutionEvents.OnBeforeCloseSolution(object pUnkReserved)
{
BeforeSolutionClosed();
return VSConstants.S_OK;
}
int IVsSolutionEvents.OnBeforeUnloadProject(IVsHierarchy pRealHierarchy, IVsHierarchy pStubHierarchy)
{
return VSConstants.S_OK;
}
int IVsSolutionEvents.OnQueryCloseProject(IVsHierarchy pHierarchy, int fRemoving, ref int pfCancel)
{
return VSConstants.S_OK;
}
int IVsSolutionEvents.OnQueryCloseSolution(object pUnkReserved, ref int pfCancel)
{
return VSConstants.S_OK;
}
int IVsSolutionEvents.OnQueryUnloadProject(IVsHierarchy pRealHierarchy, ref int pfCancel)
{
return VSConstants.S_OK;
}
#endregion
#region IDisposable Members
public void Dispose()
{
if (solution != null && solutionEventsCookie != 0)
{
GC.SuppressFinalize(this);
solution.UnadviseSolutionEvents(solutionEventsCookie);
AfterSolutionLoaded = null;
BeforeSolutionClosed = null;
solutionEventsCookie = 0;
solution = null;
}
}
#endregion
}
用法示例:
DTE2 applicationObject = dte;
var serviceProvider = new ServiceProvider(applicationObject as IServiceProvider);
solutionEventsListener = new SolutionEventsListener(serviceProvider);
solutionEventsListener.AfterSolutionLoaded += () => /* logic here */ ;
答案 1 :(得分:7)
虽然这里的解决方案具有创造性,但它们要么不能完全解决问题,要么使用起来非常麻烦。你应该register a message filter as Microsoft recommends。
为方便起见,此处复制了代码(将VisualStudio.DTE.10.0
替换为您要打开的任何VS版本),只需注意使用Main
属性修饰STAThread
方法,消息过滤获胜'如果没有它,它将在原始MSDN解决方案中跳过。
using System;
using System.Collections.Generic;
using System.Text;
using EnvDTE;
using EnvDTE80;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace ConsoleApplication2
{
class Program
{
[STAThread]
static void Main(string[] args)
{
EnvDTE80.DTE2 dte;
object obj = null;
System.Type t = null;
// Get the ProgID for DTE 8.0.
t = System.Type.GetTypeFromProgID("VisualStudio.DTE.10.0",
true);
// Create a new instance of the IDE.
obj = System.Activator.CreateInstance(t, true);
// Cast the instance to DTE2 and assign to variable dte.
dte = (EnvDTE80.DTE2)obj;
// Register the IOleMessageFilter to handle any threading
// errors.
MessageFilter.Register();
// Display the Visual Studio IDE.
dte.MainWindow.Activate();
// =====================================
// ==Insert your automation code here.==
// =====================================
// For example, get a reference to the solution2 object
// and do what you like with it.
Solution2 soln = (Solution2)dte.Solution;
System.Windows.Forms.MessageBox.Show
("Solution count: " + soln.Count);
// =====================================
// All done, so shut down the IDE...
dte.Quit();
// and turn off the IOleMessageFilter.
MessageFilter.Revoke();
}
}
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;
int hr = CoRegisterMessageFilter(newFilter, out oldFilter);
if (hr != 0)
Marshal.ThrowExceptionForHR(hr);
}
// 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);
}
}
答案 2 :(得分:0)
我对IVSSolutionEvents技术没有太多运气(虽然我没有像上面那样完全尝试代码)。相反,我创建了一个小函数来帮助我重试调用。我知道这不是特别漂亮,但是打电话很简单,而且很有效!
以下是我对另一个类似问题的答案的链接:https://stackoverflow.com/a/8565990/1106459
(在调用其他EnvDTE函数以及打开和关闭解决方案时,它还有助于“服务器忙”错误。)