<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Personal Project on kenji.blog</title><link>http://kenji.blog/ar/tags/personal-project/</link><description>Recent content in Personal Project on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>ar</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 04:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/ar/tags/personal-project/index.xml" rel="self" type="application/rss+xml"/><item><title>تعلم من تطوير LogicPad: مسار إصدار تطبيق Windows تم تطويره شخصياً</title><link>http://kenji.blog/ar/p/logicpad-windows-app-development-journey/</link><pubDate>Sun, 13 Sep 2026 04:00:00 +0900</pubDate><guid>http://kenji.blog/ar/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) باستخدام تقنيات الويب يعتبر عقلانياً جداً من وجهة نظر سرعة التطوير وقابلية الصيانة. ومع ذلك، اخترت بجرأة مسار تطوير تطبيق يُدعى &amp;ldquo;LogicPad&amp;rdquo; كتطبيق أصلي محسّن بالكامل لنظام التشغيل Windows.&lt;/p>
&lt;p>LogicPad هو محاكي للدوائر المنطقية الرقمية ومحرر نصوص يستهدف مهندسي الأجهزة ومتعلمي الدوائر المنطقية. يتطلب التطبيق محاكاة عشرات الآلاف من البوابات المنطقية في الوقت الفعلي وتصيير بيانات أشكال موجية معقدة في نفس الوقت دون أي تأخير. في هذا المجال الذي يتطلب أداءً فائقاً، فإن التوقفات المؤقتة لبضعة أجزاء من الألف من الثانية (micro-stutters) الناتجة عن تجميع القمامة (Garbage Collection) وعبء التصيير الخاص بعروض الويب (WebViews) ستؤدي إلى تدهور قاتل في تجربة المستخدم.&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 مخطط زمني لتطوير LogicPad
dateFormat YYYY-MM-DD
section &amp;#34;التخطيط والتصميم&amp;#34;
&amp;#34;تحليل المتطلبات والنماذج الأولية&amp;#34; :a1, 2025-10-01, 30d
&amp;#34;تصميم البنية (Core C++)&amp;#34; :a2, after a1, 20d
section &amp;#34;التطوير الأساسي&amp;#34;
&amp;#34;محرك المحاكاة (C++)&amp;#34; :a3, after a2, 45d
&amp;#34;تكامل WinUI 3 XAML&amp;#34; :a4, after a3, 40d
section &amp;#34;تحسين UI/UX&amp;#34;
&amp;#34;شريط العنوان المخصص والنافذة&amp;#34; :a5, after a4, 15d
&amp;#34;الموزع غير المتزامن والترابط المتعدد&amp;#34; :a6, after a5, 15d
section &amp;#34;الإصدار والمتجر&amp;#34;
&amp;#34;حزم MSIX والإمكانيات&amp;#34; :a7, after a6, 10d
&amp;#34;شهادة Microsoft Store&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 مثل Win32 API (User32/GDI) و MFC و Windows Forms و WPF و UWP. حالياً، التوصية التي تقدمها Microsoft لتطوير تطبيقات سطح مكتب Windows الحديثة هي &lt;strong>WinUI 3&lt;/strong> المرفق ضمن &lt;strong>Windows App SDK&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 مجموعة من المكتبات لتوفير أحدث واجهات برمجة تطبيقات (APIs) لنظام Windows بغض النظر عن إصدار نظام التشغيل. في حين أن منصة UWP (Universal Windows Platform) التقليدية كانت مرتبطة بقوة بتحديثات نظام التشغيل، يتم توزيع Windows App SDK مع التطبيق، مما يضمن سلوكاً متسقاً من Windows 10 (الإصدار 1809 وما بعده) إلى Windows 11.&lt;/p>
&lt;p>WinUI 3 هو إطار عمل لواجهة المستخدم الأصلية يعمل فوق Windows App SDK ويدعم بشكل كامل نظام التصميم الانسيابي (Fluent Design System). بُنيت البنية الداخلية لـ WinUI 3 باستخدام C++ و DirectX، مما يجعلها تعمل بسرعة فائقة.&lt;/p>
&lt;h3 id="32-أسباب-اختيار-c-cwinrt-بدلا-من-c">3.2. أسباب اختيار C++ (C++/WinRT) بدلاً من C#
&lt;/h3>&lt;p>كلغات تطوير لـ WinUI 3، يتم دعم كل من C# و C++. في حين أن استخدام C# و .NET من شأنه أن يحسن كفاءة التطوير بشكل كبير، فقد تم اعتماد &lt;strong>C++/WinRT&lt;/strong> في LogicPad للأسباب التالية:&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 Cache Hit Rate) إلى أقصى حد.&lt;/li>
&lt;li>&lt;strong>حدود ABI الأصلية&lt;/strong>: C++/WinRT عبارة عن إسقاط (projection) حديث لـ C++ لنموذج كائن المكون (COM). يسمح لك باستدعاء واجهات برمجة تطبيقات نظام التشغيل الأصلية مباشرة بدون عبء P/Invoke كما هو الحال في C#.&lt;/li>
&lt;/ol>
&lt;p>يوجد نموذج COM في جوهر C++/WinRT. جميع كائنات WinRT هي في الأساس كائنات COM تنفذ واجهة &lt;code>IUnknown&lt;/code>، وتقوم المؤشرات الذكية في 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>تطوير WinUI 3 باستخدام C++/WinRT قوي، ولكنه يأتي بتعقيد فريد. سأشرح هنا بالتفصيل التحديين التقنيين الكبيرين اللذين واجهتهما في تطوير LogicPad والحلول لهما.&lt;/p>
&lt;h3 id="41-رعب-تحديثات-واجهة-المستخدم-غير-المتزامنة-في-c-والروتين-المساعد-coroutines">4.1. رعب تحديثات واجهة المستخدم غير المتزامنة في C++ والروتين المساعد (Coroutines)
&lt;/h3>&lt;p>القاعدة الذهبية لتطبيقات واجهة المستخدم الحديثة هي &amp;ldquo;لا يجب حظر خيط واجهة المستخدم (UI thread)&amp;rdquo;. في LogicPad، يجب تنفيذ حسابات المحاكاة للدوائر الضخمة في خيط خلفي (background thread)، ويجب أن تنعكس النتائج على خيط واجهة المستخدم.&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: شقة أحادية الخيط و MTA: شقة متعددة الخيوط) أمر ضروري.&lt;/p>
&lt;p>الكود التالي هو نمط مستخرج من قاعدة كود LogicPad الفعلية للتبديل بسلاسة بين العمليات الحسابية في الخلفية والعودة إلى خيط واجهة المستخدم.&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">// التقاط سياق الشقة لخيط واجهة المستخدم الحالي (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">// تحديث حالة واجهة المستخدم (يتم التنفيذ في خيط واجهة المستخدم)
&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">// خلال هذا الوقت، يتم تحرير خيط واجهة المستخدم لمنع تجمد التطبيق
&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">// إعادة السياق إلى خيط واجهة المستخدم
&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">// من هنا فصاعداً سيتم التنفيذ في خيط واجهة المستخدم، لذا يمكن الوصول بأمان إلى عناصر التحكم 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">// العودة إلى خيط واجهة المستخدم حتى عند حدوث استثناء لعرض رسالة الخطأ
&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> هذا كالسحر، ولكنه داخلياً يعتمد على آلية C++ متقدمة تستخدم واجهة &lt;code>IContextCallback&lt;/code> لتذكر سياق الخيط الأصلي وإرسال (إدراج في قائمة الانتظار) العملية إلى ذلك السياق عند نقطة &lt;code>co_await&lt;/code>. يسمح لك هذا بكتابة معالجة غير متزامنة بأسلوب رمزي إجرائي دون الوقوع في جحيم الاستدعاءات (callback hell).&lt;/p>
&lt;h3 id="42-التنفيذ-الكامل-لشريط-العنوان-المخصص">4.2. التنفيذ الكامل لشريط العنوان المخصص
&lt;/h3>&lt;p>في تطبيقات عصر Windows 11، يُعد &amp;ldquo;شريط العنوان المخصص&amp;rdquo; الذي يضع علامات التبويب أو مربع بحث في شريط عنوان النافذة (منطقة التسمية التوضيحية) مطلباً أساسياً لتجربة المستخدم الحديثة (UX). ومع ذلك، في حين أن تخصيص شريط العنوان في WinUI 3 يكون سهلاً إذا أردت تغيير اللون فقط، فإن صعوبة الأمر ترتفع بشكل حاد عندما تحاول تلبية متطلبات مثل &amp;ldquo;توسيع منطقة العميل إلى شريط العنوان مع الحفاظ على قدرة سحب النافذة وتخطيط الانجذاب (إعادة التحجيم التلقائي عند تحريك النافذة إلى حافة الشاشة)&amp;rdquo;.&lt;/p>
&lt;p>في LogicPad، استخدمنا واجهة برمجة التطبيقات &lt;code>ExtendsContentIntoTitleBar&lt;/code> لبناء شريط العنوان بعناصر XAML الخاصة بنا. يوضح الكود التالي كيفية تخصيص شريط العنوان باستخدام فئة &lt;code>AppWindow&lt;/code> من Windows App SDK.&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">// التحقق مما إذا كان التخصيص مدعوماً لإصدار نظام التشغيل
&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">// تعيين عنصر واجهة المستخدم (AppTitleBar) المحدد في XAML كمنطقة سحب
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span> &lt;span class="c1">// ※ بالنسبة لتفاصيل هذا الجزء، يجب مراقبة UIElement في XAML بواسطة موزع خيط واجهة المستخدم،
&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() لإخبار نظام التشغيل بالمنطقة القابلة للسحب.
&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 (مثل عند تغيير حجم النافذة)، يجب عليك إعادة حساب وإخطار نظام التشغيل بمنطقة اختبار الإصابة القائلة بأن &amp;ldquo;هذه منطقة يمكن سحبها&amp;rdquo; باستخدام &lt;code>InputNonClientPointerSource&lt;/code> أو &lt;code>SetDragRectangles&lt;/code>. إذا أهملت ذلك، فستواجه أخطاء حيث لا تتحرك النافذة حتى لو قمت بسحب شريط العنوان، أو على العكس، يتم احتساب النقر فوق زر كسحب للنافذة.&lt;/p>
&lt;h2 id="5-أعماق-حزم-msix-و-appxmanifest">5. أعماق حزم MSIX و AppXManifest
&lt;/h2>&lt;p>لتوزيع LogicPad بعد اكتمال التطوير، من الضروري إنشاء مُثبّت (installer). بدلاً من مُثبّتات 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 إلى قراءة وكتابة ملفات المشاريع الضخمة المحفوظة في نظام الملفات المحلي (مثل مجلد المستندات الخاص بالمستخدم). في بيئة وضع الحماية (sandbox) القياسية لـ 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> &amp;ldquo;القدرة المقيدة&amp;rdquo; (Restricted Capability)، وعند إرسال التطبيق إلى Microsoft Store، يجب تقديم مبرر للمراجعين يشرح سبب حاجتك إلى هذا الإذن. قمت بشرح أن &amp;ldquo;هذا التطبيق هو أداة احترافية تقرأ وتكتب وتصدّر ملفات مشاريع الدوائر المنطقية التعسفية الموجودة على الأقراص المحلية للمستخدمين&amp;rdquo;، وتمت الموافقة عليه دون مشاكل.&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;المطور (Visual Studio)&amp;#34;] --&amp;gt;|بناء وتوقيع| B[&amp;#34;إنشاء حزمة MSIX&amp;#34;]
B --&amp;gt; C[&amp;#34;مجموعة شهادات تطبيقات Windows (WACK)&amp;#34;]
C --&amp;gt;|اجتياز| D[&amp;#34;لوحة تحكم مركز الشركاء&amp;#34;]
C --&amp;gt;|فشل| E[&amp;#34;إصلاح مشكلات الكود / البيان&amp;#34;]
E --&amp;gt; A
D --&amp;gt;|رفع الحزمة| F[&amp;#34;عملية شهادة المتجر&amp;#34;]
F --&amp;gt; G[&amp;#34;فحص البرامج الضارة التلقائي&amp;#34;]
G --&amp;gt; H[&amp;#34;مراجعة المحتوى اليدوية&amp;#34;]
H --&amp;gt;|موافقة| I[&amp;#34;النشر على Microsoft Store&amp;#34;]
H --&amp;gt;|رفض| J[&amp;#34;معالجة الملاحظات وإعادة الإرسال&amp;#34;]
J --&amp;gt; D
I --&amp;gt; K[&amp;#34;التطبيق متاح الآن!&amp;#34;]
&lt;/pre>
&lt;h3 id="61-جدار-wack-مجموعة-شهادات-تطبيقات-windows">6.1. جدار WACK (مجموعة شهادات تطبيقات Windows)
&lt;/h3>&lt;p>قبل التحميل إلى مركز الشركاء، يجب عليك تشغيل &lt;strong>WACK (Windows App Certification Kit)&lt;/strong> محلياً واجتياز الاختبارات الأولية. WACK هي أداة تختبر تلقائياً ما إذا كان التطبيق يتعطل، أو يستدعي واجهات برمجة تطبيقات غير صالحة، وما إذا كان يفي بمتطلبات الأداء.&lt;/p>
&lt;p>في حالة التطبيقات الأصلية بلغة C++، فإن أهم شيء يجب الحذر منه هو خطأ &amp;ldquo;استخدام واجهات برمجة تطبيقات غير مدعومة&amp;rdquo;. إذا قمت بالربط الثابت لمكتبة C++ قديمة تابعة لجهة خارجية، فقد يتم استخدام واجهات برمجة تطبيقات Win32 مهملة داخل تلك المكتبة، مما يؤدي إلى الفشل في مراجعة WACK. لتجنب هذه المشكلة، قمت بتحديث المكتبات المعتمدة إلى أحدث الإصدارات وإعادة كتابة بعض الوظائف لاستخدام واجهات برمجة التطبيقات البديلة التي يوفرها Windows App SDK.&lt;/p>
&lt;h3 id="62-المراجعة-والنشر">6.2. المراجعة والنشر
&lt;/h3>&lt;p>تتضمن الإعدادات في مركز الشركاء أسعار التطبيق، وفئات العمر (تصنيف IARC)، وإدخال لقطات شاشة وصفية للمتجر. نظراً لأن LogicPad أداة تقنية، تمكنت من الحصول على تصنيف مناسب لجميع الأعمار على الفور.&lt;/p>
&lt;p>استغرق الأمر حوالي 3 أيام عمل من إرسال الحزمة حتى اكتمال المراجعة. بعد الفحص التلقائي للبرامج الضارة وفحص الوظائف، قام فريق مراجعة Microsoft بإجراء اختبار تشغيل يدوي. تمت الموافقة على طلب إذن &lt;code>runFullTrust&lt;/code> دون أي مشاكل، والشعور بالإنجاز في اللحظة التي تغيرت فيها الحالة أخيراً إلى &amp;ldquo;منشور&amp;rdquo; (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 وما إلى ذلك). يمكن نمذجة إجمالي بصمة الذاكرة (Memory Footprint) للتطبيق $M_{total}$ على النحو التالي:&lt;/p>
$$
M_{total} = M_{UI} + M_{engine} + M_{cache}
$$&lt;p>هنا، تكون الذاكرة $M_{UI}$ الناتجة عن التصيير الأصلي لـ WinUI 3 أصغر بكثير مقارنة بـ Electron الذي يقوم بتحميل محرك متصفح (حوالي 50 ميغابايت).
علاوة على ذلك، فإن ذاكرة جزء محرك C++ $M_{engine}$ تتوسع خطياً مع عدد البوابات المنطقية $N$ بفضل الهياكل المحسنة وإلغاء المؤشرات.&lt;/p>
$$
M_{engine} = N \times \text{sizeof(LogicNode)}
$$&lt;p>من خلال تحسين محاذاة الهياكل باستخدام &lt;code>#pragma pack&lt;/code> في C++، قمنا بتقليل الذاكرة لكل عقدة إلى الحد الأدنى المطلق.&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) للنظام يظل دون 200 ميغابايت حتى بالنسبة للدوائر التي تضم عشرات الآلاف من العقد.&lt;/p>
&lt;h3 id="72-ltv-و-cac-حسابات-التسويق">7.2. LTV و CAC: حسابات التسويق
&lt;/h3>&lt;p>في استراتيجية تحقيق الدخل في التطوير الشخصي، التوازن بين القيمة الدائمة للعميل (LTV: Lifetime Value) وتكلفة اكتساب العميل (CAC: Customer Acquisition Cost) هو كل شيء. يتبنى LogicPad نموذج ترخيص الشراء لمرة واحدة (freemium) بدلاً من الاشتراك.&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>تتمثل نقطة قوة التطوير الشخصي في أنه يمكن التعامل مع تكلفة العمالة للتطوير كـ &amp;ldquo;وقت هواية&amp;rdquo; كتكلفة غارقة، مما يسمح بحساب CAC استناداً إلى تكاليف التسويق الصافية فقط. حالياً، من خلال التدفق العضوي المعتمد بشكل أساسي على التسويق الشفهي (Word of mouth) في المجتمعات التقنية المتخصصة، حققنا اقتصاديات وحدة سليمة حيث $LTV > CAC$ في حالة يكون فيها $CAC \approx 0$ تقريباً.&lt;/p>
&lt;h2 id="8-الخاتمة-عالم-تطوير-التطبيقات-الأصلية-الشاق-والجميل">8. الخاتمة: عالم تطوير التطبيقات الأصلية الشاق والجميل
&lt;/h2>&lt;p>بالنظر إلى رحلة تطوير LogicPad إلى إصداره على Microsoft Store، لم تكن الطريق ممهدة بأي حال من الأحوال، بدءاً من الصراع مع أخطاء التجميع المعقدة لـ C++/WinRT، وتعقب تسريبات الذاكرة الناتجة عن أخطاء حساب المراجع لـ COM، والتحقيق في مواصفات XML لبيانات MSIX.&lt;/p>
&lt;p>بالضبط بسبب تطور تقنيات الويب ودخولنا عصر &amp;ldquo;يمكنك بناء أي شيء في المتصفح&amp;rdquo;، فإن تجربة التطوير الأصلي—حيث تضرب واجهات برمجة تطبيقات نظام التشغيل مباشرة وتهتم بكل بايت من الذاكرة وكل نبضة لوحدة المعالجة المركزية—ستعزز قدرتك الأساسية كمهندس بشكل كبير.&lt;/p>
&lt;p>تستمر عمليات التطوير بنشاط في WinUI 3 و Windows App SDK، وهما أفضل الأدوات لبناء تطبيقات جميلة تحقق أقصى استفادة من نموذج واجهة المستخدم في Windows 11. آمل بصدق أن تكون مقالة المدونة هذه مفيدة للمطورين الذين على وشك مواجهة تحدي تطوير تطبيقات Windows الأصلية، وأن تصطف المزيد من التطبيقات الرائعة في المتجر.&lt;/p>
&lt;p>التطوير لم ينته بعد. في الإصدار التالي من LogicPad، نخطط لدمج محرك تصيير أشكال موجية مخصص خاص بنا يستخدم Direct2D. في المقالة التالية، أخطط للتعمق أكثر في إمكانية التشغيل البيني بين DirectX و WinUI 3 (استخدام SwapChainPanel). ترقبوا ذلك.&lt;/p></description></item></channel></rss>