From 78b054d4d7a58ce0fb3729f3aab926d20d94916c Mon Sep 17 00:00:00 2001 From: vczh Date: Mon, 25 Aug 2025 18:51:42 -0700 Subject: [PATCH] Update release --- Import/GacUI.UnitTest.h | 13 ++- Import/GacUI.cpp | 17 +-- Import/GacUI.h | 96 +++++++++++----- Import/Vlpp.cpp | 3 + Import/Vlpp.h | 109 +++++++++++++++++++ Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 | Bin 25176 -> 25176 bytes Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 | Bin 25176 -> 25176 bytes 7 files changed, 205 insertions(+), 33 deletions(-) diff --git a/Import/GacUI.UnitTest.h b/Import/GacUI.UnitTest.h index b868db6e..dbc99bc7 100644 --- a/Import/GacUI.UnitTest.h +++ b/Import/GacUI.UnitTest.h @@ -1494,7 +1494,9 @@ UnitTestRemoteProtocol UnitTestRemoteProtocol_IOCommands >::Type; - class UnitTestRemoteProtocol : public UnitTestRemoteProtocolFeatures + class UnitTestRemoteProtocol + : public UnitTestRemoteProtocolFeatures + , protected virtual IGuiRemoteEventProcessor { using EventPair = collections::Pair, Func>; protected: @@ -1551,6 +1553,8 @@ IGuiRemoteProtocol // TODO: Failure injection to disconnected } + protected: + void ProcessRemoteEvents() override { #define ERROR_MESSAGE_PREFIX L"vl::presentation::unittest::UnitTestRemoteProtocol::ProcessRemoteEvents()#" @@ -1574,6 +1578,13 @@ IGuiRemoteProtocol } #undef ERROR_MESSAGE_PREFIX } + + public: + + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override + { + return this; + } }; } diff --git a/Import/GacUI.cpp b/Import/GacUI.cpp index 9dfc664e..3e4267f5 100644 --- a/Import/GacUI.cpp +++ b/Import/GacUI.cpp @@ -38512,7 +38512,10 @@ GuiRemoteController::INativeWindowService { if (!connectionStopped) { - remoteProtocol->ProcessRemoteEvents(); + if (auto processor = remoteProtocol->GetRemoteEventProcessor()) + { + processor->ProcessRemoteEvents(); + } bool disconnected = false; remoteMessages.Submit(disconnected); if (timerEnabled && !disconnected) @@ -40838,9 +40841,9 @@ GuiRemoteProtocolFromJsonChannel channel->Submit(disconnected); } - void GuiRemoteProtocolFromJsonChannel::ProcessRemoteEvents() + IGuiRemoteEventProcessor* GuiRemoteProtocolFromJsonChannel::GetRemoteEventProcessor() { - channel->ProcessRemoteEvents(); + return channel->GetRemoteEventProcessor(); } /*********************************************************************** @@ -40989,9 +40992,9 @@ GuiRemoteJsonChannelFromProtocol protocol->Submit(disconnected); } - void GuiRemoteJsonChannelFromProtocol::ProcessRemoteEvents() + IGuiRemoteEventProcessor* GuiRemoteJsonChannelFromProtocol::GetRemoteEventProcessor() { - protocol->ProcessRemoteEvents(); + return protocol->GetRemoteEventProcessor(); } /*********************************************************************** @@ -44614,9 +44617,9 @@ namespace vl::presentation::remote_renderer CHECK_FAIL(L"This function should not be called!"); } - void GuiRemoteRendererSingle::ProcessRemoteEvents() + IGuiRemoteEventProcessor* GuiRemoteRendererSingle::GetRemoteEventProcessor() { - CHECK_FAIL(L"This function should not be called!"); + return nullptr; } } diff --git a/Import/GacUI.h b/Import/GacUI.h index 69408863..9c56cd30 100644 --- a/Import/GacUI.h +++ b/Import/GacUI.h @@ -23304,6 +23304,16 @@ IGuiRemoteProtocolConfig virtual WString GetExecutablePath() = 0; }; +/*********************************************************************** +IGuiRemoteEventProcessor +***********************************************************************/ + + class IGuiRemoteEventProcessor : public virtual Interface + { + public: + virtual void ProcessRemoteEvents() = 0; + }; + /*********************************************************************** IGuiRemoteProtocol ***********************************************************************/ @@ -23313,9 +23323,9 @@ IGuiRemoteProtocol , public virtual IGuiRemoteProtocolMessages { public: - virtual void Initialize(IGuiRemoteProtocolEvents* events) = 0; - virtual void Submit(bool& disconnected) = 0; - virtual void ProcessRemoteEvents() = 0; + virtual void Initialize(IGuiRemoteProtocolEvents* events) = 0; + virtual void Submit(bool& disconnected) = 0; + virtual IGuiRemoteEventProcessor* GetRemoteEventProcessor() = 0; }; class GuiRemoteEventCombinator : public Object, public virtual IGuiRemoteProtocolEvents @@ -23359,9 +23369,9 @@ IGuiRemoteProtocol targetProtocol->Submit(disconnected); } - void ProcessRemoteEvents() override + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override { - targetProtocol->ProcessRemoteEvents(); + return targetProtocol->GetRemoteEventProcessor(); } }; @@ -23396,9 +23406,9 @@ IGuiRemoteProtocol targetProtocol->Submit(disconnected); } - void ProcessRemoteEvents() override + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override { - targetProtocol->ProcessRemoteEvents(); + return targetProtocol->GetRemoteEventProcessor(); } }; @@ -23491,7 +23501,7 @@ IGuiRemoteProtocolChannel virtual void Write(const TPackage& package) = 0; virtual WString GetExecutablePath() = 0; virtual void Submit(bool& disconnected) = 0; - virtual void ProcessRemoteEvents() = 0; + virtual IGuiRemoteEventProcessor* GetRemoteEventProcessor() = 0; }; /*********************************************************************** @@ -23535,9 +23545,9 @@ Serialization channel->Submit(disconnected); } - void ProcessRemoteEvents() override + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override { - channel->ProcessRemoteEvents(); + return channel->GetRemoteEventProcessor(); } }; @@ -23719,11 +23729,18 @@ void ChannelPackageSemanticUnpack( ~GuiRemoteProtocolAsyncChannelSerializerBase(); }; +#ifdef _DEBUG +#define ENSURE_THREAD_ID(ID) CHECK_ERROR(ID == Thread::GetCurrentThreadId(), L"Expected to be called in thread: " ## #ID) +#else +#define ENSURE_THREAD_ID(ID) ((void)0) +#endif + template class GuiRemoteProtocolAsyncChannelSerializer : public GuiRemoteProtocolAsyncChannelSerializerBase , public virtual IGuiRemoteProtocolChannel , protected virtual IGuiRemoteProtocolChannelReceiver + , protected virtual IGuiRemoteEventProcessor { static_assert( std::is_same_v requestIds; }; + vint threadIdUI = -1; + vint threadIdChannel = -1; + IGuiRemoteProtocolChannel* channel = nullptr; IGuiRemoteProtocolChannelReceiver* receiver = nullptr; TUIMainProc uiMainProc; @@ -23775,6 +23795,7 @@ void ChannelPackageSemanticUnpack( void UIThreadProc() { + threadIdUI = Thread::GetCurrentThreadId(); uiMainProc(this); uiMainProc = {}; @@ -23800,6 +23821,7 @@ void ChannelPackageSemanticUnpack( // So that the implementation does not need to care about thread safety // The thread stopped after receiving a signal from UIThreadProc + threadIdChannel = Thread::GetCurrentThreadId(); while (!stopping) { eventAutoChannelTaskQueued.Wait(); @@ -23871,6 +23893,7 @@ void ChannelPackageSemanticUnpack( void Write(const TPackage& package) override { // Called from UI thread + ENSURE_THREAD_ID(threadIdUI); uiPendingPackages.Add(package); } @@ -23879,6 +23902,7 @@ void ChannelPackageSemanticUnpack( // Called from UI thread #define ERROR_MESSAGE_PREFIX L"vl::presentation::remoteprotocol::channeling::GuiRemoteProtocolAsyncChannelSerializer::Submit(...)#" + ENSURE_THREAD_ID(threadIdUI); SPIN_LOCK(lockConnection) { if (!connectionAvailable) @@ -23910,14 +23934,15 @@ void ChannelPackageSemanticUnpack( QueueToChannelThread([this, requestGroup, packages = std::move(uiPendingPackages)]() { + ENSURE_THREAD_ID(threadIdChannel); for (auto&& package : packages) { channel->Write(package); } - bool disconnected = false; + bool disconnected = false; channel->Submit(disconnected); - if (disconnected) - { + if (disconnected) + { SPIN_LOCK(lockConnection) { if (requestGroup->connectionCounter == connectionCounter) @@ -23967,13 +23992,20 @@ void ChannelPackageSemanticUnpack( #undef ERROR_MESSAGE_PREFIX } + protected: + void ProcessRemoteEvents() override { // Called from UI thread - QueueToChannelThread([this]() + ENSURE_THREAD_ID(threadIdUI); + if (channel->GetRemoteEventProcessor()) { - channel->ProcessRemoteEvents(); - }, &eventAutoChannelTaskQueued); + QueueToChannelThread([this]() + { + ENSURE_THREAD_ID(threadIdChannel); + channel->GetRemoteEventProcessor()->ProcessRemoteEvents(); + }, &eventAutoChannelTaskQueued); + } FetchAndExecuteUITasks(); @@ -24003,6 +24035,13 @@ void ChannelPackageSemanticUnpack( } } + public: + + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override + { + return this; + } + public: /// @@ -24091,9 +24130,11 @@ void ChannelPackageSemanticUnpack( void Initialize(IGuiRemoteProtocolChannelReceiver* _receiver) override { // Called from UI thread + ENSURE_THREAD_ID(threadIdUI); receiver = _receiver; QueueToChannelThreadAndWait([this]() { + ENSURE_THREAD_ID(threadIdChannel); channel->Initialize(this); }, &eventAutoChannelTaskQueued); } @@ -24101,16 +24142,19 @@ void ChannelPackageSemanticUnpack( IGuiRemoteProtocolChannelReceiver* GetReceiver() override { // Called from UI thread + ENSURE_THREAD_ID(threadIdUI); return receiver; } WString GetExecutablePath() override { // Called from UI thread + ENSURE_THREAD_ID(threadIdUI); if (!executablePath) { QueueToChannelThreadAndWait([this]() { + ENSURE_THREAD_ID(threadIdChannel); executablePath = channel->GetExecutablePath(); }, &eventAutoChannelTaskQueued); } @@ -24119,6 +24163,8 @@ void ChannelPackageSemanticUnpack( }; } +#undef ENSURE_THREAD_ID + #endif /*********************************************************************** @@ -24211,7 +24257,7 @@ GuiRemoteProtocolFromJsonChannel void Initialize(IGuiRemoteProtocolEvents* _events) override; WString GetExecutablePath() override; void Submit(bool& disconnected) override; - void ProcessRemoteEvents() override; + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override; }; /*********************************************************************** @@ -24274,7 +24320,7 @@ GuiRemoteJsonChannelFromProtocol void Write(const Ptr& package) override; WString GetExecutablePath() override; void Submit(bool& disconnected) override; - void ProcessRemoteEvents() override; + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override; }; /*********************************************************************** @@ -24799,14 +24845,14 @@ namespace vl::presentation::remote_renderer GuiRemoteRendererSingle(); ~GuiRemoteRendererSingle(); - void RegisterMainWindow(INativeWindow* _window); - void UnregisterMainWindow(); - void ForceExitByFatelError(); + void RegisterMainWindow(INativeWindow* _window); + void UnregisterMainWindow(); + void ForceExitByFatelError(); - WString GetExecutablePath() override; - void Initialize(IGuiRemoteProtocolEvents* _events) override; - void Submit(bool& disconnected) override; - void ProcessRemoteEvents() override; + WString GetExecutablePath() override; + void Initialize(IGuiRemoteProtocolEvents* _events) override; + void Submit(bool& disconnected) override; + IGuiRemoteEventProcessor* GetRemoteEventProcessor() override; #define MESSAGE_NOREQ_NORES(NAME, REQUEST, RESPONSE) void Request ## NAME() override; diff --git a/Import/Vlpp.cpp b/Import/Vlpp.cpp index d4eca21d..426aab90 100644 --- a/Import/Vlpp.cpp +++ b/Import/Vlpp.cpp @@ -1511,6 +1511,9 @@ UnitTest int UnitTest::RunAndDisposeTests(const collections::Array& options) { +#ifdef VCZH_MSVC + _set_abort_behavior(0, _WRITE_ABORT_MSG); +#endif bool unrecognized = false; bool _D = false; bool _R = false; diff --git a/Import/Vlpp.h b/Import/Vlpp.h index ea0e079e..16b7a370 100644 --- a/Import/Vlpp.h +++ b/Import/Vlpp.h @@ -6075,6 +6075,115 @@ Range-Based For-Loop Iterator with Index { return {}; } + +/*********************************************************************** +Optimized Range-Based For-Loop Iterator for ArrayBase +***********************************************************************/ + + template + struct RangeBasedForLoopIteratorForList + { + protected: + const ArrayBase& arrayBase; + vint index; + + public: + RangeBasedForLoopIteratorForList(const ArrayBase& _arrayBase) + : arrayBase(_arrayBase) + , index(0) + { + } + + void operator++() + { + ++index; + } + + const T& operator*() const + { + return arrayBase.Get(index); + } + + bool operator==(const RangeBasedForLoopEnding&) const + { + return index >= arrayBase.Count(); + } + + bool operator!=(const RangeBasedForLoopEnding&) const + { + return index < arrayBase.Count(); + } + + friend bool operator==(const RangeBasedForLoopEnding&, const RangeBasedForLoopIteratorForList& iterator) + { + return iterator.index >= iterator.arrayBase.Count(); + } + + friend bool operator!=(const RangeBasedForLoopEnding&, const RangeBasedForLoopIteratorForList& iterator) + { + return iterator.index < iterator.arrayBase.Count(); + } + }; + + template + RangeBasedForLoopIteratorForList begin(const ArrayBase& arrayBase) + { + return { arrayBase }; + } + + template + RangeBasedForLoopEnding end(const ArrayBase& arrayBase) + { + return {}; + } + +/*********************************************************************** +Optimized Range-Based For-Loop Iterator for ArrayBase with Index +***********************************************************************/ + + template + struct RangeBasedForLoopIteratorWithIndexForList : public RangeBasedForLoopIteratorForList + { + public: + RangeBasedForLoopIteratorWithIndexForList(const ArrayBase& arrayBase) + : RangeBasedForLoopIteratorForList(arrayBase) + { + } + + Tuple operator*() const + { + return { this->arrayBase.Get(this->index), this->index }; + } + }; + + template + struct ArrayBaseWithIndex + { + const ArrayBase& arrayBase; + + ArrayBaseWithIndex(const ArrayBase& _arrayBase) + : arrayBase(_arrayBase) + { + } + }; + + template + ArrayBaseWithIndex indexed(const ArrayBase& arrayBase) + { + return { arrayBase }; + } + + template + RangeBasedForLoopIteratorWithIndexForList begin(const ArrayBaseWithIndex& wrapper) + { + return { wrapper.arrayBase }; + } + + template + RangeBasedForLoopEnding end(const ArrayBaseWithIndex& wrapper) + { + return {}; + } } } diff --git a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x64 index 0689a04582570de7210c339fc55b445e63e9484e..9144057eb572be3c6f8bcd6160ec11b878153771 100644 GIT binary patch delta 695 zcmYjOO=uHQ5boPec4v1>@`7kK7}8A|Y7o+f2yKjt+JK%c3bxqhXLp6_!I-qR{#2;; zAO%tB;X8Q|PxVry;#Cl&wBVt5Y!P}9JZaUN2T6QMH`Rgn4ey(oZ{EDwT4P&lY;{9I zK}u-xu04z6&1e$80w(%p3s;nGtjqIS!iy#l^2d0gUYosDul9LlUyH=bkfEhLCf#N} z`flK&|LEbM$F}^;+|2Cc&3t~iUawBNHH^p+JeT9RE@yGy{{S!43{ncmj!K&9)iv-# z?ZIz<2Ae9^n8zA8tCU4OVOg4xI5r)^pE1Ha{Rqyv97#RI zx)7waz*BULF-%iGlQFFI3JhvlfiEf1#zWYqZsx;RN-;mKX=4ZwVT!`|teHappl&g> zjSURyC#lhSLR60+W|;V*pI{Q0azMJb=jIx44U4s~N6NO{+YiR83s@|fsFeth#~0wM zSkOy+pBtZ8z@Td)S|KczO@xYFtP5K$S5Q= zlbE-|cwbt@qe@5cwkMXu8HKPC;;4$)_Jk>#aSW6Rv8&?$DxXB7XZ8TTi6(bNWW?oK zsoh%96hvNL-~z4-@}>cx{neA!0Sf%(42KIZ$)yxrYmyIXAigMyDd zf*(o}2{(m3W?(pAqDK`N2t_d-%HdQfiDFA~`rYeXXiAqAMv}*1MI|D-z%7wxK{Ul#^y@L~2!jcXX(`gXq$-+P zhU$JTNBUhHXBu8>Q<~b%((q0U;EZk%cT|`x>}wk<`X$lsF3jn1T=gU-M3hN7(1(;5 z#83TV{Lk})-MEg|?<`d~9`HV8;m{V_@WLkR=rJYd+s6CwiwVZDX~j^r1XiaTa9jb0 z>SbF(x8y(F=~4ra9RmqRV9hoVow)(6WKu2IQ9PZ= diff --git a/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 b/Tutorial/GacUI_HelloWorlds/UIRes/Xml.bin.x86 index 95cd254a26faf5268c46d70367fb39100734dc75..09ac03ecdfc79f7562320f9f712ab0ca12ddd558 100644 GIT binary patch delta 732 zcmYjP-%Aux81>H1-o4|lyLVe~XLZxjSlYxNtCHGMVf7e^LMXe=?97BhTidRoR6bNf z5=2;w7e&=J(nRD*F-|X+O{T){Sq~J4; z;J4C)w9|_NreiQ*;H_%ncF@5{@SJ9}G#&$cY69;^1zz?GJXAYi1l#yrxw=rh|61+q zj5T#0F0U@HEZ)iIFV||7MYoFGKni_oj~;1iJUrIS*2)XGs&;6ZCYeD!kj9I#2&MvA zYz8tEHh`Nvhb)(jVaQG51D`_w34y2(=nCnGNP&x?>pnW66t-xUTn*ns!}#I|+;b!Z zH++7Yi&sCSX9hDaSq$4Efh(euwIL=9CSi*KsvBaI!nVaAQ!u7wSpZM85vsO!is~=X zjx$=s?|NC#|57D&J9aglso<@%UP!x0u_HWfHK=a3o@Y_8@X4-d^Q78;=vG(CZl&xl zN6{TlvKHLs31zhb502o5yOog!ev* z;HxPSv32|`O;8#Q$(}goSZHg*9%eYC89M&<4ZNfNk247_Bp#E^l)FYFnzWLr5_9O@ F`Uen|(3}7O delta 797 zcmYjOL1+^}6wRcY%}lZ;TMNy`mSz(bOR+VrXhTq;7CbdYDOTFfdB54$Qna^B?d3KYx3jZLhP{4L^qc zDUtLwR}ycppTK@ZLtl%I`!SBk0UfzOKb8Y0@l}d@H3FcW>6K(dzCRHn~?G<-pCp|z=k}<54?pvIga6A z975Pj3c7$~8_%1Z2;1bvAE{DeP$Kp(N@4S9k!aEUXb*zLgU@@wm7F4zE)Jk@_WY2mX z_(C3W@m9sDU9o3MydohhcHo6}rrkH&nc&j9H@-oIZAoayZ5i^I_Gv(NILqtN1mc;?raXD`w8+4eta- z$#ci#EP#vo7?y1fWvW4Hjt4ZVEy|);8g}v-%B~a7{EN{j*A}fFhTQ_E i@pEhzbi5~SggEMj47FJ`W0Y(j56RL^>QHpozVjEYUGK;M