├── .gitignore ├── LICENSE.md ├── Makefile ├── Makefile.exe-rule ├── Makefile.flags ├── README.md ├── Windows.Foundation.h.patch ├── Windows.System.h.patch ├── base.h.patch ├── example ├── Makefile └── naughtyfication.cpp ├── include ├── WindowsNumerics.impl.h └── winrt │ └── yolort_impl │ ├── corostub.hpp │ └── yolo.ipp └── test ├── Makefile ├── Windows_8_1.System.cpp ├── intrin.cpp └── test.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | /microsoft.windows.cppwinrt.x.x.x.x.nupkg 2 | /bin/cppwinrt.exe 3 | /winrt 4 | /patched 5 | /include/winrt/yolort_impl/winrt 6 | /include/winrt/*.* 7 | /test/*.exe 8 | /test/nonbloated.ok 9 | /test/all.ok 10 | /example/*.exe 11 | /*.html 12 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | Copyright © 2021, [mjk](https://github.com/Yuubi-san) 3 | All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | CPPWINRT_INPUT = local 3 | PREFIX = /usr/local 4 | 5 | rwildcard = $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) \ 6 | $(filter $(subst *,%,$2),$d)) 7 | 8 | originals := $(call rwildcard,winrt/,*.h) 9 | results := $(originals:%=include/winrt/yolort_impl/%) 10 | patches := $(wildcard *.patch) 11 | patched_intermediates := $(patches:%.patch=patched/%) 12 | patched_results := $(patsubst %.patch, include/winrt/yolort_impl/winrt/%, \ 13 | $(patches)) 14 | apis := $(wildcard winrt/*.h) 15 | wrappers := $(apis:%=include/%) 16 | 17 | .PHONY: default 18 | default: results wrappers 19 | .PHONY: results 20 | results: $(results) 21 | .PHONY: wrappers 22 | wrappers: $(wrappers) 23 | 24 | $(patched_results): include/winrt/yolort_impl/winrt/%: patched/% 25 | $(results): include/winrt/yolort_impl/%: % 26 | mkdir --parents `echo "$@" | egrep --only-matching "^([^/]+/)+"` 27 | @if test -f "$(<:winrt/%=patched/%)"; then \ 28 | echo cp "$(<:winrt/%=patched/%)" "$@"; \ 29 | cp "$(<:winrt/%=patched/%)" "$@"; \ 30 | else \ 31 | echo cp "$<" "$@"; \ 32 | cp "$<" "$@"; \ 33 | fi 34 | @echo "[regex-fu censored to protect the innocent]" 35 | @egrep --only-matching "^WINRT_IMPL_LINK\([^,]+" "winrt/base.h" | \ 36 | sed --regexp-extended "s/^.+\((.+)$$/-es\/WINRT_IMPL_\1\/\1\//" | \ 37 | xargs sed "$@" --in-place 38 | 39 | .PHONY: patched_intermediates 40 | patched_intermediates: $(patched_intermediates) 41 | $(patched_intermediates): patched/%: winrt/% %.patch 42 | @mkdir --parents `echo "$@" | egrep --only-matching "^([^/]+/)+"` 43 | patch "$<" "$(<:winrt/%=%.patch)" -o "$@" 44 | 45 | $(wrappers): include/%: % 46 | @echo "echo \$$cxx_code_here > $@" 47 | @echo "#define HEADER_IMPL <$(@:include/%=winrt/yolort_impl/%)>" > "$@" && \ 48 | echo "#include " >> "$@" && \ 49 | echo "#undef HEADER_IMPL" >> "$@" 50 | 51 | .PHONY: clean 52 | clean: 53 | $(RM) $(results) $(patched_intermediates) $(wrappers) *.html 54 | rmdir --ignore-fail-on-non-empty patched 55 | 56 | 57 | 58 | .PHONY: originals 59 | originals: 60 | PATH="bin:$$PATH" cppwinrt -verbose -overwrite -in "$(CPPWINRT_INPUT)" -out . 61 | 62 | .PHONY: cleaner 63 | cleaner: clean 64 | $(RM) -r winrt 65 | 66 | 67 | 68 | bin/cppwinrt.exe: microsoft.windows.cppwinrt.x.x.x.x.nupkg bin 69 | unzip "$<" "$@" 70 | chmod +x "$@" 71 | 72 | bin: 73 | mkdir bin 74 | 75 | microsoft.windows.cppwinrt.x.x.x.x.nupkg: 76 | curl --location "https://www.nuget.org/api/v2/package/\ 77 | Microsoft.Windows.CppWinRT/$(CPPWINRT_VERSION)" > $@ 78 | 79 | .PHONY: pristine 80 | pristine: cleaner 81 | $(RM) bin/cppwinrt.exe microsoft.windows.cppwinrt.x.x.x.x.nupkg 82 | rmdir --ignore-fail-on-non-empty bin 83 | 84 | 85 | 86 | .PHONY: install 87 | install: 88 | cp -r \ 89 | include/winrt \ 90 | include/WindowsNumerics.impl.h \ 91 | "$PREFIX/include" 92 | 93 | 94 | 95 | # development stuff 96 | 97 | .PHONY: patches 98 | patches: $(patsubst patched/%, %-patch, $(wildcard patched/*)) 99 | 100 | .PHONY: %-patch 101 | %-patch: winrt/% 102 | (diff --unified \ 103 | --label="$<" "$<" \ 104 | --label="patched/$(@:-patch=)" "patched/$(@:-patch=)"; \ 105 | test $$? != 2) > $(@:-patch=.patch) 106 | 107 | 108 | %.html: %.md 109 | markdown "$<" > "$@" 110 | -------------------------------------------------------------------------------- /Makefile.exe-rule: -------------------------------------------------------------------------------- 1 | 2 | %.exe: %.cpp 3 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) "$<" -o "$@" $(LDLIBS) 4 | -------------------------------------------------------------------------------- /Makefile.flags: -------------------------------------------------------------------------------- 1 | 2 | override CPPFLAGS := -mcx16 -pipe -Wall -Wextra -Wpedantic -Wconversion \ 3 | -Wcast-align -Wformat=2 -Wstrict-overflow=5 \ 4 | -Wno-unknown-pragmas -fdiagnostics-color=always $(CPPFLAGS) 5 | 6 | override CXXFLAGS := -std=c++17 -Wsign-promo $(CXXFLAGS) 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YoloRT 2 | 3 | *It's not just a crutch, it's a legit wheelchair!* 4 | 5 | ## What this is 6 | 7 | Patches and scripts to make the C++ "binding" of Windows Runtime (WinRT) more 8 | C++ and less microsoft. In particular, to make it usable with MinGW. Little 9 | effort (if any) has been put into keeping the code consumable by MSVC (I'm not 10 | *against* the idea, but have neither MSVC nor the time). 11 | 12 | 13 | ## Why this exists 14 | 15 | 'Cause life is too short to upstream the fixes (again, not because I'm against 16 | it) or maintain a fork. 17 | 18 | 19 | ## Building 20 | 21 | These instructions assume you (1) don't have the original (MSVC-specific) winrt 22 | headers to apply the patches to and (2) want to generate said headers. 23 | 24 | ### Dependencies 25 | 26 | `make`, `cppwinrt`, coreutils, `grep`, `patch`, `sed`, `xargs`. See below for 27 | `cppwinrt`, the rest can be installed by invoking: 28 | 29 | * on Debian, `# apt install make coreutils grep patch sed findutils`; 30 | 31 | * on MSYS2, `# pacman --sync --needed make coreutils grep patch sed findutils`. 32 | 33 | #### `cppwinrt` (the generator) 34 | If you don't have (the desired version of) `cppwinrt` and don't want to / cannot 35 | build from [source](https://github.com/microsoft/cppwinrt), you can obtain it by 36 | invoking 37 | 38 | `$ make bin/cppwinrt.exe` 39 | 40 | This will download the latest build 41 | [from nuget.org](https://www.nuget.org/packages/Microsoft.Windows.CppWinRT/). 42 | You'll need `curl` and `unzip` commands (eponymous to packages). If latest 43 | doesn't work for you in the end, try 44 | 45 | `$ make CPPWINRT_VERSION=2.0.210122.3 bin/cppwinrt.exe` 46 | 47 | This will get you the latest (and currently the only) version the patches are 48 | known to be compatible with. 49 | 50 | ### Actual building 51 | 52 | ``` 53 | $ make originals 54 | $ make --jobs=$(nproc) 55 | ``` 56 | 57 | The fist command generates original (MSVC-specific) winrt headers from [windows 58 | metadata (.winmd)](https://docs.microsoft.com/en-us/uwp/winrt-cref/winmd-files) 59 | files. By default it looks for them in `$WINDIR/SysNative/WinMetadata` or maybe 60 | in `$WINDIR/System32/WinMetadata` or thereabouts. If needed, override this using 61 | the `CPPWINRT_INPUT` variable (see also `cppwinrt -help` for possible special 62 | values to use here). 63 | 64 | The second command populates the `include` directory with the final output: 65 | patched/wrapped winrt headers usable with MinGW. It can take some time. 66 | 67 | ### Testing 68 | 69 | It is highly recommended to run tests if you have some other combination than 70 | windows 8.1 x86-64 & cppwinrt 2.0.210122.3 & g++ 10: 71 | 72 | `$ (cd test && make --jobs=$(nproc))` 73 | 74 | You'll actually need MinGW for this. The package names in Debian are 75 | `g++-mingw-w64-{i686,x86-64}`, in MSYS2 they are `mingw-w64-{i686,x86_64}-gcc`. 76 | 77 | Right now, the testing procedure comprises, mostly: including each of the API 78 | headers into separate hello-world-ish programs, compiling and running them. It 79 | takes a while. Also, the XAML headers will eat all your RAM and ask for 80 | seconds; reduce `--jobs` then. 81 | 82 | ### Installation 83 | 84 | Finally, 85 | 86 | `# make install` 87 | 88 | to copy the headers to `$PREFIX/include`, where `$PREFIX` is `/usr/local` by 89 | default. 90 | 91 | 92 | ## Usage 93 | 94 | Currently requires a hacky incantation in the form of an option added to your 95 | preprocessor flags (`CPPFLAGS`): 96 | 97 | `-iquote /usr/local/include/winrt/yolort_impl` 98 | 99 | This assumes `/usr/local/include` is where you have the headers installed. If 100 | you have them in an unusual or project-specific place, don't forget to also add 101 | that place to `CPLUS_INCLUDE_PATH` or specify via the `-I` option. 102 | 103 | Otherwise, `#include ` as usual. 104 | 105 | 106 | ## What works 107 | 108 | The module unit (`winrt/winrt.ixx`) likely doesn't and, thus, isn't present in 109 | the final output. (Meh, GCC doesn't yet really have modules support anyway.) 110 | 111 | 112 | ## Examples 113 | 114 | See the [`example`](example/) subdir. Currently only a minimal working example 115 | of sending toast notifications is provided. To build, run `$ make` from within 116 | the directory. 117 | 118 | 119 | ## License 120 | 121 | [MIT](LICENSE.md) 122 | 123 | 124 | ## Contributing 125 | 126 | The most useful thing right now is to try this on as many projects, systems, 127 | architectures, cppwinrt versions and compilers as possible, and report any 128 | issues, including compiler warnings and deficiencies in good developer 129 | experience (DX?). 130 | -------------------------------------------------------------------------------- /Windows.Foundation.h.patch: -------------------------------------------------------------------------------- 1 | --- winrt/Windows.Foundation.h 2 | +++ patched/Windows.Foundation.h 3 | @@ -2921,6 +2921,7 @@ 4 | private: 5 | static fire_and_forget cancel_asynchronously(Async async) 6 | { 7 | +#ifdef WINRT_IMPL_COROUTINES 8 | co_await winrt::resume_background(); 9 | try 10 | { 11 | @@ -2929,6 +2930,10 @@ 12 | catch (hresult_error const&) 13 | { 14 | } 15 | +#else 16 | + static_assert( !sizeof(Async), "don't use me without coroutine support" ); 17 | + return {}; 18 | +#endif 19 | } 20 | }; 21 | 22 | @@ -3385,8 +3390,10 @@ 23 | 24 | #ifdef __cpp_lib_coroutine 25 | namespace std 26 | -#else 27 | +#elif __has_include() 28 | namespace std::experimental 29 | +#else 30 | +namespace corostub 31 | #endif 32 | { 33 | template 34 | @@ -3513,13 +3520,19 @@ 35 | template 36 | Windows::Foundation::IAsyncAction when_all(T... async) 37 | { 38 | +#ifdef WINRT_IMPL_COROUTINES 39 | (void(co_await async), ...); 40 | co_return; 41 | +#else 42 | + static_assert( !sizeof(std::tuple), "don't use me without coroutine support" ); 43 | + return {}; 44 | +#endif 45 | } 46 | 47 | template 48 | T when_any(T const& first, Rest const& ... rest) 49 | { 50 | +#ifdef WINRT_IMPL_COROUTINES 51 | static_assert(impl::has_category_v, "T must be WinRT async type such as IAsyncAction or IAsyncOperation."); 52 | static_assert((std::is_same_v && ...), "All when_any parameters must be the same type."); 53 | 54 | @@ -3554,6 +3567,10 @@ 55 | co_await resume_on_signal(shared->event.get()); 56 | impl::check_status_canceled(shared->status); 57 | co_return shared->result.GetResults(); 58 | +#else 59 | + static_assert( !sizeof(T), "don't use me without coroutine support" ); 60 | + return {}; 61 | +#endif 62 | } 63 | } 64 | #endif 65 | -------------------------------------------------------------------------------- /Windows.System.h.patch: -------------------------------------------------------------------------------- 1 | --- winrt/Windows.System.h 2 | +++ patched/Windows.System.h 3 | @@ -422,13 +422,36 @@ 4 | 5 | WINRT_EXPORT namespace winrt 6 | { 7 | + namespace Windows::System 8 | + { 9 | + /* These types are missing from the headers generated from windows 8.1, 10 | + so even just the interface alone of the following functions was broken. 11 | + Instead of simply deleting the functions, I added declarations of the 12 | + missing types (and only declarations -- so that the header doesn't break 13 | + on windows 10) just in case this all can somehow be useful. 14 | + The functions was turned into pseudo-templates so as to let them 15 | + pass the 1st phase of compilation with only declarations of the missing 16 | + types available. 17 | + */ 18 | + struct DispatcherQueue; 19 | + enum class DispatcherQueuePriority; 20 | + } 21 | + 22 | + template< 23 | + typename Q, 24 | + typename P = std::enable_if_t< 25 | + std::is_same_v, 26 | + Windows::System::DispatcherQueuePriority 27 | + >, 28 | + std::enable_if_t, int> = 0 29 | + > 30 | [[nodiscard]] inline auto resume_foreground( 31 | - Windows::System::DispatcherQueue const& dispatcher, 32 | - Windows::System::DispatcherQueuePriority const priority = Windows::System::DispatcherQueuePriority::Normal) noexcept 33 | + Q const& dispatcher, 34 | + P const priority = P::Normal) noexcept 35 | { 36 | struct awaitable 37 | { 38 | - awaitable(Windows::System::DispatcherQueue const& dispatcher, Windows::System::DispatcherQueuePriority const priority) noexcept : 39 | + awaitable(Q const& dispatcher, P const priority) noexcept : 40 | m_dispatcher(dispatcher), 41 | m_priority(priority) 42 | { 43 | @@ -454,8 +477,8 @@ 44 | } 45 | 46 | private: 47 | - Windows::System::DispatcherQueue const& m_dispatcher; 48 | - Windows::System::DispatcherQueuePriority const m_priority; 49 | + Q const& m_dispatcher; 50 | + P const m_priority; 51 | bool m_queued{}; 52 | }; 53 | 54 | @@ -463,7 +486,11 @@ 55 | }; 56 | 57 | #ifdef WINRT_IMPL_COROUTINES 58 | - inline auto operator co_await(Windows::System::DispatcherQueue const& dispatcher) 59 | + template< 60 | + typename Q, 61 | + std::enable_if_t, int> = 0 62 | + > 63 | + inline auto operator co_await(Q const& dispatcher) 64 | { 65 | return resume_foreground(dispatcher); 66 | } 67 | -------------------------------------------------------------------------------- /base.h.patch: -------------------------------------------------------------------------------- 1 | --- winrt/base.h 2 | +++ patched/base.h 3 | @@ -27,8 +27,12 @@ 4 | 5 | #if __has_include() 6 | #define WINRT_IMPL_NUMERICS 7 | +#if __has_include() 8 | +// mingw 6.0.0 headers don't have this and it *seems* unused in winrt, but 9 | +// leaving it in just in case: 10 | #include 11 | #endif 12 | +#endif 13 | 14 | #ifdef __cpp_lib_coroutine 15 | 16 | @@ -43,7 +47,7 @@ 17 | using suspend_never = std::suspend_never; 18 | } 19 | 20 | -#else 21 | +#elif __has_include() 22 | 23 | #include 24 | 25 | @@ -56,6 +60,19 @@ 26 | using suspend_never = std::experimental::suspend_never; 27 | } 28 | 29 | +#else 30 | + 31 | +#include 32 | + 33 | +namespace winrt::impl 34 | +{ 35 | + template 36 | + using coroutine_handle = corostub::coroutine_handle; 37 | + 38 | + using suspend_always = corostub::suspend_always; 39 | + using suspend_never = corostub::suspend_never; 40 | +} 41 | + 42 | #endif 43 | 44 | #ifdef _DEBUG 45 | @@ -355,6 +372,7 @@ 46 | __declspec(selectany) void(__stdcall* winrt_resume_handler)(void const* token) noexcept {}; 47 | __declspec(selectany) int32_t(__stdcall* winrt_activation_handler)(void* classId, winrt::guid const& iid, void** factory) noexcept {}; 48 | 49 | +namespace winrt { 50 | extern "C" 51 | { 52 | void* __stdcall WINRT_IMPL_LoadLibraryW(wchar_t const* name) noexcept; 53 | @@ -431,6 +449,7 @@ 54 | int32_t __stdcall WINRT_CanUnloadNow() noexcept; 55 | int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept; 56 | } 57 | +} // namespace winrt 58 | 59 | #ifdef _M_HYBRID 60 | #define WINRT_IMPL_LINK(function, count) __pragma(comment(linker, "/alternatename:#WINRT_IMPL_" #function "@" #count "=#" #function "@" #count)) 61 | @@ -2751,7 +2770,7 @@ 62 | } 63 | 64 | auto header = precreate_hstring_on_heap(length); 65 | - memcpy_s(header->buffer, sizeof(wchar_t) * length, value, sizeof(wchar_t) * length); 66 | + yolort::memcpy(header->buffer, sizeof(wchar_t) * length, value, sizeof(wchar_t) * length); 67 | return header; 68 | } 69 | 70 | @@ -3102,6 +3121,12 @@ 71 | { 72 | return reinterpret_cast(object); 73 | } 74 | + 75 | + template 76 | + operator R () const noexcept 77 | + { 78 | + return static_cast(*this); 79 | + } 80 | }; 81 | 82 | template 83 | @@ -3459,8 +3484,8 @@ 84 | return{}; 85 | } 86 | hstring_builder text(size); 87 | - memcpy_s(text.data(), left.size() * sizeof(wchar_t), left.data(), left.size() * sizeof(wchar_t)); 88 | - memcpy_s(text.data() + left.size(), right.size() * sizeof(wchar_t), right.data(), right.size() * sizeof(wchar_t)); 89 | + yolort::memcpy(text.data(), left.size() * sizeof(wchar_t), left.data(), left.size() * sizeof(wchar_t)); 90 | + yolort::memcpy(text.data() + left.size(), right.size() * sizeof(wchar_t), right.data(), right.size() * sizeof(wchar_t)); 91 | return text.to_hstring(); 92 | } 93 | } 94 | @@ -8112,7 +8137,9 @@ 95 | 96 | static time_point from_time_t(time_t time) noexcept 97 | { 98 | - return from_sys(std::chrono::system_clock::from_time_t(time)); 99 | + return std::chrono::time_point_cast( 100 | + from_sys(std::chrono::system_clock::from_time_t(time)) 101 | + ); 102 | } 103 | 104 | static file_time to_file_time(time_point const& time) noexcept 105 | @@ -8392,7 +8419,7 @@ 106 | coroutine_handle<> m_handle; 107 | }; 108 | auto state = std::make_unique(context, handle); 109 | - submit_threadpool_callback([](void*, void* p) 110 | + submit_threadpool_callback([](void*, void* p) __stdcall 111 | { 112 | std::unique_ptr state{ static_cast(p) }; 113 | resume_apartment_sync(state->m_context, state->m_handle); 114 | @@ -8949,8 +8976,10 @@ 115 | 116 | #ifdef __cpp_lib_coroutine 117 | namespace std 118 | -#else 119 | +#elif __has_include() 120 | namespace std::experimental 121 | +#else 122 | +namespace corostub 123 | #endif 124 | { 125 | template 126 | -------------------------------------------------------------------------------- /example/Makefile: -------------------------------------------------------------------------------- 1 | 2 | include ../Makefile.exe-rule 3 | include ../Makefile.flags 4 | override CPPFLAGS += -I ../include -iquote ../include/winrt/yolort_impl 5 | override LDLIBS += -lole32 -loleaut32 6 | 7 | srcs := $(wildcard *.cpp) 8 | exes := $(srcs:.cpp=.exe) 9 | 10 | .PHONY: examples 11 | examples: $(exes) 12 | 13 | $(exes): 14 | 15 | naughtyfication.exe: ../include/winrt/Windows.Data.Xml.Dom.h ../include/winrt/Windows.UI.Notifications.h 16 | 17 | .PHONY: clean 18 | clean: 19 | $(RM) $(exes) 20 | -------------------------------------------------------------------------------- /example/naughtyfication.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using std::cerr; 10 | static std::wbuffer_convert> 11 | converting_stderr_buf{ cerr.rdbuf() }; 12 | std::wostream wcerr{ &converting_stderr_buf }; 13 | 14 | template 15 | struct wflusher { ~wflusher(){ Stream.flush(); } }; 16 | static wflusher wcerr_flusher; 17 | 18 | using std::wstring_view; 19 | using namespace std::string_view_literals; 20 | 21 | 22 | int main() try 23 | { 24 | using namespace winrt::Windows::UI::Notifications; 25 | using mgr = ToastNotificationManager; 26 | 27 | auto toastdoc = mgr::GetTemplateContent( ToastTemplateType::ToastText01 ); 28 | toastdoc.SelectSingleNode(L"//text").InnerText(L"hello world"); 29 | 30 | wcerr <<"markup: LR\"("<< wstring_view{toastdoc.GetXml()} <<")\"\n"; 31 | 32 | const auto aumid = L"mjk.YoloRT.NaughtyExample"sv; //application user model ID 33 | mgr::CreateToastNotifier(aumid).Show( ToastNotification{toastdoc} ); 34 | 35 | /* 36 | For the notification to be shown, the AUMID needs to have been registered 37 | in the system, which is currently outside the scope of this example. One 38 | (the only?) way to do that is putting an AUMID-bearing shortcut into the 39 | start menu. See, e.g., https://docs.microsoft.com/en-us/previous-versions\ 40 | /windows/desktop/legacy/hh802762(v=vs.85) 41 | */ 42 | } 43 | catch ( const winrt::hresult_error &e ) 44 | { 45 | wcerr <<"error 0x"<< std::hex << e.code() <<": "<< 46 | wstring_view{e.message()} << '\n'; 47 | return 1; 48 | } 49 | catch ( const std::exception &e ) 50 | { 51 | cerr << e.what() << '\n'; 52 | return 1; 53 | } 54 | -------------------------------------------------------------------------------- /include/WindowsNumerics.impl.h: -------------------------------------------------------------------------------- 1 | 2 | // This file is merely to cheaply plug compilability holes in windows 10 winrt 3 | // APIs that use types from the non-free(?) WindowsNumerics library 4 | // unconditionally, i. e., unguarded by __has_include. 5 | // MinGW will probably have a complete implementation in the future, at which 6 | // point this file may turn into a part of the problem it solves now (FIXME). 7 | 8 | #ifndef YOLORT_WINDOWSNUMERICS_IMPL_H 9 | #define YOLORT_WINDOWSNUMERICS_IMPL_H 10 | 11 | #include 12 | #include 13 | 14 | _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ 15 | { 16 | // These definitions make sense to *me*, but one cannot be sure microsoft 17 | // didn't add proprietary extensions to mathematics. 18 | 19 | #define define_mathy_type(name, T, N, ...) \ 20 | struct name \ 21 | { \ 22 | private: \ 23 | constexpr auto _tie() const \ 24 | { \ 25 | auto members = std::tie( __VA_ARGS__ ); \ 26 | static_assert( std::tuple_size_v == (N) ); \ 27 | return members; \ 28 | } \ 29 | public: \ 30 | T __VA_ARGS__; \ 31 | friend constexpr auto operator==( const name &l, const name &r ) \ 32 | { return l._tie() == r._tie(); } \ 33 | } 34 | 35 | #define define_vector_type(T,N,...) define_mathy_type(T##N, T, N, __VA_ARGS__) 36 | define_vector_type(float,2,x,y); 37 | define_vector_type(float,3,x,y,z); 38 | define_vector_type(float,4,x,y,z,w); 39 | #undef define_vector_type 40 | 41 | #define define_matrix_type(T,N,M) struct T##N##x##M : std::array {} 42 | define_matrix_type(float,2,2); 43 | define_matrix_type(float,2,3); 44 | define_matrix_type(float,2,4); 45 | define_matrix_type(float,3,2); 46 | define_matrix_type(float,3,3); 47 | define_matrix_type(float,3,4); 48 | define_matrix_type(float,4,2); 49 | define_matrix_type(float,4,3); 50 | define_matrix_type(float,4,4); 51 | #undef define_matrix_type 52 | 53 | define_mathy_type(quaternion, float, 4, a,b,c,d ); 54 | define_mathy_type(plane, float, 3+1, x,y,z, d ); 55 | 56 | #undef define_mathy_type 57 | } 58 | _WINDOWS_NUMERICS_END_NAMESPACE_ 59 | 60 | #endif // YOLORT_WINDOWSNUMERICS_IMPL_H 61 | -------------------------------------------------------------------------------- /include/winrt/yolort_impl/corostub.hpp: -------------------------------------------------------------------------------- 1 | 2 | #ifndef YOLORT_IMPL_COROSTUB_HPP 3 | #define YOLORT_IMPL_COROSTUB_HPP 4 | 5 | namespace corostub 6 | { 7 | template 8 | struct coroutine_handle 9 | { 10 | coroutine_handle() = default; 11 | coroutine_handle( decltype(nullptr) ); 12 | void *address() const; 13 | void operator()() const {} 14 | operator bool() const; 15 | static coroutine_handle<> from_address( ... ); 16 | }; 17 | 18 | struct suspend_always {}; 19 | struct suspend_never {}; 20 | 21 | template 22 | struct coroutine_traits; 23 | } 24 | 25 | #endif // YOLORT_IMPL_COROSTUB_HPP 26 | 27 | -------------------------------------------------------------------------------- /include/winrt/yolort_impl/yolo.ipp: -------------------------------------------------------------------------------- 1 | 2 | // It is safe to assume that every other line 3 | // here has UB (but refer to the filename). 4 | 5 | #ifndef YOLORT_WRAP_IPP 6 | #define YOLORT_WRAP_IPP 7 | 8 | // just microsoft things 9 | #if __has_include() 10 | #include // for __cpp_lib_coroutine in winrt/base.h 11 | #endif 12 | #include // for memcmp in winrt/base.h 13 | #include 14 | using std::nullptr_t; // for unqualified nullptr_t in winrt/base.h 15 | #include // for UINT_MAX in winrt/base.h 16 | #include 17 | 18 | namespace yolort 19 | { 20 | inline void memcpy( 21 | void * const dst, 22 | std::size_t const dstsize [[maybe_unused]], 23 | const void *const src, 24 | std::size_t const srcsize ) noexcept 25 | { 26 | assert( dst ); 27 | assert( src ); 28 | assert( srcsize <= dstsize ); 29 | std::memcpy( dst, src, srcsize ); 30 | } 31 | } 32 | 33 | 34 | #include 35 | // work around the `undefined reference to _ReturnAddress` for now... 36 | #define _ReturnAddress() __builtin_return_address(0) 37 | #include 38 | // mingw apparently doesn't(?) yet implement this one as of gcc 10: 39 | template 40 | inline unsigned char _InterlockedCompareExchange128( 41 | std::int64_t volatile *const pcurrent, 42 | std::int64_t const desired_hi, 43 | std::int64_t const desired_lo, 44 | std::int64_t *const pexpected ) noexcept 45 | { 46 | #ifdef _WIN64 47 | return __sync_bool_compare_and_swap 48 | ( 49 | reinterpret_cast<__int128_t volatile *>(pcurrent), 50 | *reinterpret_cast<__int128_t *>(pexpected), 51 | __int128_t{desired_hi} << 64 | desired_lo 52 | ); 53 | #else 54 | static_assert( !sizeof(Dummy), "not implemented for 32-bit targets" ); 55 | return {}; 56 | #endif 57 | } 58 | 59 | 60 | // just libstdc++ things 61 | 62 | #include 63 | #if !defined(__cpp_lib_to_chars) or __cpp_lib_to_chars < 201611 64 | #include 65 | #include 66 | #include 67 | namespace std 68 | { 69 | // release the Kraken! 70 | 71 | #if __GNUC__ < 10 // maybe 9 already has this, dunno 72 | enum class chars_format 73 | { 74 | scientific = 0b001, 75 | fixed = 0b010, 76 | hex = 0b100, 77 | general = fixed | scientific, 78 | }; 79 | #endif 80 | 81 | template< 82 | typename Float, 83 | enable_if_t, int> = 0 84 | > 85 | inline to_chars_result to_chars( 86 | char *const first, char *const last, 87 | Float const value, 88 | chars_format const fmt [[maybe_unused]] ) noexcept 89 | { 90 | assert( fmt == chars_format::general ); 91 | try 92 | { 93 | ostringstream os; 94 | os << value; 95 | const auto &s = os.str(); 96 | if ( s.size() > static_cast(last-first) ) 97 | return { last, errc::value_too_large }; 98 | return { copy(s.begin(), s.end(), first), {} }; 99 | } 100 | catch ( ... ) 101 | { 102 | return { last, errc::value_too_large }; 103 | } 104 | } 105 | } 106 | #endif // __cpp_lib_to_chars 107 | 108 | #endif // YOLORT_WRAP_IPP 109 | 110 | 111 | #ifdef HEADER_IMPL 112 | #define __pragma(...) 113 | #pragma GCC diagnostic push 114 | #pragma GCC diagnostic ignored "-Wattributes" 115 | #pragma GCC diagnostic ignored "-Wunused-parameter" 116 | #pragma GCC diagnostic ignored "-Wconversion" 117 | #pragma GCC diagnostic ignored "-Wpedantic" 118 | #pragma GCC diagnostic ignored "-Wstrict-aliasing" 119 | // ^ warning: dereferencing type-punned pointer will break strict-aliasing 120 | // rules 121 | // if (result == *(int64_t*)¤t_value) 122 | // ^~~~~~~~~~~~~~~~~~~~~~~~ 123 | #pragma GCC diagnostic ignored "-Wclass-memaccess" 124 | // ^ warning: 'void* memset(void*, int, size_t)' clearing an object of type 125 | // 'struct winrt::com_array' with no trivial copy-assignment; 126 | // use value-initialization instead 127 | // Y U NO C++, MS?? 128 | #include HEADER_IMPL 129 | #pragma GCC diagnostic pop 130 | #undef __pragma 131 | #endif 132 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | 2 | include ../Makefile.exe-rule 3 | include ../Makefile.flags 4 | override CPPFLAGS += -I ../include -iquote ../include/winrt/yolort_impl 5 | 6 | apis := $(wildcard ../winrt/Windows.*.h) 7 | api_exes := $(apis:../winrt/%.h=%.exe) 8 | all_exes := intrin.exe $(api_exes) 9 | 10 | bloatastic_apis := \ 11 | $(wildcard ../winrt/Windows.ApplicationModel.Store.Preview*.h) \ 12 | $(wildcard ../winrt/Windows.UI.Xaml*.h) 13 | # bloatastic being roughly defined as "my 1-GB SBC catches fire compiling this" 14 | bloatastic_exes := $(bloatastic_apis:../winrt/%.h=%.exe) 15 | 16 | %.ok: 17 | for exe in $(filter %.exe, $?); do ./$$exe || exit 1; done 18 | touch $@ 19 | 20 | all.ok: nonbloated.ok $(bloatastic_exes) 21 | 22 | nonbloated.ok: $(filter-out $(bloatastic_exes), $(all_exes)) 23 | 24 | $(api_exes): %.exe: ../include/winrt/%.h ../include/winrt/yolort_impl/winrt/%.h ../include/winrt/yolort_impl/yolo.ipp test.cpp 25 | $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) "-DHEADER=$(@:%.exe=)" test.cpp -o $@ $(LDLIBS) 26 | 27 | intrin.exe: ../include/winrt/yolort_impl/yolo.ipp 28 | 29 | .PHONY: clean 30 | clean: 31 | $(RM) all.ok nonbloated.ok $(all_exes) 32 | -------------------------------------------------------------------------------- /test/Windows_8_1.System.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | enum class winrt::Windows::System::DispatcherQueuePriority : int32_t 6 | { 7 | _unset, 8 | 9 | Low = -13, 10 | Normal = 42, 11 | High = +69, 12 | }; 13 | 14 | struct winrt::Windows::System::DispatcherQueue 15 | { 16 | mutable DispatcherQueuePriority test_val{}; 17 | 18 | template 19 | bool TryEnqueue( DispatcherQueuePriority const p, F && ) const 20 | { 21 | std::cout << static_cast(p) << '\n'; 22 | test_val = p; 23 | return true; 24 | } 25 | }; 26 | 27 | int main() 28 | { 29 | using D = winrt::Windows::System::DispatcherQueue; 30 | using P = winrt::Windows::System::DispatcherQueuePriority; 31 | 32 | { 33 | const D d; 34 | winrt::resume_foreground( d ).await_suspend({}); 35 | assert( d.test_val == P::Normal ); 36 | } 37 | { 38 | const D d; 39 | winrt::resume_foreground( d, P::Low ).await_suspend({}); 40 | assert( d.test_val == P::Low ); 41 | } 42 | { 43 | const D d; 44 | winrt::resume_foreground( d, P::High ).await_suspend({}); 45 | assert( d.test_val == P::High ); 46 | } 47 | 48 | #ifdef WINRT_IMPL_COROUTINES 49 | // TODO: test `operator co_await( Windows::System::DispatcherQueue const & )` 50 | #endif 51 | } 52 | -------------------------------------------------------------------------------- /test/intrin.cpp: -------------------------------------------------------------------------------- 1 | #ifdef _WIN64 2 | #include 3 | #include 4 | #include 5 | #endif 6 | 7 | int main() 8 | { 9 | #ifdef _WIN64 10 | alignas(16) std::array current{0,0}; 11 | constexpr decltype(current) 12 | desired{ 0x0123456789ABCDEFll, -0x0123456789ABCDEFll }; 13 | 14 | auto expected = current; 15 | assert(( _InterlockedCompareExchange128( 16 | current.data(), desired[1], desired[0], expected.data() ) )); 17 | assert( current == desired ); 18 | #endif 19 | } 20 | -------------------------------------------------------------------------------- /test/test.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include HEADER 3 | #include 4 | 5 | #define stringify_impl(x) #x 6 | #define stringify(x) stringify_impl(x) 7 | 8 | int main() 9 | { 10 | std::puts( "It's-a me, " stringify(HEADER) "!" ); 11 | } 12 | --------------------------------------------------------------------------------