这个问题由来已久,却一直没有找到原因。大家都知道,VisualStudio的DebuggerVisualizers是一个非常方便的插件,可以帮助我们调试时查看Datatable视图,前阵子突然发现在查看时报错了,截图 如下:
详细信息里的内容是:
1 有关调用实时(JIT)调试而不是此对话框的详细信息, 2 请参见此消息的结尾。 3 4 ************** 异常文本 ************** 5 System.Exception: 函数计算超时。 6 在 Microsoft.VisualStudio.DebuggerVisualizers.DebugViewerShim.PrivateCallback.MaybeDeserializeAndThrowException(Byte[] data) 7 在 Microsoft.VisualStudio.DebuggerVisualizers.DebugViewerShim.ManagedShim.DelegatedHost.CreateViewer(IntPtr hwnd, HostServicesHelper hsh, SafeProxyWrapper proxy) 8 9 10 ************** 已加载的程序集 ************** 11 mscorlib 12 程序集版本:4.0.0.0 13 Win32 版本:4.0.30319.18444 built by: FX451RTMGDR 14 基本代码:file:///C:/Windows/Microsoft.NET/Framework/v4.0.30319/mscorlib.dll 15 ---------------------------------------- 16 Microsoft.VisualStudio.Platform.AppDomainManager 17 程序集版本:12.0.0.0 18 Win32 版本:12.0.21005.1 19 基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/Microsoft.VisualStudio.Platform.AppDomainManager/v4.0_12.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualStudio.Platform.AppDomainManager.dll 20 ---------------------------------------- 21 System 22 程序集版本:4.0.0.0 23 Win32 版本:4.0.30319.18408 built by: FX451RTMGREL 24 基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System/v4.0_4.0.0.0__b77a5c561934e089/System.dll 25 ---------------------------------------- 26 System.Configuration 27 程序集版本:4.0.0.0 28 Win32 版本:4.0.30319.18408 built by: FX451RTMGREL 29 基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Configuration/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll 30 ---------------------------------------- 31 System.Xml 32 程序集版本:4.0.0.0 33 Win32 版本:4.0.30319.34234 built by: FX452RTMGDR 34 基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Xml/v4.0_4.0.0.0__b77a5c561934e089/System.Xml.dll 35 ---------------------------------------- 36 System.Windows.Forms 37 程序集版本:4.0.0.0 38 Win32 版本:4.0.30319.18408 built by: FX451RTMGREL 39 基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll 40 ---------------------------------------- 41 System.Drawing 42 程序集版本:4.0.0.0 43 Win32 版本:4.0.30319.18408 built by: FX451RTMGREL 44 基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Drawing/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll 45 ---------------------------------------- 46 Microsoft.VisualStudio.DebuggerVisualizers 47 程序集版本:12.0.0.0 48 Win32 版本:12.0.21005.1 49 基本代码:file:///C:/Windows/assembly/GAC_MSIL/Microsoft.VisualStudio.DebuggerVisualizers/12.0.0.0__b03f5f7f11d50a3a/Microsoft.VisualStudio.DebuggerVisualizers.dll 50 ---------------------------------------- 51 System.Windows.Forms.resources 52 程序集版本:4.0.0.0 53 Win32 版本:4.0.30319.18408 built by: FX451RTMGREL 54 基本代码:file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms.resources/v4.0_4.0.0.0_zh-Hans_b77a5c561934e089/System.Windows.Forms.resources.dll 55 ---------------------------------------- 56 57 ************** JIT 调试 ************** 58 要启用实时(JIT)调试, 59 该应用程序或计算机的 .config 文件(machine.config)的 system.windows.forms 节中必须设置 60 jitDebugging 值。 61 编译应用程序时还必须启用 62 调试。 63 64 例如: 65 66 <configuration> 67 <system.windows.forms jitDebugging="true" /> 68 </configuration> 69 70 启用 JIT 调试后,任何未经处理的异常 71 都将被发送到在此计算机上注册的 JIT 调试器, 72 而不是由此对话框处理。
从这个错误内容来看,最后抛出的是行6和行7,这是IDE绘制查看器弹窗时抛出的异常,我找了下这个dll,还真找到了,具体位置在
Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.VisualStudio.DebuggerVisualizers.dll
当然,VS真正调的应该不是这个位置,从错误行49可以看出(实际上把这个位置的DebuggerVisualizers.dll删除照样可以使用),是调的Windows下面的某个位置,这可能是写到注册表里或者环境变量里了,反正是这个dll不错,但是vs使用的位置我没法查到。用Reflector反编译之,行7的CreateViewer源码如下:
1 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine), ResourceExposure(ResourceScope.None)] 2 internal void CreateViewer(IntPtr hwnd, ManagedShim.HostServicesHelper hsh, ManagedShim.SafeProxyWrapper proxy) 3 { 4 try 5 { 6 byte[] data = proxy.InitSourceDataProvider(); 7 using (AssemblyResolver resolver = new HostResolver(proxy, hsh.IsRemote, new ServiceProvider.WindowWrapper(hwnd))) 8 { 9 string str; 10 string str2; 11 int num; 12 ASSEMBLYLOCRESOLUTION assemblylocresolution; 13 byte[] buffer; 14 byte[] buffer2; 15 PrivateCallback.MaybeDeserializeAndThrowException(data); 16 proxy.GetManagedViewerCreationData(out str, out buffer, out buffer2, out str2, out assemblylocresolution, out num); 17 if ((assemblylocresolution == ASSEMBLYLOCRESOLUTION.ALR_ERROR) && (str != null)) 18 { 19 throw new TerminalException(str, MessageBoxIcon.Hand); 20 } 21 if (((buffer != null) && (str == null)) && (hsh.IsRemote && !QueryRemoteLoadAllowed(null, new ServiceProvider.WindowWrapper(hwnd)))) 22 { 23 throw new TerminalException(MessageBoxIcon.Hand); 24 } 25 ClassAndAssemblySpec spec = new ClassAndAssemblySpec(str, buffer, assemblylocresolution != ASSEMBLYLOCRESOLUTION.ALR_NAME, str2); 26 DialogDebuggerVisualizer visualizer = (DialogDebuggerVisualizer) spec.CreateInstance(resolver); 27 using (PrivateCallback callback = new PrivateCallback(proxy, num != 0)) 28 { 29 visualizer.Show(new ServiceProvider(hwnd, hsh).DialogService, callback); 30 } 31 } 32 } 33 catch (TerminalException exception) 34 { 35 exception.DisplayDialog(new ServiceProvider.WindowWrapper(hwnd)); 36 } 37 catch (Exception exception2) 38 { 39 new ThreadExceptionDialog(exception2).ShowDialog(new ServiceProvider.WindowWrapper(hwnd)); 40 } 41 }
从上面可以看出,走到行15就执行了异常处理,然后由PrivateCallback的MaybeDeserializeAndThrowException方法接管过来,MaybeDeserializeAndThrowException源码如下:
1 internal static unsafe byte[] MaybeDeserializeAndThrowException(byte[] data) 2 { 3 if ((data == null) || (data.Length == 0)) 4 { 5 return null; 6 } 7 DebugeeHost.DataPrefix prefix = (DebugeeHost.DataPrefix) data[0]; 8 switch (prefix) 9 { 10 case DebugeeHost.DataPrefix.Exception: 11 { 12 Exception exception = (Exception) DeserializeObject(data, 1); 13 throw exception; 14 } 15 case DebugeeHost.DataPrefix.ObjectData: 16 return data; 17 18 case DebugeeHost.DataPrefix.CustomExceptionData: 19 { 20 DebugeeHost.CustomExceptionDataHolder cedh = (DebugeeHost.CustomExceptionDataHolder) DeserializeObject(data, 1); 21 throw new RemoteObjectSourceException(cedh); 22 } 23 case DebugeeHost.DataPrefix.ErrorString: 24 case DebugeeHost.DataPrefix.ErrorStringNoHost: 25 if (data.Length < 8) 26 { 27 throw new ApplicationException(SR.GetString("E_G_InvalidSerializationFormat")); 28 } 29 break; 30 31 default: 32 return data; 33 } 34 fixed (byte* numRef = data) 35 { 36 int length = numRef[4]; 37 if ((data.Length - 8) < (length * 2)) 38 { 39 throw new ApplicationException(SR.GetString("E_G_InvalidSerializationFormat")); 40 } 41 char* chPtr = (char*) (numRef + 8); 42 string message = new string(chPtr, 0, length); 43 if (prefix == DebugeeHost.DataPrefix.ErrorStringNoHost) 44 { 45 throw new TerminalException(message, MessageBoxIcon.Exclamation); 46 } 47 throw new Exception(message); 48 } 49 }
这里应该就是最后的“事发现场了”,其中case的枚举如下:
1 internal enum DataPrefix : byte 2 { 3 CustomExceptionData = 3, 4 ErrorString = 4, 5 ErrorStringNoHost = 5, 6 Exception = 1, 7 ObjectData = 2 8 }
到此好像没法追踪下去了,它是通过传入的byte[]的0位值来抛出相应的异常,只有值为2或者default的时候才不抛出,由于没法模拟环境,即使我给了传入byte[],那么里面的调用层次还是要经过一番考究的。为此我也考虑了其他因素:
-
系统
-
硬件
-
内存
-
杀毒软件
-
IDE本身
-
软件冲突
-
补丁
-
IDE配置
现在的现象是时好时坏,那么2、7就可以排除了,找了另外一台电脑,同样的系统同样的vs版本可以查看,那么1和5可以排除,内存用360释放一样有错,3可以排除,杀毒软件退掉依旧,4可以排除,6的话就麻烦了,难以查证,8的话也对比了正常的配置,没有差异,也可排除。
现在比较有效的办法有两个:
1、清理项目或者清理解决方案;
2、杀进程,在任务管理器里结束与vs项目相关的host进程(不包括devenv.exe),如果有MSBuildTaskHost也要结束,然后再启动新实例,一般都能正常查看。
交流群:
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。