在 Win32 程序中使用 XAML 托管 API 导航到页面会导致访问冲突
Naivgating to a page using the XAML Hosting API in a Win32 program causes an access violation
我正在使用 XAML 托管 API 在我的 win32 程序中托管 XAML 内容。我已成功初始化托管框架并创建 DesktopWindowXamlSource
objects。我已将我的 DesktopWindowXamlSource
的 Content()
设置为 Frame.
每当我尝试导航到具有该 Frame
的页面时,我的问题就会出现。
为了创建一个 Page
供我的程序使用,我遵循了以下步骤:
定义IDL
namespace Program { [default_interface] runtimeclass SettingsPage: Windows.UI.Xaml.Controls.Page { SettingsPage(); } }
我构建项目,将生成的header和源文件从
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
header:
#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
。然后,在您的桌面应用程序中,从在 UWP 应用程序中创建的 Frame
导航到页面。