快速调整窗口大小时,程序中出现 System.ExecutionEngineException

问题描述 投票:0回答:1

当我调整 WinUI 3 应用程序的大小时,它在程序中有一个

System.ExecutionEngineException
,我必须在按下热键时进行检测。

系统执行引擎异常 H结果=0x80131506 来源= 堆栈跟踪:

return PInvoke.CallWindowProc(wndProc, hWnd, Msg, wParam, lParam);

在我的应用程序中,我有一个

ToggleButton
,我想通过 F6 键进行切换。就正确切换按钮而言,一切工作正常,但每当我快速调整应用程序大小时,它就会崩溃。

Resizing crashing app

我尝试检查窗口句柄是否为空,但没有解决问题。我也尝试通过处理它来获得更好的错误消息,但没有成功。

复制

GitHub 存储库

我使用 Visual Studio 2022 和空白应用程序,打包(桌面中的 WinUI 3)并安装了 CsWin32 软件包。

MainWindow.xaml.cs

using System;
using System.Runtime.InteropServices;
using Microsoft.UI.Xaml;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.Input.KeyboardAndMouse;
using Windows.Win32.UI.WindowsAndMessaging;

namespace HotkeySubclassing;

public sealed partial class MainWindow : Window
{
    private WNDPROC wndProc = null!;

    private LRESULT HotKeyProc(HWND hWnd, uint Msg, WPARAM wParam, LPARAM lParam)
    {
        uint WM_HOTKEY = 0x0312; // HotKey Window Message

        if (Msg == WM_HOTKEY)
        {
            if (ToggleButton.IsEnabled)
            {
                ToggleButton.IsChecked = !ToggleButton.IsChecked;
            }
        }

        return PInvoke.CallWindowProc(wndProc, hWnd, Msg, wParam, lParam); // Error happens on this line
    }

    public MainWindow()
    {
        this.InitializeComponent();

        // Get window handle
        HWND hWnd = new(WinRT.Interop.WindowNative.GetWindowHandle(this));

        // Register hotkey
        int id = 0x0000;
        _ = PInvoke.RegisterHotKey(hWnd, id, HOT_KEY_MODIFIERS.MOD_NOREPEAT, 0x75); // F6

        // Add hotkey function pointer to window procedure
        WNDPROC hotKeyDelegate = HotKeyProc;
        nint hotKeyProcPtr = Marshal.GetFunctionPointerForDelegate(hotKeyDelegate);
        nint wndPtr = PInvoke.SetWindowLongPtr(hWnd, WINDOW_LONG_PTR_INDEX.GWL_WNDPROC, hotKeyProcPtr);
        wndProc = Marshal.GetDelegateForFunctionPointer<WNDPROC>(wndPtr);
    }
}

NativeMethods.txt

RegisterHotKey
UnregisterHotKey
SetWindowLongPtr
CallWindowProc

MainWindow.xaml

<?xml version="1.0" encoding="utf-8" ?>
<Window
    x:Class="HotkeySubclassing.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="HotkeySubclassing"
    mc:Ignorable="d">

    <StackPanel
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        Orientation="Horizontal">
        <ToggleButton x:Name="ToggleButton">Click Me</ToggleButton>
    </StackPanel>
</Window>
c# .net windows xaml winui-3
1个回答
0
投票

这是因为运行 .NET 时,您生活在一个“托管”世界中,当 .NET 需要时,通常是在垃圾收集器运行时,可以在内存中移动对象。

因此,您必须将传递的对象“固定”到非托管内存,这样它们就不会被移动。最简单的方法是创建一个静态变量,如下所示:

public sealed partial class MainWindow : Window
{
    private static WNDPROC wndProc = null!;
    private static WNDPROC hp = HotKeyProc;
    private static MainWindow _window;

    private static LRESULT HotKeyProc(HWND hWnd, uint Msg, WPARAM wParam, LPARAM lParam)
    {
        uint WM_HOTKEY = 0x0312; // HotKey Window Message

        if (Msg == WM_HOTKEY)
        {
            if (_window.ToggleButton.IsEnabled)
            {
                _window.ToggleButton.IsChecked = !_window.ToggleButton.IsChecked;
            }
        }

        return PInvoke.CallWindowProc(wndProc, hWnd, Msg, wParam, lParam);
    }

    public MainWindow()
    {
        this.InitializeComponent();

        _window = this;

        // Get window handle
        HWND hWnd = new(WinRT.Interop.WindowNative.GetWindowHandle(this));

        // Register hotkey
        int id = 0x0000;
        _ = PInvoke.RegisterHotKey(hWnd, id, HOT_KEY_MODIFIERS.MOD_NOREPEAT, 0x75); // F6

        // Add hotkey function pointer to window procedure
        nint hotKeyProcPtr = Marshal.GetFunctionPointerForDelegate(hp);
        nint wndPtr = PInvoke.SetWindowLongPtr(hWnd, WINDOW_LONG_PTR_INDEX.GWL_WNDPROC, hotKeyProcPtr);
        wndProc = Marshal.GetDelegateForFunctionPointer<WNDPROC>(wndPtr);
    }
}

这里有一个示例如何为按钮制作全局键盘加速器/热键?它有一些可重用的代码并且工作方式有点不同

© www.soinside.com 2019 - 2024. All rights reserved.