├── .clang-format ├── .editorconfig ├── .gitattributes ├── .gitignore ├── Base ├── Strings │ └── StringTransform.cpp ├── Sync │ ├── CriticalSection.cpp │ ├── SRWLock.cpp │ └── Sync.cpp ├── Threading │ ├── ParallelTaskRunnerImpl.hpp │ ├── SequencedTaskRunnerImpl.cpp │ ├── SequencedTaskRunnerImpl.h │ ├── TaskRunner.cpp │ ├── TaskRunnerDispatchImpl.cpp │ ├── TaskRunnerDispatchImpl.h │ ├── TaskRunnerImpl.cpp │ ├── TaskRunnerImpl.h │ ├── ThreadPool.h │ ├── ThreadPoolForLinux.cpp │ ├── ThreadPoolForLinux.h │ ├── ThreadPoolForWindows.cpp │ ├── ThreadPoolForWindows.h │ ├── ThreadPoolTimerManger.h │ ├── ThreadPoolWaitManger.h │ ├── ThreadTaskRunnerImpl.cpp │ ├── ThreadTaskRunnerImpl.h │ └── ThreadTaskRunnerProxyImpl.h └── Utils │ ├── FileInfo.cpp │ └── SystemInfo.cpp ├── Directory.Build.props ├── Directory.Build.targets ├── Example ├── Example.cpp ├── Example.h ├── Example.ico ├── Example.rc ├── Example.vcxproj ├── Example.vcxproj.filters ├── Example.xml ├── Resource.h ├── framework.h ├── small.ico └── targetver.h ├── Include ├── Base │ ├── Containers │ │ ├── Array.h │ │ ├── ArrayView.h │ │ ├── BitMap.h │ │ ├── ConstructorPolicy.h │ │ ├── DoublyLinkedList.h │ │ ├── HashSet.h │ │ ├── Optional.h │ │ └── SingleLinkedList.h │ ├── Encoding.h │ ├── ErrorCode.h │ ├── Exception.h │ ├── IO │ │ └── File.h │ ├── Memory │ │ ├── Alloc.h │ │ ├── RefPtr.h │ │ ├── UniquePtr.h │ │ └── WeakPtr.h │ ├── SAL.h │ ├── SafeCast.h │ ├── Shared │ │ └── Windows │ │ │ └── km.h │ ├── Strings │ │ ├── NString.h │ │ ├── String.h │ │ ├── StringTransform.h │ │ └── StringView.h │ ├── Sync │ │ ├── AutoLock.h │ │ ├── CriticalSection.h │ │ ├── Interlocked.h │ │ ├── InterlockedQueue.h │ │ ├── InterlockedSingleLinkedList.h │ │ ├── SRWLock.h │ │ └── Sync.h │ ├── Threading │ │ ├── Coroutine.h │ │ ├── ProcessThreads.h │ │ └── TaskRunner.h │ ├── Time │ │ ├── Common.h │ │ ├── TickCount.h │ │ └── TimeSpan.h │ ├── Utils │ │ ├── ComObjectImpl.h │ │ ├── FileInfo.h │ │ ├── MathUtils.h │ │ ├── SystemInfo.h │ │ └── Version.h │ ├── YY.h │ └── tchar.h ├── Media │ ├── Brushes │ │ └── Brush.h │ ├── Color.h │ ├── Font.h │ ├── Graphics │ │ └── DrawContext.h │ ├── Pens │ │ └── Pen.h │ ├── Point.h │ ├── Rect.h │ ├── Resource.h │ └── Size.h └── MegaUI │ ├── Base │ └── MegaUITypeInt.h │ ├── Control │ ├── Button.h │ └── TextBox.h │ ├── Core │ ├── ControlInfo.h │ ├── ControlInfoImp.h │ ├── DeferCycle.h │ ├── Element.h │ ├── Layout.h │ ├── Property.h │ ├── StyleSheet.h │ ├── TextScaleManger.h │ ├── UIEvent.h │ ├── Unit.h │ └── Value.h │ ├── Parser │ └── UIParser.h │ ├── Render │ ├── FontEnumMap.h │ └── Render.h │ └── Window │ ├── Window.h │ └── WindowElement.h ├── Media ├── Font.cpp └── Graphics │ ├── D2D │ ├── D2D1_0DrawContext.cpp │ ├── D2D1_0DrawContext.h │ ├── D2D1_1DrawContext.cpp │ ├── D2D1_1DrawContext.h │ ├── DWriteHelper.cpp │ └── DWriteHelper.h │ ├── D3D │ ├── D3D11DrawContext.cpp │ ├── D3D11DrawContext.h │ ├── SolidColorPixelShader.hlsl │ └── VertexShader.hlsl │ ├── DrawAsyncCommandContext.cpp │ ├── DrawAsyncCommandContext.h │ ├── DrawContext.cpp │ └── GDIPlus │ ├── GDIPlusDrawContext.cpp │ ├── GDIPlusDrawContext.h │ ├── GDIPlusHelper.h │ └── GdiPlusTextLayout.hpp ├── MegaUI.sln ├── MegaUI ├── Accessibility │ └── UIAutomation │ │ ├── AccessibleEventManager.cpp │ │ ├── AccessibleEventManager.h │ │ ├── ElementAccessibleProviderImpl.cpp │ │ ├── ElementAccessibleProviderImpl.h │ │ ├── ElementPatternProviderImpl.h │ │ ├── PatternProviderImpl.h │ │ ├── WindowElementAccessibleProviderImpl.cpp │ │ ├── WindowElementAccessibleProviderImpl.h │ │ └── WindowElementPatternProviderImpl.h ├── Common.xml ├── Control │ ├── Button.cpp │ └── TextBox.cpp ├── Core │ ├── Unit.cpp │ ├── Value.cpp │ └── Windows │ │ └── TextScaleManger.cpp ├── MegaUI.cpp ├── MegaUI.natvis ├── MegaUI.vcxproj ├── MegaUI.vcxproj.filters ├── Parser │ ├── UIParser.cpp │ └── ValueParser.h ├── Render │ ├── FontEnumMap.cpp │ └── Render.cpp ├── Window │ ├── Window.cpp │ └── WindowElement.cpp ├── core │ ├── ControlInfo.cpp │ ├── Element.cpp │ └── StyleSheet.cpp ├── framework.h ├── pch.cpp └── pch.h ├── ThirdParty └── rapidxml │ ├── license.txt │ ├── rapidxml.hpp │ ├── rapidxml_iterators.hpp │ ├── rapidxml_print.hpp │ └── rapidxml_utils.hpp ├── UnitTest ├── AsyncFileUnitTest.cpp ├── BitMapUnitTest.cpp ├── DynamicArrayUnitTest.cpp ├── StringUnitTest.cpp ├── TaskRunnerUnitTest.cpp ├── UnitTest.vcxproj ├── UnitTest.vcxproj.filters ├── ValueParserUnitTest.cpp ├── pch.cpp └── pch.h ├── YY C++风格.md └── readme.md /.clang-format: -------------------------------------------------------------------------------- 1 | # https://clang.llvm.org/docs/ClangFormatStyleOptions.html 2 | 3 | Language: Cpp 4 | # BasedOnStyle: Microsoft 5 | 6 | Standard : c++14 7 | 8 | IndentWidth : 4 9 | AccessModifierOffset : -4 10 | IndentAccessModifiers : false 11 | PointerAlignment: Left 12 | ReferenceAlignment : Left 13 | ColumnLimit : 0 14 | 15 | TabWidth: 4 16 | UseTab: Never 17 | 18 | # 命名空间缩进 19 | NamespaceIndentation : All 20 | CompactNamespaces : false 21 | # 命名空间结束添加 注释 // namespace XXX 22 | FixNamespaceComments : true 23 | 24 | 25 | IndentWrappedFunctionNames: false 26 | 27 | AlignArrayOfStructures: Left 28 | 29 | # public结束后有一个回车 30 | EmptyLineBeforeAccessModifier : LogicalBlock 31 | 32 | 33 | BreakConstructorInitializers : BeforeComma 34 | BreakInheritanceList : BeforeComma 35 | # template后面不要有空格 36 | SpaceAfterTemplateKeyword : false 37 | 38 | Cpp11BracedListStyle : true 39 | 40 | # AlignEscapedNewlines : DontAlign 41 | SpaceBeforeCpp11BracedList : true 42 | 43 | # AllowAllParametersOfDeclarationOnNextLine : false 44 | SortUsingDeclarations : false 45 | SortIncludes : Never 46 | 47 | BreakBeforeBraces: Custom 48 | BraceWrapping: 49 | AfterFunction : true 50 | AfterNamespace : true 51 | AfterUnion : true 52 | AfterExternBlock : true 53 | BeforeElse : true 54 | BeforeWhile : false 55 | SplitEmptyFunction : true 56 | SplitEmptyRecord : true 57 | AfterCaseLabel : true 58 | AfterControlStatement: Always 59 | BeforeLambdaBody : true 60 | AfterClass : true 61 | AfterStruct : true 62 | AfterEnum : true 63 | 64 | SpaceBeforeParens : ControlStatements 65 | 66 | SpaceBeforeCaseColon : false 67 | SpacesInContainerLiterals : true -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | 4 | # 代码文件尽可能的使用 UTF-8,因为英语字符占据大多数。 5 | # 数据文件比如 XML,json统一缩进 2,因为外部规范往往如此 6 | 7 | [*] 8 | end_of_line = crlf 9 | insert_final_newline = true 10 | charset = utf-8-bom 11 | indent_style = space 12 | indent_size = 4 13 | 14 | [*.{vcxproj,xml,props,targets}] 15 | indent_style = space 16 | indent_size = 2 17 | insert_final_newline = false 18 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=crlf 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /Base/Sync/CriticalSection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | __YY_IGNORE_INCONSISTENT_ANNOTATION_FOR_FUNCTION() 4 | 5 | namespace YY 6 | { 7 | namespace Base 8 | { 9 | namespace Sync 10 | { 11 | void __YYAPI CriticalSection::Lock() noexcept 12 | { 13 | const auto _uCurrentThreadId = Threading::GetCurrentThreadId(); 14 | if (uOwnerThreadId == _uCurrentThreadId) 15 | { 16 | ++uLockRef; 17 | return; 18 | } 19 | 20 | oSRWLock.Lock(); 21 | uOwnerThreadId = _uCurrentThreadId; 22 | uLockRef = 0; 23 | } 24 | 25 | bool __YYAPI CriticalSection::TryLock() noexcept 26 | { 27 | const auto _uCurrentThreadId = Threading::GetCurrentThreadId(); 28 | if (uOwnerThreadId == _uCurrentThreadId) 29 | { 30 | ++uLockRef; 31 | return true; 32 | } 33 | 34 | if (oSRWLock.TryLock()) 35 | { 36 | uOwnerThreadId = _uCurrentThreadId; 37 | uLockRef = 0; 38 | return true; 39 | } 40 | 41 | return false; 42 | } 43 | 44 | void __YYAPI CriticalSection::Unlock() noexcept 45 | { 46 | --uLockRef; 47 | if (uLockRef == 0) 48 | { 49 | uOwnerThreadId = 0; 50 | oSRWLock.Unlock(); 51 | } 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Base/Sync/SRWLock.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace YY 4 | { 5 | namespace Base 6 | { 7 | namespace Sync 8 | { 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Base/Sync/Sync.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | __YY_IGNORE_INCONSISTENT_ANNOTATION_FOR_FUNCTION() 5 | 6 | namespace YY 7 | { 8 | namespace Base 9 | { 10 | namespace Sync 11 | { 12 | template 13 | bool __YYAPI WaitEqualOnAddress( 14 | volatile ValueType* _pAddress, 15 | ValueType _CompareValue, 16 | TimeSpan _uMilliseconds) noexcept 17 | { 18 | if (_uMilliseconds.GetMilliseconds() <= 0) 19 | { 20 | return *_pAddress == _CompareValue; 21 | } 22 | else if (_uMilliseconds == TimeSpan::GetMax()) 23 | { 24 | for (;;) 25 | { 26 | auto _Temp = *_pAddress; 27 | if (_Temp == _CompareValue) 28 | break; 29 | 30 | WaitOnAddress(_pAddress, &_Temp, sizeof(_Temp), UINT32_MAX); 31 | } 32 | 33 | return true; 34 | } 35 | else 36 | { 37 | const auto _uExpireTick = TickCount::GetCurrent() + _uMilliseconds; 38 | for (;;) 39 | { 40 | auto _Temp = *_pAddress; 41 | if (_Temp == _CompareValue) 42 | break; 43 | 44 | const auto _uCurrent = TickCount::GetCurrent(); 45 | if (_uCurrent > _uExpireTick) 46 | return false; 47 | 48 | if (!WaitOnAddress(_pAddress, &_Temp, sizeof(_Temp), (_uExpireTick - _uCurrent).GetMilliseconds())) 49 | return false; 50 | } 51 | 52 | return true; 53 | } 54 | } 55 | 56 | bool __YYAPI WaitEqualOnAddress( 57 | volatile void* Address, 58 | void* CompareAddress, 59 | size_t AddressSize, 60 | TimeSpan _uMilliseconds) noexcept 61 | { 62 | switch (AddressSize) 63 | { 64 | case 1: 65 | { 66 | using Type = uint8_t; 67 | return WaitEqualOnAddress((volatile Type*)(Address), *(Type*)(CompareAddress), _uMilliseconds); 68 | } 69 | case 2: 70 | { 71 | using Type = uint16_t; 72 | return WaitEqualOnAddress((volatile Type*)(Address), *(Type*)(CompareAddress), _uMilliseconds); 73 | } 74 | case 4: 75 | { 76 | using Type = uint32_t; 77 | return WaitEqualOnAddress((volatile Type*)(Address), *(Type*)(CompareAddress), _uMilliseconds); 78 | } 79 | case 8: 80 | { 81 | using Type = uint64_t; 82 | return WaitEqualOnAddress((volatile Type*)(Address), *(Type*)(CompareAddress), _uMilliseconds); 83 | } 84 | default: 85 | return false; 86 | break; 87 | } 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Base/Threading/SequencedTaskRunnerImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #pragma pack(push, __YY_PACKING) 6 | 7 | namespace YY 8 | { 9 | namespace Base 10 | { 11 | namespace Threading 12 | { 13 | class SequencedTaskRunnerImpl : public SequencedTaskRunner 14 | { 15 | friend YY::Base::Threading::ThreadPool; 16 | private: 17 | InterlockedQueue oTaskQueue; 18 | 19 | union 20 | { 21 | volatile uint32_t uWakeupCountAndPushLock; 22 | struct 23 | { 24 | volatile uint32_t bPushLock : 1; 25 | volatile uint32_t bStopWakeup : 1; 26 | volatile uint32_t bInterrupt : 1; 27 | volatile uint32_t uWakeupCount : 29; 28 | }; 29 | }; 30 | enum : uint32_t 31 | { 32 | LockedQueuePushBitIndex = 0, 33 | StopWakeupBitIndex, 34 | InterruptBitIndex, 35 | WakeupCountStartBitIndex, 36 | StopWakeupRaw = 1 << StopWakeupBitIndex, 37 | InterruptRaw = 1 << InterruptBitIndex, 38 | WakeupOnceRaw = 1 << WakeupCountStartBitIndex, 39 | LockQueuePushLockAndWakeupOnceRaw = WakeupOnceRaw + (1u << LockedQueuePushBitIndex), 40 | TerminateTaskRunnerRaw = StopWakeupRaw | InterruptRaw, 41 | }; 42 | 43 | uString szThreadDescription; 44 | 45 | public: 46 | SequencedTaskRunnerImpl(uString _szThreadDescription = uString()); 47 | 48 | ~SequencedTaskRunnerImpl() override; 49 | 50 | SequencedTaskRunnerImpl(const SequencedTaskRunnerImpl&) = delete; 51 | 52 | SequencedTaskRunnerImpl& operator=(const SequencedTaskRunnerImpl&) = delete; 53 | 54 | ///////////////////////////////////////////////////// 55 | // TaskRunner 56 | virtual TaskRunnerStyle __YYAPI GetStyle() const noexcept override; 57 | 58 | HRESULT __YYAPI Join(TimeSpan _nWaitTimeOut) noexcept override; 59 | 60 | HRESULT __YYAPI Interrupt() noexcept override; 61 | 62 | void __YYAPI operator()(); 63 | 64 | private: 65 | HRESULT __YYAPI PostTaskInternal(_In_ RefPtr _pTask) override; 66 | 67 | void __YYAPI CleanupTaskQueue() noexcept; 68 | 69 | void __YYAPI ExecuteTaskRunner(); 70 | }; 71 | } 72 | } 73 | } // namespace YY 74 | 75 | #pragma pack(pop) 76 | -------------------------------------------------------------------------------- /Base/Threading/TaskRunnerDispatchImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #pragma pack(push, __YY_PACKING) 14 | 15 | /* 16 | TaskRunnerDispatch 仅处理调度任务(比如定时器、异步IO),无法参执行其他Task。 17 | 18 | */ 19 | 20 | namespace YY 21 | { 22 | namespace Base 23 | { 24 | namespace Threading 25 | { 26 | class TaskRunnerDispatch 27 | { 28 | public: 29 | static _Ret_notnull_ TaskRunnerDispatch* __YYAPI Get() noexcept; 30 | 31 | #if defined(_WIN32) 32 | virtual bool __YYAPI BindIO(_In_ HANDLE _hHandle) const noexcept = 0; 33 | #endif 34 | 35 | virtual void __YYAPI SetTimerInternal(_In_ RefPtr _pTimer) noexcept = 0; 36 | 37 | virtual HRESULT __YYAPI SetWaitInternal(_In_ RefPtr _pWait) noexcept = 0; 38 | 39 | /// 40 | /// 发起异步请求成功后请调用此函数。内部将对完成端口进行监听。 41 | /// 42 | /// 43 | virtual void __YYAPI StartIo() noexcept = 0; 44 | 45 | protected: 46 | static void __YYAPI DispatchTask(RefPtr _pDispatchTask) noexcept 47 | { 48 | if (!_pDispatchTask) 49 | return; 50 | 51 | do 52 | { 53 | if (_pDispatchTask->IsCanceled()) 54 | break; 55 | 56 | // 不属于任何TaskRunner,因此在线程池随机唤醒 57 | if (_pDispatchTask->pOwnerTaskRunnerWeak == nullptr) 58 | { 59 | auto _hr = ThreadPool::PostTaskInternal(_pDispatchTask.Get()); 60 | return; 61 | } 62 | 63 | // 任务所属的 TaskRunner 已经释放? 64 | auto _pResumeTaskRunner = _pDispatchTask->pOwnerTaskRunnerWeak.Get(); 65 | if (_pResumeTaskRunner == nullptr) 66 | break; 67 | 68 | _pResumeTaskRunner->PostTaskInternal(std::move(_pDispatchTask)); 69 | return; 70 | } while (false); 71 | 72 | _pDispatchTask->Wakeup(YY::Base::HRESULT_From_LSTATUS(ERROR_CANCELLED)); 73 | } 74 | }; 75 | } 76 | } 77 | } // namespace YY 78 | 79 | #pragma pack(pop) 80 | -------------------------------------------------------------------------------- /Base/Threading/TaskRunnerImpl.cpp: -------------------------------------------------------------------------------- 1 | #include "TaskRunnerImpl.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | __YY_IGNORE_INCONSISTENT_ANNOTATION_FOR_FUNCTION() 8 | 9 | namespace YY 10 | { 11 | namespace Base 12 | { 13 | namespace Threading 14 | { 15 | thread_local WeakPtr g_pTaskRunnerWeak; 16 | 17 | uint32_t __YYAPI GenerateNewTaskRunnerId() 18 | { 19 | static uint32_t s_TaskRunnerId = 0; 20 | return Sync::Increment(&s_TaskRunnerId); 21 | } 22 | 23 | uint32_t __YYAPI GetWaitTimeSpan(TickCount _uWakeupTickCount) noexcept 24 | { 25 | if (_uWakeupTickCount == TickCount::GetMax()) 26 | return UINT32_MAX; 27 | 28 | auto _nTimeSpan = _uWakeupTickCount - TickCount::GetCurrent(); 29 | if (_nTimeSpan.GetInternalValue() <= 0) 30 | { 31 | return 1ul; 32 | } 33 | else if (_nTimeSpan.GetMilliseconds() >= UINT32_MAX) 34 | { 35 | return UINT32_MAX; 36 | } 37 | 38 | return (uint32_t)(std::max)(_nTimeSpan.GetMilliseconds(), 1ll); 39 | } 40 | } 41 | } 42 | } // namespace YY::Base::Threading 43 | -------------------------------------------------------------------------------- /Base/Threading/TaskRunnerImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #pragma pack(push, __YY_PACKING) 7 | 8 | namespace YY 9 | { 10 | namespace Base 11 | { 12 | namespace Threading 13 | { 14 | extern thread_local WeakPtr g_pTaskRunnerWeak; 15 | 16 | uint32_t __YYAPI GenerateNewTaskRunnerId(); 17 | 18 | uint32_t __YYAPI GetWaitTimeSpan(_In_ TickCount _uWakeupTickCount) noexcept; 19 | } 20 | } 21 | } // namespace YY::Base::Threading 22 | 23 | #pragma pack(pop) 24 | -------------------------------------------------------------------------------- /Base/Threading/ThreadPool.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(_WIN32) 4 | #include 5 | #else 6 | #include 7 | #endif 8 | -------------------------------------------------------------------------------- /Base/Threading/ThreadPoolForLinux.cpp: -------------------------------------------------------------------------------- 1 | #include "pch.h" 2 | #include "ThreadPoolForLinux.h" 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | __YY_IGNORE_INCONSISTENT_ANNOTATION_FOR_FUNCTION() 10 | 11 | namespace YY::Base::Threading 12 | { 13 | constexpr uint32_t MinThreadsCount = 10; 14 | constexpr uint32_t MaxThreadsCount = 500; 15 | 16 | HRESULT __YYAPI ThreadPool::ExecuteTask(ThreadPoolSimpleCallback _pfnCallback, void* _pUserData) noexcept 17 | { 18 | auto _pThread = oIdleThreadQueue.Pop(); 19 | if (_pThread) 20 | { 21 | _pThread->pUserData = _pUserData; 22 | _pThread->pfnCallback = _pfnCallback; 23 | 24 | pthread_kill(_pThread->hThread, SIGUSR1); 25 | return S_OK; 26 | } 27 | 28 | for (auto uCurrentThreadCount = uThreadCount;;) 29 | { 30 | if (uCurrentThreadCount >= MaxThreadsCount) 31 | { 32 | // 达到线程创建上限 33 | auto _pTask = New(_pfnCallback, _pUserData); 34 | if(!_pTask) 35 | return E_OUTOFMEMORY; 36 | 37 | oPendingTaskQueue.Push(_pTask); 38 | return S_OK; 39 | } 40 | 41 | const auto _uLast = Sync::CompareExchange(&uThreadCount, uCurrentThreadCount + 1, uCurrentThreadCount); 42 | if (_uLast == uCurrentThreadCount) 43 | { 44 | break; 45 | } 46 | 47 | uCurrentThreadCount = _uLast; 48 | } 49 | 50 | _pThread = New(); 51 | if (!_pThread) 52 | { 53 | Sync::Decrement(&uThreadCount); 54 | return E_OUTOFMEMORY; 55 | } 56 | 57 | _pThread->pfnCallback = _pfnCallback; 58 | _pThread->pUserData = _pUserData; 59 | _pThread->pThreadPool = this; 60 | 61 | const auto _iResult = pthread_create(&_pThread->hThread, nullptr, 62 | [](void* _pUserData) -> void* 63 | { 64 | auto _pThread = (ThreadInfoEntry*)_pUserData; 65 | return _pThread->pThreadPool->TaskExecuteRoutine(_pThread); 66 | }, _pThread); 67 | 68 | if (_iResult == 0) 69 | { 70 | return S_OK; 71 | } 72 | 73 | Sync::Decrement(&uThreadCount); 74 | Delete(_pThread); 75 | 76 | // TODO: 错误代码转换 77 | return E_FAIL; 78 | } 79 | 80 | void* ThreadPool::TaskExecuteRoutine(ThreadInfoEntry* _pThread) noexcept 81 | { 82 | sigset_t set; 83 | sigemptyset(&set); 84 | sigaddset(&set, SIGUSR1); 85 | int signo; 86 | 87 | for (;;) 88 | { 89 | if (_pThread->pfnCallback) 90 | { 91 | _pThread->pfnCallback(_pThread->pUserData); 92 | _pThread->pfnCallback = nullptr; 93 | _pThread->pUserData = nullptr; 94 | } 95 | 96 | for (;;) 97 | { 98 | auto _pTask = oPendingTaskQueue.Pop(); 99 | if (!_pTask) 100 | break; 101 | 102 | _pTask->pfnCallback(_pTask->pUserData); 103 | 104 | Delete(_pTask); 105 | } 106 | 107 | 108 | _pThread->pThreadPool->oIdleThreadQueue.Push(_pThread); 109 | 110 | pthread_sigmask(SIG_SETMASK, &set, nullptr); 111 | if (sigwait(&set, &signo) != 0) 112 | { 113 | break; 114 | } 115 | 116 | if (signo != SIGUSR1) 117 | break; 118 | } 119 | 120 | Sync::Decrement(&uThreadCount); 121 | Delete(_pThread); 122 | pthread_detach(pthread_self()); 123 | return nullptr; 124 | } 125 | 126 | ThreadPool* __YYAPI ThreadPool::Get() noexcept 127 | { 128 | static ThreadPool s_ThreadPool; 129 | return &s_ThreadPool; 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /Base/Threading/ThreadPoolForLinux.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #pragma pack(push, __YY_PACKING) 9 | 10 | namespace YY::Base::Threading 11 | { 12 | typedef void(__YYAPI* ThreadPoolSimpleCallback)(void* _pUserData); 13 | 14 | struct ThreadPoolTaskEntry 15 | { 16 | ThreadPoolSimpleCallback pfnCallback = nullptr; 17 | void* pUserData = nullptr; 18 | }; 19 | 20 | class ThreadPool; 21 | 22 | struct ThreadInfoEntry 23 | { 24 | ThreadInfoEntry* pNext = nullptr; 25 | pthread_t hThread = 0; 26 | ThreadPoolSimpleCallback pfnCallback = nullptr; 27 | void* pUserData = nullptr; 28 | ThreadPool* pThreadPool = nullptr; 29 | }; 30 | 31 | class ThreadPool 32 | { 33 | private: 34 | InterlockedSingleLinkedList oIdleThreadQueue; 35 | InterlockedQueue oPendingTaskQueue; 36 | 37 | volatile uint32_t uThreadCount = 0; 38 | 39 | constexpr ThreadPool() = default; 40 | 41 | public: 42 | template 43 | static HRESULT __YYAPI PostTaskInternalWithoutAddRef(_In_ Task* _pTask) noexcept 44 | { 45 | return Get()->ExecuteTask( 46 | [](_In_ void* _pUserData) 47 | { 48 | auto _pTask = reinterpret_cast(_pUserData); 49 | _pTask->operator()(); 50 | }, 51 | _pTask); 52 | } 53 | 54 | template 55 | static HRESULT __YYAPI PostTaskInternal(_In_ Task* _pTask) noexcept 56 | { 57 | _pTask->AddRef(); 58 | auto _hr = Get()->ExecuteTask( 59 | [](_In_ void* _pUserData) 60 | { 61 | auto _pTask = reinterpret_cast(_pUserData); 62 | _pTask->operator()(); 63 | _pTask->Release(); 64 | }, 65 | _pTask); 66 | 67 | if (FAILED(_hr)) 68 | { 69 | _pTask->Release(); 70 | } 71 | return _hr; 72 | } 73 | 74 | private: 75 | void* TaskExecuteRoutine(ThreadInfoEntry* _pThread) noexcept; 76 | 77 | static _Ret_notnull_ ThreadPool* __YYAPI Get() noexcept; 78 | 79 | HRESULT __YYAPI ExecuteTask(_In_ ThreadPoolSimpleCallback _pfnCallback, _In_opt_ void* _pUserData) noexcept; 80 | }; 81 | } 82 | 83 | namespace YY 84 | { 85 | using namespace YY::Base::Threading; 86 | } 87 | 88 | #pragma pack(pop) 89 | -------------------------------------------------------------------------------- /Base/Threading/ThreadPoolForWindows.cpp: -------------------------------------------------------------------------------- 1 | #include "ThreadPoolForWindows.h" 2 | 3 | __YY_IGNORE_INCONSISTENT_ANNOTATION_FOR_FUNCTION() 4 | 5 | namespace YY 6 | { 7 | namespace Base 8 | { 9 | namespace Threading 10 | { 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /Base/Threading/ThreadPoolForWindows.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #pragma pack(push, __YY_PACKING) 7 | 8 | namespace YY 9 | { 10 | namespace Base 11 | { 12 | namespace Threading 13 | { 14 | class ThreadPool 15 | { 16 | public: 17 | template 18 | static HRESULT __YYAPI PostTaskInternalWithoutAddRef(_In_ Task* _pTask) noexcept 19 | { 20 | auto _bRet = TrySubmitThreadpoolCallback( 21 | [](_Inout_ PTP_CALLBACK_INSTANCE _pInstance, 22 | _In_ PVOID _pContext) 23 | { 24 | auto _pTask = reinterpret_cast(_pContext); 25 | _pTask->operator()(); 26 | }, 27 | _pTask, 28 | nullptr); 29 | 30 | return _bRet ? S_OK : HRESULT_From_LSTATUS(GetLastError()); 31 | } 32 | 33 | template 34 | static HRESULT __YYAPI PostTaskInternal(_In_ Task* _pTask) noexcept 35 | { 36 | _pTask->AddRef(); 37 | auto _bRet = TrySubmitThreadpoolCallback( 38 | [](_Inout_ PTP_CALLBACK_INSTANCE _pInstance, 39 | _In_ PVOID _pContext) 40 | { 41 | auto _pTask = reinterpret_cast(_pContext); 42 | _pTask->operator()(); 43 | _pTask->Release(); 44 | }, 45 | _pTask, 46 | nullptr); 47 | 48 | if (!_bRet) 49 | { 50 | auto _hr = HRESULT_From_LSTATUS(GetLastError()); 51 | _pTask->Release(); 52 | return _hr; 53 | } 54 | 55 | return S_OK; 56 | } 57 | }; 58 | } 59 | } 60 | } 61 | 62 | namespace YY 63 | { 64 | using namespace YY::Base::Threading; 65 | } 66 | 67 | #pragma pack(pop) 68 | -------------------------------------------------------------------------------- /Base/Threading/ThreadTaskRunnerImpl.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #pragma pack(push, __YY_PACKING) 14 | 15 | namespace YY 16 | { 17 | namespace Base 18 | { 19 | namespace Threading 20 | { 21 | class ThreadTaskRunnerBaseImpl 22 | : public ThreadTaskRunner 23 | { 24 | public: 25 | virtual uintptr_t __YYAPI RunTaskRunnerLoop() = 0; 26 | }; 27 | 28 | class ThreadTaskRunnerImpl 29 | : public ThreadTaskRunnerBaseImpl 30 | , public ThreadPoolTimerManger 31 | , public ThreadPoolWaitMangerForSingleThreading 32 | { 33 | private: 34 | InterlockedQueue oTaskQueue; 35 | 36 | // |uWeakupCount| bStopWakeup | bPushLock | 37 | // | 31 ~ 2 | 1 | 0 | 38 | union 39 | { 40 | volatile uint32_t uWakeupCountAndPushLock; 41 | struct 42 | { 43 | volatile uint32_t bPushLock : 1; 44 | volatile uint32_t bStopWakeup : 1; 45 | volatile uint32_t bInterrupt : 1; 46 | volatile uint32_t bBackgroundLoop : 1; 47 | uint32_t uWakeupCount : 28; 48 | }; 49 | }; 50 | enum : uint32_t 51 | { 52 | LockedQueuePushBitIndex = 0, 53 | StopWakeupBitIndex, 54 | InterruptBitIndex, 55 | BackgroundLoopIndex, 56 | WakeupCountStartBitIndex, 57 | StopWakeupRaw = 1 << StopWakeupBitIndex, 58 | InterruptRaw = 1 << InterruptBitIndex, 59 | BackgroundLoopRaw = 1 << BackgroundLoopIndex, 60 | WakeupOnceRaw = 1 << WakeupCountStartBitIndex, 61 | UnlockQueuePushLockBitAndWakeupOnceRaw = WakeupOnceRaw - (1u << LockedQueuePushBitIndex), 62 | TerminateTaskRunnerRaw = StopWakeupRaw | InterruptRaw, 63 | }; 64 | 65 | volatile uint32_t uThreadId; 66 | uString szThreadDescription; 67 | 68 | public: 69 | ThreadTaskRunnerImpl(_In_ uint32_t _uThreadId = Threading::GetCurrentThreadId(), _In_ bool _bBackgroundLoop = false, uString _szThreadDescription = uString()); 70 | 71 | /// 72 | /// 从线程池借用一个线程,执行TaskRunner。 73 | /// 74 | /// 75 | // ThreadTaskRunnerImpl(_In_ uint32_t _uTaskRunnerId); 76 | 77 | ThreadTaskRunnerImpl(const ThreadTaskRunnerImpl&) = delete; 78 | 79 | ~ThreadTaskRunnerImpl(); 80 | 81 | ThreadTaskRunnerImpl& operator=(const ThreadTaskRunnerImpl&) = delete; 82 | 83 | ///////////////////////////////////////////////////// 84 | // TaskRunner 85 | virtual TaskRunnerStyle __YYAPI GetStyle() const noexcept override; 86 | 87 | HRESULT __YYAPI Join(TimeSpan _nWaitTimeOut) noexcept override; 88 | 89 | HRESULT __YYAPI Interrupt() noexcept override; 90 | 91 | ///////////////////////////////////////////////////// 92 | // ThreadTaskRunner 93 | 94 | virtual uint32_t __YYAPI GetThreadId() override; 95 | 96 | // 97 | //////////////////////////////////////////////////// 98 | 99 | void __YYAPI EnableWakeup(_In_ bool _bEnable); 100 | 101 | void __YYAPI operator()(); 102 | 103 | uintptr_t __YYAPI RunTaskRunnerLoop() override; 104 | 105 | private: 106 | HRESULT __YYAPI PostTaskInternal(_In_ RefPtr _pTask) override; 107 | 108 | HRESULT __YYAPI SetTimerInternal(_In_ RefPtr _pTask) override; 109 | 110 | HRESULT __YYAPI SetWaitInternal(_In_ RefPtr _pTask) override; 111 | 112 | void __YYAPI DispatchTimerTask(RefPtr _pTimerTask) override; 113 | 114 | void __YYAPI DispatchWaitTask(RefPtr _pWaitTask) override; 115 | 116 | void __YYAPI CleanupTaskQueue() noexcept; 117 | 118 | HRESULT __YYAPI Wakeup() noexcept; 119 | 120 | uintptr_t __YYAPI RunUIMessageLoop(); 121 | 122 | /// 123 | /// 运行后台循环,改模式UI相关处理极为滞后! 124 | /// 125 | /// 126 | uintptr_t __YYAPI RunBackgroundLoop(); 127 | }; 128 | } 129 | } 130 | } // namespace YY 131 | 132 | #pragma pack(pop) 133 | -------------------------------------------------------------------------------- /Base/Utils/FileInfo.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | __YY_IGNORE_INCONSISTENT_ANNOTATION_FOR_FUNCTION() 7 | 8 | namespace YY 9 | { 10 | namespace Base 11 | { 12 | namespace Utils 13 | { 14 | HRESULT __YYAPI GetFileVersion(LPCWSTR _szFilePath, Version* _pVersion) noexcept 15 | { 16 | _pVersion->uInternalValue = 0; 17 | auto _hFileMoudle = LoadLibraryExW(_szFilePath, NULL, LOAD_LIBRARY_AS_DATAFILE); 18 | if (!_hFileMoudle) 19 | return HRESULT_From_LSTATUS(GetLastError()); 20 | 21 | auto _lStatus = GetFileVersion(_hFileMoudle, _pVersion); 22 | FreeLibrary(_hFileMoudle); 23 | return _lStatus; 24 | } 25 | 26 | HRESULT __YYAPI GetFileVersion(HMODULE _hMoudle, Version* _pVersion) noexcept 27 | { 28 | _pVersion->uInternalValue = 0; 29 | __try 30 | { 31 | HRSRC _hRsrcVersion = FindResourceExW(_hMoudle, RT_VERSION, MAKEINTRESOURCE(1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)); 32 | 33 | if (_hRsrcVersion == NULL) 34 | { 35 | return HRESULT_From_LSTATUS(GetLastError()); 36 | } 37 | 38 | HGLOBAL _hGlobal = LoadResource(_hMoudle, _hRsrcVersion); 39 | if (_hGlobal == NULL) 40 | { 41 | return HRESULT_From_LSTATUS(GetLastError()); 42 | } 43 | 44 | VS_FIXEDFILEINFO* _pFileInfo = NULL; 45 | UINT _cbFileInfo; 46 | #ifndef _ATL_XP_TARGETING 47 | if (!VerQueryValueW(_hGlobal, L"\\", (LPVOID*)&_pFileInfo, &_cbFileInfo)) 48 | { 49 | return HRESULT_From_LSTATUS(GetLastError()); 50 | } 51 | #else 52 | // XP系统不允许直接调用,不然会触发内存非法访问。所以先复制到一个内存块上 53 | const DWORD _cbFileInfoBuffer = SizeofResource(_hMoudle, _hRsrcVersion); 54 | void* _pFileInfoBuffer = alloca(_cbFileInfoBuffer); 55 | 56 | memcpy(_pFileInfoBuffer, _hGlobal, _cbFileInfoBuffer); 57 | 58 | if (!VerQueryValueW(_pFileInfoBuffer, L"\\", (LPVOID*)&_pFileInfo, &_cbFileInfo)) 59 | { 60 | return HRESULT_From_LSTATUS(GetLastError()); 61 | } 62 | #endif 63 | 64 | _pVersion->uLowPart = _pFileInfo->dwFileVersionLS; 65 | _pVersion->uHightPart = _pFileInfo->dwFileVersionMS; 66 | return S_OK; 67 | } 68 | //抓取EXCEPTION_IN_PAGE_ERROR异常,防止IO问题导致程序崩溃。 69 | __except ((GetExceptionCode() == EXCEPTION_IN_PAGE_ERROR || GetExceptionCode() == 0xC000009C) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) 70 | { 71 | return HRESULT_From_LSTATUS(ERROR_DISK_OPERATION_FAILED); 72 | } 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /Base/Utils/SystemInfo.cpp: -------------------------------------------------------------------------------- 1 | #define _Disallow_YY_KM_Namespace 2 | 3 | #include 4 | 5 | #define WIN32_NO_STATUS 6 | #include 7 | 8 | namespace YY 9 | { 10 | namespace Base 11 | { 12 | namespace Utils 13 | { 14 | #if defined(_WIN32) 15 | Version __YYAPI YY::Base::Utils::GetOperatingSystemVersion() noexcept 16 | { 17 | const auto _pPeb = ((TEB*)NtCurrentTeb())->ProcessEnvironmentBlock; 18 | Version _uOsVersion(uint16_t(_pPeb->OSMajorVersion), uint16_t(_pPeb->OSMinorVersion), uint16_t(_pPeb->OSBuildNumber)); 19 | 20 | if (_uOsVersion == kWindowsNT5_1) 21 | { 22 | switch (HIBYTE(_pPeb->OSCSDVersion)) 23 | { 24 | case 0: 25 | break; 26 | case 1: 27 | _uOsVersion.uRevision = 1106; 28 | break; 29 | case 2: 30 | _uOsVersion.uRevision = 2180; 31 | break; 32 | case 3: 33 | default: 34 | _uOsVersion.uRevision = 5512; 35 | break; 36 | } 37 | } 38 | else if(_uOsVersion == kWindowsNT5_2) 39 | { 40 | switch (HIBYTE(_pPeb->OSCSDVersion)) 41 | { 42 | case 0: 43 | break; 44 | case 1: 45 | default: 46 | _uOsVersion.uRevision = 1830; 47 | break; 48 | } 49 | } 50 | 51 | return _uOsVersion; 52 | } 53 | #endif 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | native,Version=v0.0 10 | 11 | win;win-x86;win-x64;win-arm;win-arm64 12 | 13 | 14 | 15 | 16 | $([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../')) 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /Directory.Build.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | true 7 | 8 | 9 | 10 | $([MSBuild]::GetPathOfFileAbove('Directory.Build.targets', '$(MSBuildThisFileDirectory)../')) 11 | 12 | 13 | 14 | MultiThreadedDebugDLL 15 | 16 | 17 | MultiThreadedDLL 18 | 19 | 20 | 21 | 22 | MultiThreadedDebug 23 | 24 | 25 | MultiThreaded 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Example/Example.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #if defined(_WIN32) 4 | #include "resource.h" 5 | #endif 6 | -------------------------------------------------------------------------------- /Example/Example.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chuyu-Team/MegaUI/142dfb135d8df5fba4c3591a5e353ed7568322de/Example/Example.ico -------------------------------------------------------------------------------- /Example/Example.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Chuyu-Team/MegaUI/142dfb135d8df5fba4c3591a5e353ed7568322de/Example/Example.rc -------------------------------------------------------------------------------- /Example/Example.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | 头文件 20 | 21 | 22 | 头文件 23 | 24 | 25 | 头文件 26 | 27 | 28 | 头文件 29 | 30 | 31 | 32 | 33 | 源文件 34 | 35 | 36 | 37 | 38 | 资源文件 39 | 40 | 41 | 42 | 43 | 资源文件 44 | 45 | 46 | 资源文件 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /Example/Example.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |