#1. 今回やること
・XAML Islandsを利用して、MFCアプリにUWPのボタンを表示させます。イベントハンドラを追加は次回となります。
・MFC に XAML Islands で UWP のコントロールを追加してみようとC++ デスクトップ (Win32) アプリで標準 WinRT XAML コントロールをホストするを参考にしています。ありがとうございます。
・前回からさらに以下のことを追加して行きます。
①XAML IsLandに必要なヘッダのインクルード
②app.manifestの追加
③XAML IsLandの初期化
④XAML IsLandのハンドルの取得~表示までのコードの追加
#2. プロジェクトの作成
・今回は単一のドキュメントでプロジェクトを作成します。名前は「MFCWinRTButton」で
・いらない機能が追加されるので、「高度な機能」のドッキング可能な・・・はすべてチェックを外します。
・前回のように「C++17」へ変更、「/await」を追加します。
・pch.hはXAML関連のヘッダを追加して、以下のようになりました。
#ifndef PCH_H
#define PCH_H
// プリコンパイルするヘッダーをここに追加します
#include "framework.h"
#undef GetCurrentTime
#undef TRY
#pragma comment(lib, "windowsapp")
#include <winrt/base.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.UI.Popups.h>
#include <hstring.h>
#include <winrt/Windows.UI.Xaml.Controls.h>
#include <winrt/Windows.UI.Xaml.Controls.Primitives.h>
#include <winrt/Windows.UI.Xaml.Hosting.h>
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
#endif //PCH_H
#3. app.manifestの追加
・ソリューションエクスプローラーのプロジェクトを右クリックし、「追加」→「新しい項目」を選びます。
・「Web」→「XMLファイル」を選び名前に「app.manifest」を入力して追加します。
・追加したら、デスクトップ アプリケーション プロジェクトを作成するのXMLの中をコピペします。
<?xml version="1.0" encoding="utf-8"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- Windows 10 -->
<maxversiontested Id="10.0.18362.0"/>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>
・このapp.manifestが無いと、ビルド時にエラーが出ます。
#4. XAML IsLandの初期化
・MFCWinRTButton.cppのBOOL CMFCWinRTButtonApp::InitInstance()にwinrtの初期化とxamlマネージャーの初期化を追加します。
//前略
// CMFCWinRTButtonApp の初期化
BOOL CMFCWinRTButtonApp::InitInstance()
{
// アプリケーション マニフェストが visual スタイルを有効にするために、
// ComCtl32.dll Version 6 以降の使用を指定する場合は、
// Windows XP に InitCommonControlsEx() が必要です。さもなければ、ウィンドウ作成はすべて失敗します。
INITCOMMONCONTROLSEX InitCtrls;
InitCtrls.dwSize = sizeof(InitCtrls);
// アプリケーションで使用するすべてのコモン コントロール クラスを含めるには、
// これを設定します。
InitCtrls.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx(&InitCtrls);
//winrtの初期化
winrt::init_apartment(winrt::apartment_type::single_threaded);
//xamlマネージャーの初期化
winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager winxamlmanager = winrt::Windows::UI::Xaml::Hosting::WindowsXamlManager::InitializeForCurrentThread();
CWinAppEx::InitInstance();
//後略
#5. XAML IsLandのハンドルの取得~表示までのコードの追加
・MFCWinRTButtonView.hにDesktopWindowXamlSourceのプライベートメンバを追加します。
・これを経由して色々な操作を行います。
#pragma once
class CMFCWinRTButtonView : public CView
{
//XamlSourceの追加
winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource desktopSource;
protected: // シリアル化からのみ作成します。
CMFCWinRTButtonView() noexcept;
DECLARE_DYNCREATE(CMFCWinRTButtonView)
// 属性
public:
CMFCWinRTButtonDoc* GetDocument() const;
//後略
・クラスビューからCMFCWinRTButtonViewを選び、プロパティよりOnCreateを追加します。
・追加したCMFCWinRTButtonView::OnCreate(LPCREATESTRUCT lpCreateStruct)にコードを追加します。
int CMFCWinRTButtonView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// ハンドルを取得
auto interop = desktopSource.as<IDesktopWindowXamlSourceNative>();
// ウインドウへアタッチ
winrt::check_hresult(interop->AttachToWindow(this->m_hWnd));
//XAML用のHWNDを取得
HWND hWndXamlIsland = nullptr;
interop->get_WindowHandle(&hWndXamlIsland);
//ボタンの作成
winrt::Windows::UI::Xaml::Controls::Button button;
button.Content(winrt::box_value(winrt::hstring(L"Button")));
//XAML contentの作成。ここにコントロールを追加して行きます
winrt::Windows::UI::Xaml::Controls::StackPanel xamlContainer;
//StackPanelへコントロール(ボタン)を登録して、StackPanelをXamlSourceへ追加
xamlContainer.Children().Append(button);
desktopSource.Content(xamlContainer);
//今回はウインドウの(0,0)~(500,500)の正方形の領域にXAMLを表示しています。
//画面全体に表示させたい場合はGetWindowRectでウインドウの大きさを取得して,それを指定してください。
//サイズ変更に対応する場合は、OnSize()を追加して、ハンドルを取得して、StackPanelの大きさを指定してください。
::SetWindowPos(hWndXamlIsland, NULL, 0, 0, 500, 500, SWP_SHOWWINDOW);
xamlContainer.UpdateLayout();
return 0;
}
・追加したコードについての説明はコメントで入れておいたので確認してください。
・MSのページではパッケージ化するって書いてあったけど、パッケージ化しなくても表示できてますね。
・実行するとこんな感じです。
・MFCのSDIアプリにUWPのボタンを表示させてみました。案外簡単にMFCアプリもモダン!にできるでしょう?
・次回はこのボタンにイベントハンドラを追加します。
目次へ