c++ - 在 Win32 程序中使用 XAML 托管 API 导航到页面会导致访问冲突

标签 c++ winapi winrt-xaml c++-winrt

我正在使用 XAML 托管 API 在我的 win32 程序中托管 XAML 内容。我已经成功初始化了托管框架并创建了DesktopWindowXamlSource对象。我设置了Content()我的DesktopWindowXamlSourceFrame.每当我尝试导航到带有 Frame 的页面时,就会出现我的问题。 .

创建 Page为了让我的程序使用,我按照以下步骤操作:

  • 定义 IDL
    namespace Program
    {
        [default_interface]
        runtimeclass SettingsPage: Windows.UI.Xaml.Controls.Page
        {
            SettingsPage();
        }
    }
    
  • 我构建项目,从 project_root_folder\Debug\Generated Files\sources 复制生成的头文件和源文件到项目的根目录。然后我使用解决方案资源管理器添加文件。
  • 我删除了static_assert从每个文件。
  • 我构建了项目,然后尝试使用 ContentFrame.Navigate(xaml_typename<winrt::Program::SettingsPage>); 导航到该页面
  • DesktopWindowXamlSource的内容设置为 ContentFrame .每次我尝试导航到该页面时,都会收到此错误:

    Exception thrown at 0x00007FFA08C08106 (Windows.UI.Xaml.dll) in Program.exe: 0xC0000005: Access violation reading location 0x0000000000000000.



    我的入口点和 WindowProc :
    #include "pchRT.h"
    #include <Windows.h>
    #include <windowsx.h>
    #include "UIEngine.h"
    
    LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
        static UI::UIEngine* uiEngine{ nullptr };
    
        switch (msg)
        {
        case WM_CREATE:
            uiEngine = new UI::UIEngine{ reinterpret_cast<HMODULE>(GetWindowLongPtrW(hWnd, GWLP_HINSTANCE)), hWnd };
        break;
        case WM_GETMINMAXINFO:
        {
            const auto mmInfo{ reinterpret_cast<LPMINMAXINFO>(lParam) };
            mmInfo->ptMinTrackSize.x = 876;
            mmInfo->ptMinTrackSize.y = 565;
        }
        break;
        case WM_SIZE:
            if (uiEngine)
            {
                //...
            }
            break;
        case WM_DESTROY:
            delete uiEngine;
            winrt::uninit_apartment();
            PostQuitMessage(0);
            break;
    
        default:
            return DefWindowProcW(hWnd, msg, wParam, lParam);
        }
    
        return 0;
    }
    
    int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, LPWSTR, int nCmdShow)
    {
        PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY handlePolicy{0};
        handlePolicy.HandleExceptionsPermanentlyEnabled = 1;
        handlePolicy.RaiseExceptionOnInvalidHandleReference = 1;
    
        SetProcessMitigationPolicy(ProcessStrictHandleCheckPolicy, &handlePolicy, sizeof PROCESS_MITIGATION_STRICT_HANDLE_CHECK_POLICY);
        WNDCLASSEXW wc{
            sizeof WNDCLASSEXW, CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS, WindowProc, 0, 0, hInstance, nullptr,
            reinterpret_cast<HCURSOR>(LoadImageW(nullptr, IDC_ARROW, IMAGE_CURSOR, 0, 0, LR_SHARED)),
            reinterpret_cast<HBRUSH>(COLOR_WINDOWTEXT), nullptr, L"Settings Manager", nullptr
        };
        const auto hWnd{
            CreateWindowExW(WS_EX_LAYERED, MAKEINTATOM(RegisterClassExW(&wc)), L"Settings Manager", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
                            CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, HWND_DESKTOP, nullptr, hInstance, nullptr)
        };
        SetLayeredWindowAttributes(hWnd, 0, 255, LWA_ALPHA);
        ShowWindow(hWnd, nCmdShow);
    
        MSG msg;
        while (GetMessageW(&msg, nullptr, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
    
        return 0;
    }
    
    UIEngine标题:
    #pragma once
    #include "pchRT.h"
    #include "resource.h"
    #include "MainPage.h"
    #include <Windows.h>
    #include <dwmapi.h>
    #include <string>
    #include <fstream>
    #include <memory>
    #include <vector>
    
    namespace UI
    {
        class UIEngine
        {
            HWND XamlIslandsWindow{}, CaptionIslandsWindow{}, Window;
            winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource DesktopWindowXamlSource;
            winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource CaptionXamlSource;
            winrt::Windows::UI::Xaml::Controls::Grid CaptionGrid, PanelGrid{ nullptr };
            winrt::Windows::UI::Xaml::Controls::Frame ContentFrame;
            bool HandleOverlap;
            RECT ClientArea;
            HINSTANCE AppInstance;
            winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Storage::Streams::IRandomAccessStream>
                ExtractAndLoadResource(
                    int resourceId, LPCWSTR resourceType) const;
            static winrt::Windows::UI::Xaml::FrameworkElement FindElement(
                winrt::Windows::UI::Xaml::FrameworkElement const& startElement, PCWCH name);
        public:
            explicit UIEngine(HINSTANCE appInstance, HWND hWnd);
    
        };
    }
    
    UIEngine执行:
    #include "pchRT.h"
    #include "UIEngine.h"
    using namespace winrt;
    using namespace winrt::Windows::UI::Xaml;
    using namespace winrt::Windows::UI::Xaml::Controls;
    using namespace winrt::Windows::UI::Xaml::Media;
    using namespace winrt::Windows::UI;
    using namespace winrt::Windows::UI::Composition;
    using namespace winrt::Windows::UI::Xaml::Input;
    using namespace winrt::Windows::Foundation;
    using namespace winrt::Windows::Foundation::Numerics;
    using namespace winrt::Windows::Storage::Streams;
    using namespace winrt::Windows::UI::Xaml::Media::Imaging;
    using namespace winrt::Windows::UI::Xaml::Controls::Primitives;
    
    namespace UI
    {
        UIEngine::UIEngine(const HINSTANCE appInstance, const HWND hWnd) : Window(hWnd), HandleOverlap(false), AppInstance(appInstance)
        {
            init_apartment();
            auto windowInterop{ DesktopWindowXamlSource.as<IDesktopWindowXamlSourceNative>() }, windowInterop2{
                     CaptionXamlSource.as<IDesktopWindowXamlSourceNative>()
            };
            check_hresult(windowInterop->AttachToWindow(hWnd));
            check_hresult(windowInterop2->AttachToWindow(hWnd));
            windowInterop->get_WindowHandle(&XamlIslandsWindow);
            windowInterop2->get_WindowHandle(&CaptionIslandsWindow);
            ClientArea.top *= -1;
            SetWindowLongPtrW(CaptionIslandsWindow, GWL_EXSTYLE,
                GetWindowLongPtrW(CaptionIslandsWindow, GWL_EXSTYLE) | WS_EX_TRANSPARENT);
            EnableWindow(CaptionIslandsWindow, FALSE);
            SetWindowPos(CaptionIslandsWindow, nullptr, 0, 1, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
            SetWindowPos(XamlIslandsWindow, nullptr, 0, ClientArea.top, 0, 0,
                SWP_NOSIZE | SWP_NOZORDER | SWP_SHOWWINDOW);
    
            const Border captionBorder;
            const AcrylicBrush captionBorderBrush;
            captionBorderBrush.TintOpacity(0.65);
            captionBorderBrush.TintColor({ 255, 25, 25, 25 });
            captionBorderBrush.FallbackColor({ 255, 35, 35, 35 });
            captionBorderBrush.BackgroundSource(AcrylicBackgroundSource::HostBackdrop);
            captionBorder.Background(captionBorderBrush);
            captionBorder.HorizontalAlignment(HorizontalAlignment::Left);
            captionBorder.Width(75);
            CaptionGrid.Children().Append(captionBorder);
            CaptionXamlSource.Content(CaptionGrid);
            ContentFrame.Navigate(xaml_typename<winrt::Program::SettingsPage>());
        }
    }
    
    pchRT.h :
    #pragma once
    #include <Unknwn.h>
    #include <winrt/base.h>
    #include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
    #include <winrt/Windows.UI.Xaml.Hosting.h>
    #include <winrt/Windows.UI.Xaml.Media.h>
    #include <winrt/Windows.UI.Xaml.Controls.h>
    #include <winrt/Windows.UI.Xaml.Input.h>
    #include <winrt/Windows.UI.h>
    #include <winrt/Windows.UI.Input.h>
    #include <winrt/Windows.UI.Xaml.h>
    #include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
    #include <winrt/Windows.Foundation.h>
    #include <winrt/Windows.Foundation.Collections.h>
    #include <winrt/Windows.UI.Xaml.Markup.h>
    #include <winrt/Windows.UI.Xaml.Interop.h>
    #include <winrt/Windows.Storage.Streams.h>
    #include <winrt/Windows.UI.Xaml.Media.Imaging.h>
    #include <winrt/Windows.UI.Xaml.Data.h>
    

    我的调用堆栈由这些函数调用组成:
        Windows.UI.Xaml.dll!00007ffa08c08106()  Unknown
        Windows.UI.Xaml.dll!00007ffa08c25edc()  Unknown
        Windows.UI.Xaml.dll!00007ffa08c27c22()  Unknown
        Windows.UI.Xaml.dll!00007ffa08c27da7()  Unknown
        Windows.UI.Xaml.dll!00007ffa08c27ead()  Unknown
        Windows.UI.Xaml.dll!00007ffa08c28006()  Unknown
        Windows.UI.Xaml.dll!00007ffa08c280e8()  Unknown
        Windows.UI.Xaml.dll!00007ffa08c281df()  Unknown
        Windows.UI.Xaml.dll!00007ffa08b7e225()  Unknown
        Windows.UI.Xaml.dll!00007ffa08b7e1af()  Unknown
    >   Program.exe!winrt::impl::consume_Windows_UI_Xaml_Controls_INavigate<winrt::Windows::UI::Xaml::Controls::Frame>::Navigate(const winrt::Windows::UI::Xaml::Interop::TypeName & sourcePageType) Line 10998 C++
        Program.exe!UI::UIEngine::UIEngine(HINSTANCE__ * appInstance, HWND__ * hWnd, tagRECT clientArea) Line 123   C++
        Program.exe!WindowProc(HWND__ * hWnd, unsigned int msg, unsigned __int64 wParam, __int64 lParam) Line 33    C++
        [External Code] 
        Program.exe!wWinMain(HINSTANCE__ * hInstance, HINSTANCE__ * __formal, wchar_t * __formal, int nCmdShow) Line 128    C++
        [External Code] 
    

    我正在使用 C++/WinRT 标志 -optimize 编译我的代码,我已经包含了#include "UI.SettingsPage.g.cpp"

    最佳答案

    所以我得到了这个工作。您需要按照以下步骤操作:Custom Control XAML Hosting API

    在执行这些步骤时,忽略方向 Add a new UserControl并添加 Page反而。然后,在您的桌面应用程序中,从 Frame 导航到页面。在 UWP 应用中创建。

    关于c++ - 在 Win32 程序中使用 XAML 托管 API 导航到页面会导致访问冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60961590/

    相关文章:

    c++ - 在使用 NaCl 的 C++ 中,如何按值对 JSON 对象进行排序?

    c++ - 有静态常量成员时的赋值运算符?

    c - 使用 GDI 的弹丸曲线

    java - 是否有等同于 JAVA pack() 的 WIN32 API?

    c# - 为什么调用 await 会过早地完成父任务?

    c++ - 在 C++ 中使用 regex/boost 查找两个数字之间的数字

    c++ - OpenGL 高度图渲染器不产生平滑的地形

    c++ - WaitForMultipleObjects 会修改*多个*对象的状态吗?

    c# - 具有图形的 Windows 8 C# 和 XAML 应用程序架构

    c# - 自定义 View 层次结构的语义缩放,而不是普通的网格或 ListView