Создание HwndSource напрямую
Я пытаюсь создать окно, создавая HwndSource
непосредственно. На данный момент у меня есть альтернативное решение - наследование от Window
класс, но мне просто интересно, что не так с моим HwndSource
реализация. поскольку Window
использования HwndSource
по сути, я чувствую, что должен быть способ.
Вот упрощенная версия моего кода:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
HwndSource wndPopup = new HwndSource(0, 0x12cf0000/*WS_VISIBLE|WS_OVERLAPPEDWINDOW*/, 0, 10, 10, 500, 500, "Test", IntPtr.Zero);
wndPopup.RootVisual = new Rectangle() { Fill = Brushes.Red, Width = 100, Height = 100 };
}
Окно создается, как и ожидалось, но после того, как я закрываю его (Alt+F4 или значок "Закрыть") и наводит указатель мыши на главное окно, множество сообщений выводится в отладчик:
Исключение: "System.ComponentModel.Win32Exception" в WindowsBase.dll
Детали исключения:
Exception thrown: 'System.ComponentModel.Win32Exception' in WindowsBase.dll
Additional information: Invalid window handle
Трассировки стека:
WindowsBase.dll!MS.Win32.UnsafeNativeMethods.GetWindowText(System.Runtime.InteropServices.HandleRef, System.Text.StringBuilder, int)
PresentationCore.dll!System.Windows.Automation.Peers.GenericRootAutomationPeer.GetNameCore()
PresentationCore.dll!System.Windows.Automation.Peers.AutomationPeer.UpdateSubtree()
PresentationCore.dll!System.Windows.ContextLayoutManager.fireAutomationEvents()
PresentationCore.dll!System.Windows.ContextLayoutManager.UpdateLayout()
PresentationCore.dll!System.Windows.ContextLayoutManager.UpdateLayoutCallback(object)
PresentationCore.dll!System.Windows.Media.MediaContext.InvokeOnRenderCallback.DoWork()
PresentationCore.dll!System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
PresentationCore.dll!System.Windows.Media.MediaContext.RenderMessageHandlerCore(object)
PresentationCore.dll!System.Windows.Media.MediaContext.RenderMessageHandler(object)
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, object, int)
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object, System.Delegate, object, int, System.Delegate)
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeImpl()
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.InvokeInSecurityContext(object)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, object, bool)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, object, bool)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, object)
WindowsBase.dll!System.Windows.Threading.DispatcherOperation.Invoke()
WindowsBase.dll!System.Windows.Threading.Dispatcher.ProcessQueue()
WindowsBase.dll!System.Windows.Threading.Dispatcher.WndProcHook(System.IntPtr, int, System.IntPtr, System.IntPtr, ref bool)
WindowsBase.dll!MS.Win32.HwndWrapper.WndProc(System.IntPtr, int, System.IntPtr, System.IntPtr, ref bool)
WindowsBase.dll!MS.Win32.HwndSubclass.DispatcherCallbackOperation(object)
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.InternalRealCall(System.Delegate, object, int)
WindowsBase.dll!System.Windows.Threading.ExceptionWrapper.TryCatchWhen(object, System.Delegate, object, int, System.Delegate)
WindowsBase.dll!System.Windows.Threading.Dispatcher.LegacyInvokeImpl(System.Windows.Threading.DispatcherPriority, System.TimeSpan, System.Delegate, object, int)
WindowsBase.dll!MS.Win32.HwndSubclass.SubclassWndProc(System.IntPtr, int, System.IntPtr, System.IntPtr)
[Native to Managed Transition]
[Managed to Native Transition]
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrameImpl(System.Windows.Threading.DispatcherFrame)
WindowsBase.dll!System.Windows.Threading.Dispatcher.PushFrame(System.Windows.Threading.DispatcherFrame)
PresentationFramework.dll!System.Windows.Application.RunDispatcher(object)
PresentationFramework.dll!System.Windows.Application.RunInternal(System.Windows.Window)
PresentationFramework.dll!System.Windows.Application.Run(System.Windows.Window)
PresentationFramework.dll!System.Windows.Application.Run()
WpfCombox.exe!WpfCombox.App.Main()
[Native to Managed Transition]
[Managed to Native Transition]
mscorlib.dll!System.AppDomain.ExecuteAssembly(string, System.Security.Policy.Evidence, string[])
Microsoft.VisualStudio.HostingProcess.Utilities.dll!Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object)
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, object, bool)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, object, bool)
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, object)
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart()
Итак, ошибки происходят где-то глубоко в коде фреймворка.
Я пытался заполнить другие свойства или добавить очистку в Disposed
обработчик, но это не влияет на результат. Если я не установлю RootVisual
ошибок нет (но, конечно, это не вариант).
Есть идеи, что мне не хватает?
1 ответ
Одно решение, которое я нашел, - это создать одноранговый узел автоматизации для корневого визуала. Иначе, GenericRootAutomationPeer
будет создан фреймворком, который вызывает GetWindowText
Windows API.
public class PopupRootAutomationPeer : UIElementAutomationPeer
{
public PopupRootAutomationPeer(FrameworkElement owner)
: base(owner) { }
protected override string GetClassNameCore()
{
return "Pane";
}
protected override AutomationControlType GetAutomationControlTypeCore()
{
return AutomationControlType.Pane;
}
protected override string GetNameCore()
{
return "PopupRootAutomationPeer";
}
}
// Wrap content of the window with this class
class PopupRoot : Canvas
{
protected override AutomationPeer OnCreateAutomationPeer()
{
return new PopupRootAutomationPeer(this);
}
}
Вероятно, есть способ деинициализировать HwndSource
когда он закрывается, так что автоматизация не вызывается на несуществующее окно, но я еще не нашел его.