C# 可视化工具:类型为';的未处理异常;System.CannotUnloadAppDomainException';发生在mscorlib.dll中
我正试图按照以下指南为Visual Studio 2015编写Visual Studio可视化工具: 但是我想使用WPF而不是WinForms 对于可视化工具,我有以下代码:C# 可视化工具:类型为';的未处理异常;System.CannotUnloadAppDomainException';发生在mscorlib.dll中,c#,wpf,visual-studio-2015,C#,Wpf,Visual Studio 2015,我正试图按照以下指南为Visual Studio 2015编写Visual Studio可视化工具: 但是我想使用WPF而不是WinForms 对于可视化工具,我有以下代码: using Microsoft.VisualStudio.DebuggerVisualizers; [assembly: System.Diagnostics.DebuggerVisualizer(typeof(Visualizer.DebuggerSide), typeof(VisualizerObjectSource
using Microsoft.VisualStudio.DebuggerVisualizers;
[assembly: System.Diagnostics.DebuggerVisualizer(typeof(Visualizer.DebuggerSide), typeof(VisualizerObjectSource),
Target = typeof(string), Description = "Visualizer")]
namespace Visualizer
{
public class DebuggerSide : DialogDebuggerVisualizer
{
protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
{
var window = new MainWindow();
window.ShowDialog();
}
public static void TestShowVisualizer(object thingToVisualize)
{
var visualizerHost = new VisualizerDevelopmentHost(thingToVisualize, typeof(DebuggerSide));
visualizerHost.ShowVisualizer();
}
}
}
然后我从控制台应用程序调用它进行如下测试:
namespace Visualizer.Debug
{
using System;
class Program
{
[STAThread]
static void Main(string[] args)
{
var data = "test";
DebuggerSide.TestShowVisualizer(data);
}
}
}
代码运行良好,窗口在window.ShowDialog
点启动。关闭窗口后,代码从Show
返回,并在visualizerHost.ShowVisualizer()处抛出异常代码>
例外情况是:
System.CannotUnloadAppDomainException未处理
HResult=-21462347 Message=卸载appdomain时出错。
(来自HRESULT:0x801315的异常)源=mscorlib StackTrace:
位于System.AppDomain.Unload(AppDomain域)
位于Microsoft.VisualStudio.DebuggerVisualizers.DebugViewersIM.ManagedShim.Microsoft.VisualStudio.DebuggerVisualizers.DebugViewersIM.IManagedViewerHost.CreateViewer(IntPtr
hwnd,对象主机服务SPARAM,IPropertyProxyesIDE代理)
在Microsoft.VisualStudio.DebuggerVisualizers.VisualizerDevelopmentHost.EEProxyImpl.ShowVisualizer(IntPtr
父窗口)
在Microsoft.VisualStudio.DebuggerVisualizers.VisualizerDevelopmentHost.ShowVisualizer()上
在C:\git\Visualizer\Visualizer\Class1.cs中的Visualizer.DebuggerSide.TestShowVisualizer(对象ThingToVisualizer)中:第20行
在C:\git\Visualizer\Visualizer.Debug\Program.cs中的Visualizer.Debug.Program.Main(字符串[]args)处:第10行
位于System.AppDomain.\u nExecuteAssembly(RuntimeAssembly程序集,字符串[]args)
位于System.AppDomain.ExecuteAssembly(字符串汇编文件、证据汇编安全性、字符串[]args)
在Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()上
位于System.Threading.ThreadHelper.ThreadStart\u上下文(对象状态)
位于System.Threading.ExecutionContext.RunInternal(ExecutionContext
executionContext、ContextCallback回调、对象状态、布尔值
(同步CTX)
在System.Threading.ExecutionContext.Run(ExecutionContext ExecutionContext,ContextCallback回调,对象状态,布尔值
(同步CTX)
在System.Threading.ExecutionContext.Run(ExecutionContext ExecutionContext,ContextCallback回调,对象状态)
位于System.Threading.ThreadHelper.ThreadStart()的内部异常:
考虑到错误可能是由于WPF代码试图返回Visual Studio代码,我尝试在一个完全独立的AppDomain中启动WPF窗口,但当我尝试卸载该AppDomain时,我得到了相同的错误
主窗口的代码:
namespace Visualizer
{
using System.Windows;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
嗯,那真是令人讨厌
我在一台支持触摸屏的计算机上,因此WPF为手写笔输入注册。当WPF窗口自行卸载并且AppDomain
尝试卸载时,手写笔输入线程将继续运行并阻止AppDomain卸载。()
我最初尝试使用一个单独的AppDomain来解决这个问题,并确保在关闭主窗口时调用了Dispatcher.InvokeShutdown()
,正如链接文章中建议的那样。在我的可视化工具中,Show
方法变成:
protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
{
var domain = AppDomain.CreateDomain("My Friendly Domain");
CrossAppDomainDelegate action = () =>
{
var window = new MainWindow();
window.ShowDialog();
};
domain.DoCallBack(action);
AppDomain.Unload(domain);
}
主窗口有以下代码:
public MainWindow()
{
InitializeComponent();
}
protected override void OnClosing(CancelEventArgs e)
{
// Without this AppDomain unloading will fail and hate you forever...
Dispatcher.InvokeShutdown();
base.OnClosing(e);
}
这适用于从控制台应用程序进行调试,但是VisualStudio似乎不允许您在Visualizers中调用CrossAppDomainDelegates
,并且我得到了某种形式的序列化异常
答复
显而易见的下一步,因为我根本不在乎手写笔的支持是完全删除它。此处给出了这方面的代码-
这使得可视化工具中的代码
:
using Microsoft.VisualStudio.DebuggerVisualizers;
[assembly: System.Diagnostics.DebuggerVisualizer(
typeof(Visualizer.DebuggerSide),
typeof(VisualizerObjectSource),
Target = typeof(string),
Description = "Visualizer")]
namespace Visualizer
{
public class DebuggerSide : DialogDebuggerVisualizer
{
protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
{
var window = new MainWindow();
window.ShowDialog();
}
public static void TestShowVisualizer(object thingToVisualize)
{
var visualizerHost = new VisualizerDevelopmentHost(thingToVisualize, typeof(DebuggerSide));
visualizerHost.ShowVisualizer();
}
}
}
和主窗口
:
namespace Visualizer
{
using System.ComponentModel;
using System.Reflection;
using System.Windows;
using System.Windows.Input;
public partial class MainWindow : Window
{
public MainWindow()
{
DisableWPFTabletSupport();
InitializeComponent();
}
public static void DisableWPFTabletSupport()
{
// Get a collection of the tablet devices for this window.
var devices = Tablet.TabletDevices;
if (devices.Count == 0)
{
return;
}
var inputManagerType = typeof(InputManager);
var stylusLogic = inputManagerType.InvokeMember("StylusLogic",
BindingFlags.GetProperty | BindingFlags.Instance | BindingFlags.NonPublic,
null, InputManager.Current, null);
if (stylusLogic == null)
{
return;
}
var stylusLogicType = stylusLogic.GetType();
while (devices.Count > 0)
{
// Remove the first tablet device in the devices collection.
stylusLogicType.InvokeMember("OnTabletRemoved",
BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.NonPublic,
null, stylusLogic, new object[] { (uint)0 });
}
}
}
}
更简单的答案
事实证明,这两个步骤都有些过分,实际上我只需要在OnClosing
事件处理程序中保留对Dispatcher.InvokeShutdown()的调用,并正常调用主窗口:
protected override void Show(IDialogVisualizerService windowService, IVisualizerObjectProvider objectProvider)
{
var window = new MainWindow();
window.ShowDialog();
}
和主窗口:
protected override void OnClosing(CancelEventArgs e)
{
Dispatcher.InvokeShutdown();
base.OnClosing(e);
}