diff --git a/cppwinrt/code_writers.h b/cppwinrt/code_writers.h
index 4b4fa8229..e24b462cb 100644
--- a/cppwinrt/code_writers.h
+++ b/cppwinrt/code_writers.h
@@ -169,7 +169,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 0f8d398fb..f4ed40fb9 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 26c1fdafd..fe2b4ea95 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 1b26659a3..fc5cc1cb4 100644
--- a/cppwinrt/main.cpp
+++ b/cppwinrt/main.cpp
@@ -294,7 +294,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_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 943e640ed..3e4198eef 100644
--- a/strings/base_coroutine_foundation.h
+++ b/strings/base_coroutine_foundation.h
@@ -655,9 +655,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 4ea37bf75..81e5cee6d 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))
@@ -676,9 +690,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_includes.h b/strings/base_includes.h
index 7354a304c..307f06ba2 100644
--- a/strings/base_includes.h
+++ b/strings/base_includes.h
@@ -25,29 +25,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 92f746699..d78961f86 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_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/test/test_cpp20/async.cpp b/test/test_cpp20/async.cpp
new file mode 100644
index 000000000..129e71080
--- /dev/null
+++ b/test/test_cpp20/async.cpp
@@ -0,0 +1,98 @@
+#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
+ // IAsyncOperation and IAsyncOperationWithProgress are affected by compiler bugs so disabled for now:
+ // https://developercommunity.visualstudio.com/t/identifier-not-found-with-default-membe/1376824
+ //
+
+ IAsyncAction Action()
+ {
+ co_await 10ms;
+ throw hresult_invalid_argument(L"Async");
+ }
+
+ IAsyncActionWithProgress ActionWithProgress()
+ {
+ co_await 10ms;
+ throw hresult_invalid_argument(L"Async");
+ }
+
+#if 0
+ 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;
+ }
+#endif
+
+ 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);
+#if 0
+ Check(Operation);
+ Check(OperationWithProgress);
+#endif
+}
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 ea74230cc..000000000
--- a/test/test_cpp20/pch.h
+++ /dev/null
@@ -1,12 +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.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 485218a0f..828d45acf 100644
--- a/test/test_cpp20/test_cpp20.vcxproj
+++ b/test/test_cpp20/test_cpp20.vcxproj
@@ -131,6 +131,8 @@
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreaded
stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -153,6 +155,8 @@
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreadedDebug
stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -173,6 +177,8 @@
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreadedDebug
stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -193,6 +199,8 @@
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreadedDebug
stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -213,6 +221,8 @@
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreadedDebug
stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -235,6 +245,8 @@
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreaded
stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -259,6 +271,8 @@
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreaded
stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -283,6 +297,8 @@
NOMINMAX;_MBCS;%(PreprocessorDefinitions)
MultiThreaded
stdcpplatest
+ NotUsing
+ /bigobj
Console
@@ -299,15 +315,9 @@
-
-
-
-
- NotUsing
-
-
- Create
-
+
+
+