<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Windows App SDK on kenji.blog</title><link>http://kenji.blog/tags/windows-app-sdk/</link><description>Recent content in Windows App SDK on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ja</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 04:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/tags/windows-app-sdk/index.xml" rel="self" type="application/rss+xml"/><item><title>LogicPad開発記から学ぶ：個人開発のWindowsアプリをリリースするまでの軌跡</title><link>http://kenji.blog/p/logicpad-windows-app-development-journey/</link><pubDate>Sun, 13 Sep 2026 04:00:00 +0900</pubDate><guid>http://kenji.blog/p/logicpad-windows-app-development-journey/</guid><description>&lt;img src="http://kenji.blog/p/logicpad-windows-app-development-journey/img/eyecatch.jpg" alt="Featured image of post LogicPad開発記から学ぶ：個人開発のWindowsアプリをリリースするまでの軌跡" />&lt;h2 id="1-はじめになぜ今あえてwindowsネイティブアプリを作るのか">1. はじめに：なぜ今、あえてWindowsネイティブアプリを作るのか
&lt;/h2>&lt;p>現代のアプリケーション開発において、ElectronやTauri、React Nativeなどのクロスプラットフォーム技術が主流となっていることは間違いありません。ウェブ技術を用いて一度書けばどこでも動く（Write Once, Run Anywhere）というアプローチは、開発スピードと保守性の観点から非常に合理的です。しかし、私はあえて「LogicPad」というアプリケーションを、Windowsに完全に最適化されたネイティブアプリケーションとして開発する道を選びました。&lt;/p>
&lt;p>LogicPadは、ハードウェアエンジニアや論理回路の学習者をターゲットとした、デジタル論理回路のシミュレーター兼テキストエディタです。数万個の論理ゲートをリアルタイムでシミュレーションし、同時に複雑な波形データを遅延なくレンダリングする必要があります。このような極限のパフォーマンスが求められる領域では、ガベージコレクションによる数ミリ秒の一時停止（マイクロスタッター）や、ウェブビューのレンダリングオーバーヘッドが致命的なユーザー体験の低下を招きます。&lt;/p>
&lt;p>本記事では、このLogicPadの開発構想から、C++とWinUI 3（Windows App SDK）を用いた実装、特有の技術的壁の突破、MSIXパッケージング、そしてMicrosoft Storeを通じた全世界への配信に至るまでの軌跡を、非常に詳細な技術的解説とともに振り返ります。個人開発者がどのようにしてエンタープライズ品質のネイティブWindowsアプリを作り上げるのか、そのプロセスを共有することで、同じようにネイティブ開発に挑む方々の道標となれば幸いです。&lt;/p>
&lt;h2 id="2-プロジェクトのタイムライン">2. プロジェクトのタイムライン
&lt;/h2>&lt;p>LogicPadの開発は、週末と夜間の時間を活用した個人プロジェクトとして進められました。全体のタイムラインは約半年（6ヶ月）に及びます。以下は、そのプロジェクトの進行を示すGanttチャートです。&lt;/p>
&lt;pre class="mermaid">
gantt
title &amp;#34;LogicPad Development Timeline&amp;#34;
dateFormat YYYY-MM-DD
section &amp;#34;Planning &amp;amp; Design&amp;#34;
&amp;#34;Requirement Analysis &amp;amp; Prototyping&amp;#34; :a1, 2025-10-01, 30d
&amp;#34;Architecture Design (Core C++)&amp;#34; :a2, after a1, 20d
section &amp;#34;Core Development&amp;#34;
&amp;#34;Simulation Engine (C++)&amp;#34; :a3, after a2, 45d
&amp;#34;WinUI 3 XAML Integration&amp;#34; :a4, after a3, 40d
section &amp;#34;UI/UX Refinement&amp;#34;
&amp;#34;Custom Title Bar &amp;amp; Windowing&amp;#34; :a5, after a4, 15d
&amp;#34;Async Dispatcher &amp;amp; Multithreading&amp;#34; :a6, after a5, 15d
section &amp;#34;Release &amp;amp; Store&amp;#34;
&amp;#34;MSIX Packaging &amp;amp; Capabilities&amp;#34; :a7, after a6, 10d
&amp;#34;Microsoft Store Certification&amp;#34; :a8, after a7, 14d
&lt;/pre>
&lt;p>このように、開発時間の大部分はコアエンジンの最適化と、WinUI 3とC++間の非同期処理の統合に費やされました。ネイティブ開発はクロスプラットフォーム開発に比べて初期のセットアップや学習コストが高いものの、最終的なパフォーマンスという形でその投資は確実に回収されます。&lt;/p>
&lt;h2 id="3-技術選定c--winui-3--windows-app-sdk-の深淵">3. 技術選定：C++ / WinUI 3 / Windows App SDK の深淵
&lt;/h2>&lt;p>LogicPadの開発にあたり、技術スタックの選定は最も重要な決定の一つでした。WindowsプラットフォームにおけるネイティブUIフレームワークには、歴史的にWin32 API（User32/GDI）、MFC、Windows Forms、WPF、UWPなど様々な選択肢が存在します。現在、MicrosoftがモダンなWindowsデスクトップアプリケーション開発の推奨としているのが、&lt;strong>Windows App SDK&lt;/strong>に同梱されている&lt;strong>WinUI 3&lt;/strong>です。&lt;/p>
&lt;h3 id="31-windows-app-sdkとwinui-3のアーキテクチャ">3.1. Windows App SDKとWinUI 3のアーキテクチャ
&lt;/h3>&lt;p>Windows App SDKは、OSのバージョンに依存せずに最新のWindows APIを提供するためのライブラリ群です。従来のUWP（Universal Windows Platform）がOSのアップデートと強く結びついていたのに対し、Windows App SDKはアプリケーションと共に配布されるため、Windows 10（バージョン1809以降）からWindows 11まで、一貫した動作を保証します。&lt;/p>
&lt;p>WinUI 3は、このWindows App SDK上で動作するネイティブUIフレームワークであり、Fluent Design Systemを完全にサポートしています。WinUI 3の内部はC++とDirectXで構築されており、非常に高速に動作します。&lt;/p>
&lt;h3 id="32-cではなくあえてccwinrtを選ぶ理由">3.2. C#ではなく、あえてC++（C++/WinRT）を選ぶ理由
&lt;/h3>&lt;p>WinUI 3の開発言語としてはC#とC++がサポートされています。C#と.NETを使用すれば開発効率は飛躍的に向上しますが、LogicPadでは以下の理由から&lt;strong>C++/WinRT&lt;/strong>を採用しました。&lt;/p>
&lt;ol>
&lt;li>&lt;strong>決定論的メモリ管理&lt;/strong>: ガベージコレクタ（GC）が存在しないため、メモリの確保と解放のタイミングを完全にコントロールできます。シミュレーションループ中にGCの一時停止が発生することを防ぎます。&lt;/li>
&lt;li>&lt;strong>SIMDとキャッシュの最適化&lt;/strong>: C++ではメモリの物理的なレイアウト（Struct of Arrays等）を厳密に定義でき、CPUキャッシュのヒット率を最大化できます。&lt;/li>
&lt;li>&lt;strong>ネイティブのABI境界&lt;/strong>: C++/WinRTは、COM（Component Object Model）のモダンなC++プロジェクションです。C#のようなP/Invokeのオーバーヘッドなしに、OSのネイティブAPIを直接呼び出すことができます。&lt;/li>
&lt;/ol>
&lt;p>C++/WinRTの根底にはCOMが存在します。すべてのWinRTオブジェクトは本質的に &lt;code>IUnknown&lt;/code> インターフェースを実装したCOMオブジェクトであり、C++/WinRTの &lt;code>winrt::com_ptr&lt;/code> などのスマートポインタが参照カウント（&lt;code>AddRef&lt;/code> / &lt;code>Release&lt;/code>）を自動的に管理します。&lt;/p>
&lt;h2 id="4-winui-3開発における最大の壁と突破口">4. WinUI 3開発における最大の壁と突破口
&lt;/h2>&lt;p>C++/WinRTを用いたWinUI 3開発は、強力である反面、特有の複雑さを伴います。ここでは、LogicPadの開発において特に苦労した2つの大きな技術的課題とその解決策について詳しく解説します。&lt;/p>
&lt;h3 id="41-cにおける非同期ui更新の恐怖とコルーチン">4.1. C++における非同期UI更新の恐怖とコルーチン
&lt;/h3>&lt;p>モダンなUIアプリケーションの鉄則は、「UIスレッドをブロックしてはならない」ということです。LogicPadでは、巨大な回路のシミュレーション計算をバックグラウンドスレッドで実行し、その結果をUIスレッドに反映させる必要があります。&lt;/p>
&lt;p>C#であれば &lt;code>async/await&lt;/code> と &lt;code>DispatcherQueue&lt;/code> を使って比較的簡単に記述できますが、C++においてはC++20のコルーチン（Coroutines）と &lt;code>winrt::apartment_context&lt;/code> を組み合わせて実現します。COMのアパートメントモデル（STA: Single-Threaded Apartment と MTA: Multi-Threaded Apartment）の理解が不可欠です。&lt;/p>
&lt;p>以下のコードは、LogicPadの実際のコードベースから抽出した、バックグラウンドでの計算とUIスレッドへの復帰をシームレスに行うパターンです。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;winrt/Windows.Foundation.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;winrt/Microsoft.UI.Dispatching.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;winrt/Microsoft.UI.Xaml.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">winrt&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">Microsoft&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">UI&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Xaml&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="k">using&lt;/span> &lt;span class="k">namespace&lt;/span> &lt;span class="n">Microsoft&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">UI&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Dispatching&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// ボタンクリックのイベントハンドラ
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="n">winrt&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">fire_and_forget&lt;/span> &lt;span class="n">MainWindow&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">OnRunSimulationClicked&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IInspectable&lt;/span> &lt;span class="k">const&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="cm">/* sender */&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">RoutedEventArgs&lt;/span> &lt;span class="k">const&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="cm">/* args */&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 現在のUIスレッドのアパートメントコンテキスト（STA）をキャプチャする
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">winrt&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">apartment_context&lt;/span> &lt;span class="n">ui_thread&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">try&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// UIのステータスを更新（ここはUIスレッドで実行される）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">StatusTextBlock&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">Text&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;シミュレーション実行中...&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ProgressBar&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">IsIndeterminate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// スレッドプール（MTA）へコンテキストを移行
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">co_await&lt;/span> &lt;span class="n">winrt&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">resume_background&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 非常に重いシミュレーション処理（バックグラウンドスレッドで実行）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// この間、UIスレッドは解放され、アプリケーションのフリーズを防ぐ
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">std&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">vector&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">LogicResult&lt;/span>&lt;span class="o">&amp;gt;&lt;/span> &lt;span class="n">results&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">CoreEngine&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">RunMassiveSimulation&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// シミュレーション結果を文字列にフォーマット（引き続きバックグラウンドで実行）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">winrt&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">hstring&lt;/span> &lt;span class="n">outputText&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">FormatResults&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">results&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// UIスレッドへコンテキストを戻す
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">co_await&lt;/span> &lt;span class="n">ui_thread&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 以降はUIスレッドで実行されるため、XAMLのコントロールに安全にアクセス可能
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">ResultTextBlock&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">Text&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">outputText&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ProgressBar&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">IsIndeterminate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">false&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">StatusTextBlock&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">Text&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;完了しました&amp;#34;&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">catch&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">winrt&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">hresult_error&lt;/span> &lt;span class="k">const&lt;/span>&lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">ex&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 例外発生時もUIスレッドに戻ってエラーメッセージを表示
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">co_await&lt;/span> &lt;span class="n">ui_thread&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">StatusTextBlock&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">Text&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="sa">L&lt;/span>&lt;span class="s">&amp;#34;エラー: &amp;#34;&lt;/span> &lt;span class="o">+&lt;/span> &lt;span class="n">ex&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">message&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ProgressBar&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">IsIndeterminate&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">false&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>この &lt;code>winrt::apartment_context&lt;/code> の挙動は魔法のように見えますが、内部的には &lt;code>IContextCallback&lt;/code> インターフェースを利用して元のスレッドコンテキストを記憶し、&lt;code>co_await&lt;/code> 時にそのコンテキストに対して処理をディスパッチ（エンキュー）するという高度なC++の仕組みが働いています。これにより、コールバック地獄に陥ることなく、手続き的なコードの見た目で非同期処理を記述できます。&lt;/p>
&lt;h3 id="42-カスタムタイトルバーの完全な実装">4.2. カスタムタイトルバーの完全な実装
&lt;/h3>&lt;p>Windows 11時代のアプリケーションにおいて、ウィンドウのタイトルバー（キャプション領域）にタブや検索ボックスを配置する「カスタムタイトルバー」は、モダンなUXの必須要件です。しかし、WinUI 3におけるタイトルバーのカスタマイズは、単に色を変えるだけなら簡単ですが、「クライアント領域をタイトルバーに拡張しつつ、ウィンドウのドラッグ移動やスナップレイアウト（ウィンドウを画面端に寄せた時の自動リサイズ）を維持する」という要件を満たそうとすると、一気に難易度が跳ね上がります。&lt;/p>
&lt;p>LogicPadでは、&lt;code>ExtendsContentIntoTitleBar&lt;/code> APIを使用して、タイトルバーを自前のXAML要素で構築しました。以下のコードは、Windows App SDKの &lt;code>AppWindow&lt;/code> クラスを利用してタイトルバーをカスタマイズする手順です。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;winrt/Microsoft.UI.Windowing.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;winrt/Microsoft.UI.Interop.h&amp;gt;&lt;/span>&lt;span class="cp">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#include&lt;/span> &lt;span class="cpf">&amp;lt;microsoft.ui.interop.h&amp;gt;&lt;/span>&lt;span class="cp"> &lt;/span>&lt;span class="c1">// for GetWindowIdFromWindow
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kt">void&lt;/span> &lt;span class="n">MainWindow&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">InitializeCustomTitleBar&lt;/span>&lt;span class="p">()&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// 現在のウィンドウのHWND（ウィンドウハンドル）を取得
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">auto&lt;/span> &lt;span class="n">windowNative&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="k">this&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">try_as&lt;/span>&lt;span class="o">&amp;lt;::&lt;/span>&lt;span class="n">IWindowNative&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">HWND&lt;/span> &lt;span class="n">hwnd&lt;/span>&lt;span class="p">{&lt;/span> &lt;span class="k">nullptr&lt;/span> &lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">windowNative&lt;/span>&lt;span class="o">-&amp;gt;&lt;/span>&lt;span class="n">get_WindowHandle&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="o">&amp;amp;&lt;/span>&lt;span class="n">hwnd&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// HWNDからWindowIdに変換し、AppWindowインスタンスを取得
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">winrt&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Microsoft&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">UI&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">WindowId&lt;/span> &lt;span class="n">windowId&lt;/span> &lt;span class="o">=&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">winrt&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Microsoft&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">UI&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">GetWindowIdFromWindow&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">hwnd&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">appWindow&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">winrt&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Microsoft&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">UI&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Windowing&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">AppWindow&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">GetFromWindowId&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">windowId&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// カスタマイズがサポートされているOSバージョンかチェック
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="k">if&lt;/span> &lt;span class="p">(&lt;/span>&lt;span class="n">winrt&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Microsoft&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">UI&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Windowing&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">AppWindowTitleBar&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">IsCustomizationSupported&lt;/span>&lt;span class="p">())&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">auto&lt;/span> &lt;span class="n">titleBar&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="n">appWindow&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">TitleBar&lt;/span>&lt;span class="p">();&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// クライアント領域（コンテンツ）をタイトルバーまで拡張
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">titleBar&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">ExtendsContentIntoTitleBar&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// デフォルトのキャプションボタン（最小化・最大化・閉じる）の背景を透明にする
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="n">titleBar&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">ButtonBackgroundColor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">winrt&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Microsoft&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">UI&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Colors&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Transparent&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">titleBar&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">ButtonInactiveBackgroundColor&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">winrt&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Microsoft&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">UI&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Colors&lt;/span>&lt;span class="o">::&lt;/span>&lt;span class="n">Transparent&lt;/span>&lt;span class="p">());&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// XAML側で定義したUI要素（AppTitleBar）をドラッグ領域として設定
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// ※この部分の詳細はXAML側のUIElementをUIスレッドのDispatcherで監視し、
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// SetDragRectangles() を呼び出してドラッグ可能領域をOSに教える必要があります。
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>この実装における最大の罠は、XAML側のUI要素のサイズが変わるたび（ウィンドウのリサイズ時など）に、&lt;code>InputNonClientPointerSource&lt;/code> や &lt;code>SetDragRectangles&lt;/code> を用いて、OSに対して「ここはドラッグできる領域である」というヒットテスト領域の再計算と通知を行わなければならない点です。これを怠ると、タイトルバーをドラッグしてもウィンドウが動かなくなったり、逆にボタンをクリックしたいのにウィンドウドラッグと判定されたりするバグが発生します。&lt;/p>
&lt;h2 id="5-msixパッケージングの深淵とappxmanifest">5. MSIXパッケージングの深淵とAppXManifest
&lt;/h2>&lt;p>開発が完了したLogicPadを配布するためには、インストーラを作成する必要があります。従来のMSIやEXEのインストーラではなく、私はモダンな &lt;strong>MSIX&lt;/strong> フォーマットを採用しました。MSIXは、インストールとアンインストールが完全にクリーンに行われ（レジストリを汚さない）、自動アップデート機能も備えているため、ユーザーにとって非常に安全で快適です。&lt;/p>
&lt;p>しかし、C++で記述されたネイティブアプリをMSIXでパッケージングする際、最も注意すべきなのが &lt;code>Package.appxmanifest&lt;/code>（マニフェストファイル）の設定です。&lt;/p>
&lt;p>LogicPadはローカルのファイルシステム（ユーザーのドキュメントフォルダ等）に保存された巨大なプロジェクトファイルを読み書きする必要があります。標準のUWPのサンドボックス環境では、アプリ自身の隔離されたデータフォルダ（AppContainer）しかアクセスできません。ネイティブデスクトップアプリとしてフルアクセス権限を得るためには、マニフェストで &lt;code>runFullTrust&lt;/code> 機能を宣言する必要があります。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;utf-8&amp;#34;?&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;Package&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">xmlns=&lt;/span>&lt;span class="s">&amp;#34;http://schemas.microsoft.com/appx/manifest/foundation/windows10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">xmlns:uap=&lt;/span>&lt;span class="s">&amp;#34;http://schemas.microsoft.com/appx/manifest/uap/windows10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">xmlns:rescap=&lt;/span>&lt;span class="s">&amp;#34;http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">IgnorableNamespaces=&lt;/span>&lt;span class="s">&amp;#34;uap rescap&amp;#34;&lt;/span>&lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Identity&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">Name=&lt;/span>&lt;span class="s">&amp;#34;LogicPad.Studio&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">Publisher=&lt;/span>&lt;span class="s">&amp;#34;CN=Kenji&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="na">Version=&lt;/span>&lt;span class="s">&amp;#34;1.0.0.0&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;DisplayName&amp;gt;&lt;/span>LogicPad&lt;span class="nt">&amp;lt;/DisplayName&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;PublisherDisplayName&amp;gt;&lt;/span>Kenji&lt;span class="nt">&amp;lt;/PublisherDisplayName&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Logo&amp;gt;&lt;/span>Assets\StoreLogo.png&lt;span class="nt">&amp;lt;/Logo&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/Properties&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Dependencies&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;TargetDeviceFamily&lt;/span> &lt;span class="na">Name=&lt;/span>&lt;span class="s">&amp;#34;Windows.Desktop&amp;#34;&lt;/span> &lt;span class="na">MinVersion=&lt;/span>&lt;span class="s">&amp;#34;10.0.17763.0&amp;#34;&lt;/span> &lt;span class="na">MaxVersionTested=&lt;/span>&lt;span class="s">&amp;#34;10.0.22621.0&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/Dependencies&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Capabilities&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">&amp;lt;!-- 一般的な機能制限 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;Capability&lt;/span> &lt;span class="na">Name=&lt;/span>&lt;span class="s">&amp;#34;internetClient&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c">&amp;lt;!-- ネイティブデスクトップアプリとして動作するための制限付き機能 --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;rescap:Capability&lt;/span> &lt;span class="na">Name=&lt;/span>&lt;span class="s">&amp;#34;runFullTrust&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/Capabilities&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/Package&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>この &lt;code>&amp;lt;rescap:Capability Name=&amp;quot;runFullTrust&amp;quot; /&amp;gt;&lt;/code> は「制限付き機能（Restricted Capability）」と呼ばれ、Microsoft Storeに提出する際に、なぜこの権限が必要なのかを審査担当者に正当化する理由書を提出する必要があります。私は「本アプリはユーザーのローカルディスクにある任意の論理回路プロジェクトファイルを読み書き・エクスポートするプロフェッショナル向けツールであるため」と説明し、無事に承認を得ました。&lt;/p>
&lt;h2 id="6-microsoft-storeへの道のりと審査プロセス">6. Microsoft Storeへの道のりと審査プロセス
&lt;/h2>&lt;p>アプリケーションの完成とMSIXパッケージのビルドが終われば、いよいよMicrosoft Storeへの提出です。個人開発者にとって、ストアを通じた配布は、アップデートの自動配信、信頼性の担保、そして決済システムの利用という計り知れないメリットがあります。&lt;/p>
&lt;p>Microsoft Storeへの提出プロセスは、Partner Center（パートナーセンター）を通じて行われます。以下のフローチャートは、ビルドから公開までの全体像を示しています。&lt;/p>
&lt;pre class="mermaid">
flowchart TD
A[&amp;#34;Developer (Visual Studio)&amp;#34;] --&amp;gt;|Build &amp;amp; Sign| B[&amp;#34;MSIX Bundle Generation&amp;#34;]
B --&amp;gt; C[&amp;#34;Windows App Certification Kit (WACK)&amp;#34;]
C --&amp;gt;|Pass| D[&amp;#34;Partner Center Dashboard&amp;#34;]
C --&amp;gt;|Fail| E[&amp;#34;Fix Code / Manifest Issues&amp;#34;]
E --&amp;gt; A
D --&amp;gt;|Upload Package| F[&amp;#34;Store Certification Process&amp;#34;]
F --&amp;gt; G[&amp;#34;Automated Malware Scan&amp;#34;]
G --&amp;gt; H[&amp;#34;Manual Content Review&amp;#34;]
H --&amp;gt;|Approved| I[&amp;#34;Publishing to Microsoft Store&amp;#34;]
H --&amp;gt;|Rejected| J[&amp;#34;Address Feedback &amp;amp; Re-submit&amp;#34;]
J --&amp;gt; D
I --&amp;gt; K[&amp;#34;App is Live!&amp;#34;]
&lt;/pre>
&lt;h3 id="61-wackwindows-app-certification-kitの壁">6.1. WACK（Windows App Certification Kit）の壁
&lt;/h3>&lt;p>Partner Centerにアップロードする前に、必ずローカルで &lt;strong>WACK (Windows App Certification Kit)&lt;/strong> を実行し、事前テストを通過させる必要があります。WACKは、アプリがクラッシュしないか、不正なAPIを呼び出していないか、パフォーマンス要件を満たしているかを自動でテストするツールです。&lt;/p>
&lt;p>C++のネイティブアプリの場合、特に注意すべきは「サポートされていないAPIの使用」エラーです。サードパーティ製の古いC++ライブラリを静的リンクしていると、そのライブラリ内部で非推奨のWin32 APIが使われており、WACKの審査で弾かれることがあります。私はこの問題を回避するために、依存するライブラリを最新バージョンに更新し、一部の関数はWindows App SDKが提供する代替APIに書き換えました。&lt;/p>
&lt;h3 id="62-審査と公開">6.2. 審査と公開
&lt;/h3>&lt;p>Partner Centerでの設定には、アプリの価格設定、年齢区分（IARCレーティング）、ストア用のスクリーンショットや説明文の入力が含まれます。LogicPadは技術ツールであるため、全年齢対象のレーティングを即座に取得できました。&lt;/p>
&lt;p>パッケージを提出してから審査が完了するまで、およそ3営業日かかりました。自動のマルウェアスキャンと機能チェックの後、Microsoftの審査チームによる手動の動作確認が行われます。&lt;code>runFullTrust&lt;/code> の権限要求も問題なく通過し、ついにステータスが「公開済み（In the Store）」に変わった瞬間の達成感は、何物にも代えがたいものでした。&lt;/p>
&lt;h2 id="7-ビジネスとしての個人開発パフォーマンスと収益の数学的モデル">7. ビジネスとしての個人開発：パフォーマンスと収益の数学的モデル
&lt;/h2>&lt;p>単にアプリを作って満足するのではなく、LogicPadを継続的にアップデートし、事業として成り立たせるためには、技術的な指標とビジネス的な指標の両方を定量的に評価する必要があります。&lt;/p>
&lt;h3 id="71-cがもたらすメモリ使用量の最適化モデル">7.1. C++がもたらすメモリ使用量の最適化モデル
&lt;/h3>&lt;p>LogicPadの最大の強みは、Electronベースのエディタ（例: VSCodeなど）と比較して、極めて軽量である点です。アプリケーションのメモリフットプリント $M_{total}$ は、次のようにモデル化できます。&lt;/p>
$$
M_{total} = M_{UI} + M_{engine} + M_{cache}
$$&lt;p>ここで、WinUI 3のネイティブレンダリングによる $M_{UI}$ は、ブラウザエンジンをロードするElectronに比べて劇的に小さくなります（約50MB程度）。
さらに、C++エンジン部のメモリ $M_{engine}$ は、論理ゲートの数 $N$ に対して、最適化された構造体とポインタの排除により線形にスケーリングします。&lt;/p>
$$
M_{engine} = N \times \text{sizeof(LogicNode)}
$$&lt;p>C++の &lt;code>#pragma pack&lt;/code> を用いて構造体のアライメントを最適化することで、1ノードあたりのメモリを極限まで削りました。&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-cpp" data-lang="cpp">&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#pragma pack(push, 1)
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">&lt;/span>&lt;span class="c1">// 仮想関数テーブル(vtable)を持たせず、パックすることでメモリを最小化
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="k">struct&lt;/span> &lt;span class="nc">LogicNode&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="kt">uint32_t&lt;/span> &lt;span class="n">id&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 4 bytes
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">uint16_t&lt;/span> &lt;span class="n">type&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 2 bytes
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="kt">bool&lt;/span> &lt;span class="n">isActive&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="c1">// 1 byte
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// 構造体サイズは 7 bytes（アライメントのパディングなし）
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">};&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="cp">#pragma pack(pop)
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>キャッシュレイヤーのメモリ $M_{cache}$ はシミュレーションの履歴を保持するため、$\mathcal{O}(N \log N)$ に比例して増加しますが、ベースとなるフットプリントが小さいため、数万ノードの回路でもシステム全体のRAM使用量は200MB以下に収まっています。&lt;/p>
&lt;h3 id="72-ltvとcacマーケティングの算段">7.2. LTVとCAC：マーケティングの算段
&lt;/h3>&lt;p>個人開発におけるマネタイズ戦略において、顧客生涯価値（LTV: Lifetime Value）と顧客獲得単価（CAC: Customer Acquisition Cost）のバランスが全てです。LogicPadはサブスクリプションではなく、買い切り型のライセンスモデル（フリーミアム）を採用しています。&lt;/p>
&lt;p>LTVは、将来のアップグレード版購入の確率を割引率 $d$ で割り引いた現在価値の総和として計算します。期間を $T$ とした時、以下の数式で表されます。&lt;/p>
$$
LTV = \sum_{t=1}^{T} \frac{ARPU_t \times Margin}{(1+d)^t}
$$&lt;p>一方、CACはTwitter（現X）の広告やブログ記事からの流入などにかかるマーケティング費用の総額を、新規ユーザー数で割ったものです。&lt;/p>
$$
CAC = \frac{Total\ Marketing\ Spend}{Number\ of\ New\ Users}
$$&lt;p>個人開発の強みは、開発にかかる人件費を「趣味の時間」としてサンクコスト化できるため、純粋なマーケティングコストのみでCACを計算できる点です。現在、ニッチな技術系コミュニティへの口コミを中心としたオーガニックな流入により、$CAC \approx 0$ に近い状態で $LTV > CAC$ の健全なユニットエコノミクスを実現しています。&lt;/p>
&lt;h2 id="8-おわりに泥臭くも美しいネイティブアプリ開発の世界">8. おわりに：泥臭くも美しいネイティブアプリ開発の世界
&lt;/h2>&lt;p>LogicPadの開発からMicrosoft Storeへのリリースまでの軌跡を振り返ると、C++/WinRTの難解なコンパイルエラーとの格闘、COMの参照カウントバグによるメモリリークの追跡、そしてMSIXマニフェストのXMLの仕様調査など、決して平坦な道ではありませんでした。&lt;/p>
&lt;p>ウェブ技術の進化により「何でもブラウザで作れる」時代になったからこそ、OSのAPIを直接叩き、メモリの1バイト、CPUの1クロックまで気を配るネイティブ開発の経験は、エンジニアとしての基礎体力を圧倒的に高めてくれます。&lt;/p>
&lt;p>WinUI 3とWindows App SDKは、現在も活発に開発が進められており、Windows 11のUIパラダイムを最大限に活かした美しいアプリケーションを作るための最高のツールです。このブログ記事が、これからWindowsネイティブアプリ開発に挑戦しようとしている開発者の一助となり、Storeに素晴らしいアプリが一つでも多く並ぶことを心から願っています。&lt;/p>
&lt;p>開発はまだ終わっていません。LogicPadの次のバージョンでは、Direct2Dを活用した独自の波形レンダリングエンジンの統合を予定しています。次回の記事では、DirectXとWinUI 3の相互運用（SwapChainPanelの活用）について深く掘り下げる予定です。ご期待ください。&lt;/p></description></item></channel></rss>