在页面上设置 NavigationCacheMode 会导致 System.StackOverflowException 和 CallWindowProc

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

当我在页面上将 NavigationCacheMode 设置为“启用”或“必需”时,导航到页面然后返回时,我会从

System.StackOverflowException
获得
CallWindowProc

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

ToggleButton
,可以通过 F6 键切换,效果非常好。我需要添加一个新的 Windows 过程来执行使用
CallWindowProc
的操作,并且当启用
System.StackOverflowException
时它会给我
NavigationCacheMode
。我需要
NavigationCacheMode
来保存我的按钮所处的状态。

复制

用于复制的 GitHub 存储库

YouTube 视频显示崩溃

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

MainPage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<Page
    x:Class="NavigationProc.MainPage"
    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:local="using:NavigationProc"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    NavigationCacheMode="Enabled"
    mc:Ignorable="d">

    <!--  NavigationCacheMode being set to Enabled causes the app to crash  -->

    <StackPanel
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        Orientation="Horizontal">
        <ToggleButton x:Name="ToggleButton">F6</ToggleButton>
        <Button Click="Button_Click">To go page</Button>
    </StackPanel>
</Page>

MainPage.xaml.cs

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

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace NavigationProc;

/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
    public MainPage()
    {
        InitializeComponent();
        Loaded += MainPage_Loaded;
    }

    private WNDPROC? origHotKeyProc;
    private WNDPROC? hotKeyProcD;

    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(origHotKeyProc, hWnd, Msg, wParam, lParam);
    }

    private void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        // Get window handle
        MainWindow window = App.MainWindow;
        HWND hWnd = new(WinRT.Interop.WindowNative.GetWindowHandle(window));

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

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

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        _ = Frame.Navigate(typeof(OtherPage));
    }
}

与快速调整窗口大小时在过程中获取 System.ExecutionEngineException 相关

c# .net windows xaml winui-3
1个回答
0
投票
您是否尝试过添加一个简单的逻辑,以便热键不会被多次注册?

private bool IsHotKeyRegistered { get; set; } private void MainPage_Loaded(object sender, RoutedEventArgs e) { if (IsHotKeyRegistered is true) { return; } IsHotKeyRegistered = true; ... }
    
© www.soinside.com 2019 - 2024. All rights reserved.