スポンサーリンク

Win32API+WinRT+XamlなGUIを.NETやUWPなしで作成する(1)

ネイティブからXamlでGUI作成する方法を探した。実装がよくわかってないので内部的には.NETかUWPに依存しているのかもしれない。未確認。少なくともC++17から呼び出すことが可能。

転載元

MS公式

C++ デスクトップ (Win32) アプリで標準 WinRT XAML コントロールをホストする

https://learn.microsoft.com/ja-jp/windows/apps/desktop/modernize/host-standard-control-with-xaml-islands-cpp

手順

WinRTのプロジェクトを作成。ここでUWPが含まれるものを選択しないように注意

上記からプロジェクトを作るとデフォルトでマニフェストファイルが生成されているので、マニフェストツールから追加のマニフェストファイルに登録する。

マニフェストファイルの内容を以下のように設定。バージョンはWindows10以降である必要がある。

<?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>

続いて、参照を右クリック→参照の追加 を選択。

C:\Program Files (x86)\Windows Kits\10\UnionMetadata\マニフェストファイルで指定したバージョン\Windows.winmd

ファイルを追加。

以下のようにコードを記述。

#include "pch.h"

#include <windows.h>
#include <stdlib.h>
#include <string.h>

#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.system.h>
#include <winrt/windows.ui.xaml.hosting.h>
#include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
#include <winrt/windows.ui.xaml.controls.h>
#include <winrt/Windows.ui.xaml.media.h>

using namespace winrt;
using namespace Windows::UI;
using namespace Windows::UI::Composition;
using namespace Windows::UI::Xaml::Hosting;
using namespace Windows::Foundation::Numerics;


// Microsoftのサンプルをそのままビルドすると
// TextOutでリンクエラーが出るのでこれらを追加しておく
#pragma comment(lib,"gdi32.lib")



LRESULT CALLBACK WindowProc(HWND, UINT, WPARAM, LPARAM);

HWND _hWnd;
HWND _childhWnd;
HINSTANCE _hInstance;


 
int CALLBACK WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow)
{
  _hInstance = hInstance;

  // The main window class name.
  const wchar_t szWindowClass[] = L"Win32DesktopApp";
  WNDCLASSEX windowClass = { };

  windowClass.cbSize = sizeof(WNDCLASSEX);
  windowClass.lpfnWndProc = WindowProc;
  windowClass.hInstance = hInstance;
  windowClass.lpszClassName = szWindowClass;
  windowClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

  windowClass.hIconSm = LoadIcon(windowClass.hInstance, IDI_APPLICATION);

  if (RegisterClassEx(&windowClass) == NULL)
  {
    MessageBox(NULL, L"Windows registration failed!", L"Error", NULL);
    return 0;
  }

  _hWnd = CreateWindow(
    szWindowClass,
    L"Windows c++ Win32 Desktop App",
    WS_OVERLAPPEDWINDOW | WS_VISIBLE,
    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
    NULL,
    NULL,
    hInstance,
    NULL
  );
  if (_hWnd == NULL)
  {
    MessageBox(NULL, L"Call to CreateWindow failed!", L"Error", NULL);
    return 0;
  }


  // Begin XAML Island section.

  // The call to winrt::init_apartment initializes COM; by default, in a multithreaded apartment.
  winrt::init_apartment(apartment_type::single_threaded);

  // Initialize the XAML framework's core window for the current thread.
  WindowsXamlManager winxamlmanager = WindowsXamlManager::InitializeForCurrentThread();

  // This DesktopWindowXamlSource is the object that enables a non-UWP desktop application 
  // to host WinRT XAML controls in any UI element that is associated with a window handle (HWND).
  DesktopWindowXamlSource desktopSource;

  // Get handle to the core window.
  auto interop = desktopSource.as<IDesktopWindowXamlSourceNative>();

  // Parent the DesktopWindowXamlSource object to the current window.
  check_hresult(interop->AttachToWindow(_hWnd));

  // This HWND will be the window handler for the XAML Island: A child window that contains XAML.  
  HWND hWndXamlIsland = nullptr;

  // Get the new child window's HWND. 
  interop->get_WindowHandle(&hWndXamlIsland);

  // Update the XAML Island window size because initially it is 0,0.
  SetWindowPos(hWndXamlIsland, 0, 200, 100, 800, 200, SWP_SHOWWINDOW);

  // Create the XAML content.
  Windows::UI::Xaml::Controls::StackPanel xamlContainer;
  xamlContainer.Background(Windows::UI::Xaml::Media::SolidColorBrush{ Windows::UI::Colors::LightGray() });

  Windows::UI::Xaml::Controls::TextBlock tb;
  tb.Text(L"Hello World from Xaml Islands!");
  tb.VerticalAlignment(Windows::UI::Xaml::VerticalAlignment::Center);
  tb.HorizontalAlignment(Windows::UI::Xaml::HorizontalAlignment::Center);
  tb.FontSize(48);

  xamlContainer.Children().Append(tb);
  xamlContainer.UpdateLayout();
  desktopSource.Content(xamlContainer);

  // End XAML Island section.

  ShowWindow(_hWnd, nCmdShow);
  UpdateWindow(_hWnd);

  //Message loop:
  MSG msg = { };
  while (GetMessage(&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }

  return 0;
}

      
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////

LRESULT CALLBACK WindowProc(HWND hWnd, UINT messageCode, WPARAM wParam, LPARAM lParam)
{
  PAINTSTRUCT ps;
  HDC hdc;
  wchar_t greeting[] = L"Hello World in Win32!";
  RECT rcClient;

  switch (messageCode)
  {
  case WM_PAINT:
    if (hWnd == _hWnd)
    {
      hdc = BeginPaint(hWnd, &ps);
      TextOut(hdc, 300, 5, greeting, wcslen(greeting));
      EndPaint(hWnd, &ps);
    }
    break;
  case WM_DESTROY:
    PostQuitMessage(0);
    break;

    // Create main window
  case WM_CREATE:
    _childhWnd = CreateWindowEx(0, L"ChildWClass", NULL, WS_CHILD | WS_BORDER, 0, 0, 0, 0, hWnd, NULL, _hInstance, NULL);
    return 0;

    // Main window changed size
  case WM_SIZE:
    // Get the dimensions of the main window's client
    // area, and enumerate the child windows. Pass the
    // dimensions to the child windows during enumeration.
    GetClientRect(hWnd, &rcClient);
    MoveWindow(_childhWnd, 200, 200, 400, 500, TRUE);
    ShowWindow(_childhWnd, SW_SHOW);

    return 0;

    // Process other messages.

  default:
    return DefWindowProc(hWnd, messageCode, wParam, lParam);
    break;
  }

  return 0;
}

実行例

続く。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)


この記事のトラックバックURL: