diff --git a/cppwinrt.props b/cppwinrt.props
index 943cbc823..8bf999342 100644
--- a/cppwinrt.props
+++ b/cppwinrt.props
@@ -48,6 +48,8 @@
$(CmakeOutDir)\
$(SolutionDir)_build\x86\$(Configuration)\
$(CmakeOutDir)\
+
+ PreventSdkUapPropsAssignment
diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h
index 9d4b98e23..4a06a839e 100644
--- a/cppwinrt/code_writers.h
+++ b/cppwinrt/code_writers.h
@@ -40,7 +40,7 @@ namespace cppwinrt
static void write_version_assert(writer& w)
{
w.write_root_include("base");
- auto format = R"(static_assert(winrt::check_version(CPPWINRT_VERSION, "%"), "Mismatched C++/WinRT headers.");
+ auto format = R"(static_assert(winrt::check_version(WINRT_version_number, "%"), "Mismatched C++/WinRT headers.");
#define CPPWINRT_VERSION "%"
)";
w.write(format, CPPWINRT_VERSION_STRING, CPPWINRT_VERSION_STRING);
@@ -179,7 +179,7 @@ namespace cppwinrt
[[nodiscard]] static finish_with wrap_std_namespace(writer& w)
{
- w.write(R"(namespace std
+ w.write(R"(WINRT_EXPORT namespace std
{
)");
diff --git a/cppwinrt/cppwinrt.vcxproj b/cppwinrt/cppwinrt.vcxproj
index 258feafc6..a02d37bf1 100644
--- a/cppwinrt/cppwinrt.vcxproj
+++ b/cppwinrt/cppwinrt.vcxproj
@@ -73,6 +73,7 @@
+
diff --git a/cppwinrt/cppwinrt.vcxproj.filters b/cppwinrt/cppwinrt.vcxproj.filters
index dfe1488ee..e4a27a26d 100644
--- a/cppwinrt/cppwinrt.vcxproj.filters
+++ b/cppwinrt/cppwinrt.vcxproj.filters
@@ -109,6 +109,9 @@
strings
+
+ strings
+
strings
diff --git a/cppwinrt/main.cpp b/cppwinrt/main.cpp
index eab187d6a..8d8a57c7f 100644
--- a/cppwinrt/main.cpp
+++ b/cppwinrt/main.cpp
@@ -296,7 +296,7 @@ Where is one or more of:
write_preamble(ixx);
ixx.write("module;\n");
ixx.write(strings::base_includes);
- ixx.write("\nexport module winrt;\n#define WINRT_EXPORT export\n\n");
+ ixx.write(strings::base_module);
for (auto&&[ns, members] : c.namespaces())
{
diff --git a/strings/base_abi.h b/strings/base_abi.h
index b14e8d85f..6cc1240ae 100644
--- a/strings/base_abi.h
+++ b/strings/base_abi.h
@@ -23,6 +23,7 @@ namespace winrt::impl
};
};
+ WINRT_EXPORT
using inspectable_abi = abi_t;
template <> struct abi
diff --git a/strings/base_activation.h b/strings/base_activation.h
index 8d8eb5e92..5102c8ac3 100644
--- a/strings/base_activation.h
+++ b/strings/base_activation.h
@@ -396,6 +396,7 @@ namespace winrt::impl
return factory.call(callback);
}
+ WINRT_EXPORT
template
auto call_factory_cast(F&& callback)
{
diff --git a/strings/base_collections_map.h b/strings/base_collections_map.h
index f4bd74baf..1a0fe4c1e 100644
--- a/strings/base_collections_map.h
+++ b/strings/base_collections_map.h
@@ -116,7 +116,7 @@ WINRT_EXPORT namespace winrt
}
}
-namespace std
+WINRT_EXPORT namespace std
{
template
struct tuple_size>
diff --git a/strings/base_coroutine_foundation.h b/strings/base_coroutine_foundation.h
index 3c309256c..4fec2fb5c 100644
--- a/strings/base_coroutine_foundation.h
+++ b/strings/base_coroutine_foundation.h
@@ -677,9 +677,9 @@ namespace winrt::impl
}
#ifdef __cpp_lib_coroutine
-namespace std
+WINRT_EXPORT namespace std
#else
-namespace std::experimental
+WINRT_EXPORT namespace std::experimental
#endif
{
template
diff --git a/strings/base_coroutine_threadpool.h b/strings/base_coroutine_threadpool.h
index ae77512d7..483923fe9 100644
--- a/strings/base_coroutine_threadpool.h
+++ b/strings/base_coroutine_threadpool.h
@@ -1,6 +1,20 @@
namespace winrt::impl
{
+#ifdef __cpp_lib_coroutine
+ template
+ using coroutine_handle = std::coroutine_handle;
+
+ using suspend_always = std::suspend_always;
+ using suspend_never = std::suspend_never;
+#else
+ template
+ using coroutine_handle = std::experimental::coroutine_handle;
+
+ using suspend_always = std::experimental::suspend_always;
+ using suspend_never = std::experimental::suspend_never;
+#endif
+
inline auto submit_threadpool_callback(void(__stdcall* callback)(void*, void* context), void* context)
{
if (!WINRT_IMPL_TrySubmitThreadpoolCallback(callback, context, nullptr))
@@ -50,7 +64,9 @@ namespace winrt::impl
struct resume_apartment_context
{
- resume_apartment_context() = default;
+ resume_apartment_context() :
+ m_context(try_capture(WINRT_IMPL_CoGetObjectContext)),
+ m_context_type(get_apartment_type().first) {}
resume_apartment_context(std::nullptr_t) : m_context(nullptr), m_context_type(-1) {}
resume_apartment_context(resume_apartment_context const&) = default;
resume_apartment_context(resume_apartment_context&& other) noexcept :
@@ -67,8 +83,8 @@ namespace winrt::impl
return m_context_type >= 0;
}
- com_ptr m_context = try_capture(WINRT_IMPL_CoGetObjectContext);
- int32_t m_context_type = get_apartment_type().first;
+ com_ptr m_context;
+ int32_t m_context_type;
};
inline int32_t __stdcall resume_apartment_callback(com_callback_args* args) noexcept
@@ -702,9 +718,9 @@ WINRT_EXPORT namespace winrt
}
#ifdef __cpp_lib_coroutine
-namespace std
+WINRT_EXPORT namespace std
#else
-namespace std::experimental
+WINRT_EXPORT namespace std::experimental
#endif
{
template
diff --git a/strings/base_identity.h b/strings/base_identity.h
index 5bf7bbaa8..943458d24 100644
--- a/strings/base_identity.h
+++ b/strings/base_identity.h
@@ -457,6 +457,7 @@ namespace winrt::impl
static constexpr guid value{ generate_guid(signature::data) };
};
+ WINRT_EXPORT
template
#ifdef __clang__
inline static const auto name_v
diff --git a/strings/base_implements.h b/strings/base_implements.h
index b2300edc5..68096e6b9 100644
--- a/strings/base_implements.h
+++ b/strings/base_implements.h
@@ -190,10 +190,12 @@ namespace winrt::impl
template
inline constexpr bool has_static_lifetime_v = has_static_lifetime::value;
+ WINRT_EXPORT
template
void clear_abi(T*) noexcept
{}
+ WINRT_EXPORT
template
void clear_abi(T** value) noexcept
{
@@ -1250,6 +1252,7 @@ namespace winrt::impl
}
}
+ WINRT_EXPORT
template
auto detach_from(T&& object) noexcept
{
diff --git a/strings/base_includes.h b/strings/base_includes.h
index 14d992fc9..2c954d4af 100644
--- a/strings/base_includes.h
+++ b/strings/base_includes.h
@@ -29,29 +29,7 @@
#endif
#ifdef __cpp_lib_coroutine
-
#include
-
-namespace winrt::impl
-{
- template
- using coroutine_handle = std::coroutine_handle;
-
- using suspend_always = std::suspend_always;
- using suspend_never = std::suspend_never;
-}
-
#else
-
#include
-
-namespace winrt::impl
-{
- template
- using coroutine_handle = std::experimental::coroutine_handle;
-
- using suspend_always = std::experimental::suspend_always;
- using suspend_never = std::experimental::suspend_never;
-}
-
#endif
diff --git a/strings/base_macros.h b/strings/base_macros.h
index 1b96e240c..f375b3c5f 100644
--- a/strings/base_macros.h
+++ b/strings/base_macros.h
@@ -39,6 +39,8 @@
#define _WINDOWS_NUMERICS_NAMESPACE_ winrt::Windows::Foundation::Numerics
#define _WINDOWS_NUMERICS_BEGIN_NAMESPACE_ WINRT_EXPORT namespace winrt::Windows::Foundation::Numerics
#define _WINDOWS_NUMERICS_END_NAMESPACE_
+// the include in purview of a module is intentional, we want to export the numeric types as part of the module
+#pragma warning(suppress: 5244)
#include
#undef _WINDOWS_NUMERICS_NAMESPACE_
#undef _WINDOWS_NUMERICS_BEGIN_NAMESPACE_
diff --git a/strings/base_meta.h b/strings/base_meta.h
index f951c4db0..d13505422 100644
--- a/strings/base_meta.h
+++ b/strings/base_meta.h
@@ -54,42 +54,49 @@ namespace winrt::impl
using type = T;
};
+ WINRT_EXPORT
template
struct abi
{
using type = T;
};
- template
+ WINRT_EXPORT
+ template
struct abi>>
{
using type = std::underlying_type_t;
};
- template
+ WINRT_EXPORT
+ template
using abi_t = typename abi::type;
+ WINRT_EXPORT
template
struct consume;
- template
+ WINRT_EXPORT
+ template
using consume_t = typename consume::template type;
template
struct delegate;
+ WINRT_EXPORT
template >
struct default_interface
{
using type = T;
};
- struct basic_category;
- struct interface_category;
- struct delegate_category;
- struct enum_category;
- struct class_category;
+ WINRT_EXPORT struct basic_category;
+ WINRT_EXPORT struct interface_category;
+ WINRT_EXPORT struct delegate_category;
+ WINRT_EXPORT struct enum_category;
+ WINRT_EXPORT struct class_category;
+ WINRT_EXPORT
template
struct category
{
@@ -117,6 +124,7 @@ namespace winrt::impl
static constexpr auto data{ category_signature, T>::data };
};
+ WINRT_EXPORT
template
#if defined(__clang__)
#if __has_declspec_attribute(uuid)
@@ -202,13 +210,16 @@ namespace winrt::impl
template
using arg_out = arg_in*;
- template
+ WINRT_EXPORT
+ template
struct produce_base;
- template
+ WINRT_EXPORT
+ template
struct produce;
- template
+ WINRT_EXPORT
+ template
struct produce : produce_base
{
};
diff --git a/strings/base_module.h b/strings/base_module.h
new file mode 100644
index 000000000..2dc1e4c93
--- /dev/null
+++ b/strings/base_module.h
@@ -0,0 +1,10 @@
+
+// Since modules don't result in global symbol pollution,
+// we can always enable the classic COM support.
+// Users will have to include headers declaring these interfaces
+// to make use of it.
+#include
+#undef GetCurrentTime // Get rid of this evil macro
+
+export module winrt;
+#define WINRT_EXPORT export
diff --git a/strings/base_std_hash.h b/strings/base_std_hash.h
index eb97db0e9..9767e11cf 100644
--- a/strings/base_std_hash.h
+++ b/strings/base_std_hash.h
@@ -32,7 +32,7 @@ namespace winrt::impl
};
}
-namespace std
+WINRT_EXPORT namespace std
{
template<> struct hash
{
diff --git a/strings/base_version.h b/strings/base_version.h
index 227f10402..b2396039b 100644
--- a/strings/base_version.h
+++ b/strings/base_version.h
@@ -4,6 +4,9 @@ extern "C"
__declspec(selectany)
char const * const WINRT_version = "C++/WinRT version:" CPPWINRT_VERSION;
+WINRT_EXPORT
+constexpr char const WINRT_version_number[] = CPPWINRT_VERSION;
+
#ifdef _M_IX86
#pragma comment(linker, "/include:_WINRT_version")
#else
diff --git a/test/test_cpp20/async.cpp b/test/test_cpp20/async.cpp
new file mode 100644
index 000000000..b3a582ceb
--- /dev/null
+++ b/test/test_cpp20/async.cpp
@@ -0,0 +1,92 @@
+#include
+#include
+
+#include "catch.hpp"
+
+import winrt;
+
+using namespace winrt;
+using namespace Windows::Foundation;
+using namespace std::chrono_literals;
+
+namespace
+{
+ //
+ // Just some quick tests to make sure that coroutines compile and work with C++20 modules.
+ // Taken from async_throw in test
+ //
+
+ IAsyncAction Action()
+ {
+ co_await 10ms;
+ throw hresult_invalid_argument(L"Async");
+ }
+
+ IAsyncActionWithProgress ActionWithProgress()
+ {
+ co_await 10ms;
+ throw hresult_invalid_argument(L"Async");
+ }
+
+ IAsyncOperation Operation()
+ {
+ co_await 10ms;
+ throw hresult_invalid_argument(L"Async");
+ co_return 1;
+ }
+
+ IAsyncOperationWithProgress OperationWithProgress()
+ {
+ co_await 10ms;
+ throw hresult_invalid_argument(L"Async");
+ co_return 1;
+ }
+
+ template
+ void Check(F make)
+ {
+ try
+ {
+ make().get();
+ REQUIRE(false);
+ }
+ catch (hresult_invalid_argument const& e)
+ {
+ REQUIRE(e.message() == L"Async");
+ }
+
+ handle completed{ CreateEvent(nullptr, true, false, nullptr) };
+ auto async = make();
+
+ async.Completed([&](auto&& sender, AsyncStatus status)
+ {
+ REQUIRE(async == sender);
+ REQUIRE(status == AsyncStatus::Error);
+ SetEvent(completed.get());
+ });
+
+ REQUIRE(WaitForSingleObject(completed.get(), 1000) == WAIT_OBJECT_0);
+ REQUIRE(async.Status() == AsyncStatus::Error);
+
+ hresult_error e(async.ErrorCode(), take_ownership_from_abi);
+ REQUIRE(e.message() == L"Async");
+
+ try
+ {
+ async.GetResults();
+ REQUIRE(false);
+ }
+ catch (hresult_invalid_argument const& e)
+ {
+ REQUIRE(e.message() == L"Async");
+ }
+ }
+}
+
+TEST_CASE("async_throw")
+{
+ Check(Action);
+ Check(ActionWithProgress);
+ Check(Operation);
+ Check(OperationWithProgress);
+}
diff --git a/test/test_cpp20/await_completed.cpp b/test/test_cpp20/await_completed.cpp
index 2448a3f88..a46b0c261 100644
--- a/test/test_cpp20/await_completed.cpp
+++ b/test/test_cpp20/await_completed.cpp
@@ -1,4 +1,7 @@
-#include "pch.h"
+#include
+#include "catch.hpp"
+
+import winrt;
using namespace winrt;
using namespace Windows::Foundation;
diff --git a/test/test_cpp20/format.cpp b/test/test_cpp20/format.cpp
index b3119a77e..91b56b224 100644
--- a/test/test_cpp20/format.cpp
+++ b/test/test_cpp20/format.cpp
@@ -1,5 +1,9 @@
-#include "pch.h"
+#include "winrt/Windows.Data.Json.h"
+#include "winrt/Windows.Foundation.h"
#include
+#include "catch.hpp"
+
+import winrt;
struct stringable : winrt::implements
{
diff --git a/test/test_cpp20/hstring.cpp b/test/test_cpp20/hstring.cpp
index 57d145fbb..a37c28959 100644
--- a/test/test_cpp20/hstring.cpp
+++ b/test/test_cpp20/hstring.cpp
@@ -1,4 +1,6 @@
-#include "pch.h"
+#include "catch.hpp"
+
+import winrt;
TEST_CASE("hstring")
{
diff --git a/test/test_cpp20/main.cpp b/test/test_cpp20/main.cpp
index 7873e4ee7..4b9f3f8d5 100644
--- a/test/test_cpp20/main.cpp
+++ b/test/test_cpp20/main.cpp
@@ -1,6 +1,7 @@
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
-#include "winrt/base.h"
+
+import winrt;
using namespace winrt;
diff --git a/test/test_cpp20/pch.cpp b/test/test_cpp20/pch.cpp
deleted file mode 100644
index 1d9f38c57..000000000
--- a/test/test_cpp20/pch.cpp
+++ /dev/null
@@ -1 +0,0 @@
-#include "pch.h"
diff --git a/test/test_cpp20/pch.h b/test/test_cpp20/pch.h
deleted file mode 100644
index bd678407c..000000000
--- a/test/test_cpp20/pch.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#pragma once
-
-#pragma warning(4: 4458) // ensure we compile clean with this warning enabled
-
-#define WINRT_LEAN_AND_MEAN
-#include
-#include "winrt/Windows.Data.Json.h"
-#include "winrt/Windows.Foundation.h"
-#include "winrt/Windows.Foundation.Collections.h"
-#include "winrt/Windows.Foundation.Numerics.h"
-#include
-#include "catch.hpp"
-
-using namespace std::literals;
diff --git a/test/test_cpp20/ranges.cpp b/test/test_cpp20/ranges.cpp
index 9bf88a579..a53fb00fe 100644
--- a/test/test_cpp20/ranges.cpp
+++ b/test/test_cpp20/ranges.cpp
@@ -1,7 +1,10 @@
-#include "pch.h"
#include
#include
+#include "catch.hpp"
+
+import winrt;
+
TEST_CASE("ranges")
{
{
diff --git a/test/test_cpp20/test_cpp20.vcxproj b/test/test_cpp20/test_cpp20.vcxproj
index 778faa5f0..7701247b5 100644
--- a/test/test_cpp20/test_cpp20.vcxproj
+++ b/test/test_cpp20/test_cpp20.vcxproj
@@ -131,6 +131,9 @@
$(OutputPath);Generated Files;..\
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreaded
+ stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -152,6 +155,9 @@
$(OutputPath);Generated Files;..\
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreadedDebug
+ stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -171,6 +177,9 @@
$(OutputPath);Generated Files;..\
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreadedDebug
+ stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -190,6 +199,9 @@
$(OutputPath);Generated Files;..\
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreadedDebug
+ stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -209,6 +221,9 @@
$(OutputPath);Generated Files;..\
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreadedDebug
+ stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -230,6 +245,9 @@
$(OutputPath);Generated Files;..\
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreaded
+ stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -253,6 +271,9 @@
$(OutputPath);Generated Files;..\
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreaded
+ stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -276,6 +297,9 @@
$(OutputPath);Generated Files;..\
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreaded
+ stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -292,18 +316,12 @@
-
-
-
+
+
-
- NotUsing
-
-
- Create
-
+