Increase foldability of various templates (#1338)

* Add SDKReference-sourced WinMDs when building

* Add solution items so they're more easily edited

* Update development guidance slightly

* First attempt at template folding

* Make packages easier to build, remove warning about unreferenced static

* Lift delegate creation out for better folding

* More folding of events

* Another delegate folded

* PR feedback

* Speculative improvement for QueryInterface

* PR feedback

---------

Co-authored-by: Jon Wiswall <jdwiswall@hotmail.com>
Co-authored-by: Kenny Kerr <kekerr@microsoft.com>
Co-authored-by: Jon Wiswall <jonwis@ntdev.microsoft.com>
This commit is contained in:
Jon Wiswall 2023-08-09 23:40:40 -07:00 коммит произвёл GitHub
Родитель 0958cf3a4d
Коммит 4196e08bd2
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
7 изменённых файлов: 135 добавлений и 97 удалений

Просмотреть файл

@ -11,11 +11,13 @@ C++/WinRT is an entirely standard C++ language projection for Windows Runtime (W
Don't build C++/WinRT yourself - just download the latest version here: https://aka.ms/cppwinrt/nuget
## Working on the compiler
If you really want to build it yourself, the simplest way to do so is to run the `build_test_all.cmd` script in the root directory. Developers needing to work on the C++/WinRT compiler itself should go through the following steps to arrive at an efficient inner loop:
* Open a dev command prompt pointing at the root of the repo.
* Open the `cppwinrt.sln` solution.
* Build the x64 Release configuration of the `cppwinrt` project only. Do not attempt to build anything else just yet.
* Rebuild the x64 Release configuration of the `cppwinrt` project only. Do not attempt to build anything else just yet.
* Run `build_projection.cmd` in the dev command prompt.
* Switch to the x64 Debug configuration in Visual Studio and build all projects as needed.

Просмотреть файл

@ -1,7 +1,7 @@
rem @echo off
set target_version=%1
if "%target_version%"=="" set target_version=1.2.3.4
if "%target_version%"=="" set target_version=3.0.0.0
call msbuild /m /p:Configuration=Release,Platform=x86,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:fast_fwd
call msbuild /m /p:Configuration=Release,Platform=x64,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:fast_fwd
@ -10,4 +10,4 @@ call msbuild /m /p:Configuration=Release,Platform=arm64,CppWinRTBuildVersion=%ta
call msbuild /m /p:Configuration=Release,Platform=x86,CppWinRTBuildVersion=%target_version% cppwinrt.sln /t:cppwinrt
nuget pack nuget\Microsoft.Windows.CppWinRT.nuspec -Properties cppwinrt_exe=%cd%\_build\x86\Release\cppwinrt.exe;cppwinrt_fast_fwd_x86=%cd%\_build\x86\Release\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_x64=%cd%\_build\x64\Release\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_arm=%cd%\_build\arm\Release\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_arm64=%cd%\_build\arm64\Release\cppwinrt_fast_forwarder.lib
nuget pack nuget\Microsoft.Windows.CppWinRT.nuspec -Properties target_version=%target_version%;cppwinrt_exe=%cd%\_build\x86\Release\cppwinrt.exe;cppwinrt_fast_fwd_x86=%cd%\_build\x86\Release\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_x64=%cd%\_build\x64\Release\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_arm=%cd%\_build\arm\Release\cppwinrt_fast_forwarder.lib;cppwinrt_fast_fwd_arm64=%cd%\_build\arm64\Release\cppwinrt_fast_forwarder.lib

Просмотреть файл

@ -115,6 +115,19 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_cpp20_no_sourcelocatio
{D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4}
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{D15C8430-A7CD-4616-BD84-243B26A9F1C2}"
ProjectSection(SolutionItems) = preProject
build_nuget.cmd = build_nuget.cmd
build_prior_projection.cmd = build_prior_projection.cmd
build_projection.cmd = build_projection.cmd
build_test_all.cmd = build_test_all.cmd
build_vsix.cmd = build_vsix.cmd
compile_tests.cmd = compile_tests.cmd
prepare_versionless_diffs.cmd = prepare_versionless_diffs.cmd
README.md = README.md
run_tests.cmd = run_tests.cmd
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM

Просмотреть файл

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2013/05/nuspec.xsd">
<metadata minClientVersion="2.5">
<id>Microsoft.Windows.CppWinRT</id>
<version>1.0.0.0</version>
<version>$target_version$</version>
<title>C++/WinRT Build Support</title>
<authors>Microsoft</authors>
<owners>Microsoft</owners>

Просмотреть файл

@ -6,8 +6,42 @@ namespace winrt::impl
#pragma warning(disable:4458) // declaration hides class member (okay because we do not use named members of base class)
#endif
struct implements_delegate_base
{
WINRT_IMPL_NOINLINE uint32_t increment_reference() noexcept
{
return ++m_references;
}
WINRT_IMPL_NOINLINE uint32_t decrement_reference() noexcept
{
return --m_references;
}
WINRT_IMPL_NOINLINE uint32_t query_interface(guid const& id, void** result, unknown_abi* derivedAbiPtr, guid const& derivedId) noexcept
{
if (id == derivedId || is_guid_of<Windows::Foundation::IUnknown>(id) || is_guid_of<IAgileObject>(id))
{
*result = derivedAbiPtr;
increment_reference();
return 0;
}
if (is_guid_of<IMarshal>(id))
{
return make_marshaler(derivedAbiPtr, result);
}
*result = nullptr;
return error_no_interface;
}
private:
atomic_ref_count m_references{ 1 };
};
template <typename T, typename H>
struct implements_delegate : abi_t<T>, H, update_module_lock
struct implements_delegate : abi_t<T>, implements_delegate_base, H, update_module_lock
{
implements_delegate(H&& handler) : H(std::forward<H>(handler))
{
@ -15,30 +49,17 @@ namespace winrt::impl
int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final
{
if (is_guid_of<T>(id) || is_guid_of<Windows::Foundation::IUnknown>(id) || is_guid_of<IAgileObject>(id))
{
*result = static_cast<abi_t<T>*>(this);
AddRef();
return 0;
}
if (is_guid_of<IMarshal>(id))
{
return make_marshaler(this, result);
}
*result = nullptr;
return error_no_interface;
return query_interface(id, result, static_cast<abi_t<T>*>(this), guid_of<T>());
}
uint32_t __stdcall AddRef() noexcept final
{
return ++m_references;
return increment_reference();
}
uint32_t __stdcall Release() noexcept final
{
auto const remaining = --m_references;
auto const remaining = decrement_reference();
if (remaining == 0)
{
@ -47,10 +68,6 @@ namespace winrt::impl
return remaining;
}
private:
atomic_ref_count m_references{ 1 };
};
template <typename T, typename H>
@ -73,15 +90,16 @@ namespace winrt::impl
return delegate;
}
const auto id = guid_of<T>();
com_ptr<IAgileReference> ref;
get_agile_reference(guid_of<T>(), get_abi(delegate), ref.put_void());
get_agile_reference(id, get_abi(delegate), ref.put_void());
if (ref)
{
return [ref = std::move(ref)](auto&& ... args)
return [ref = std::move(ref), id](auto&& ... args)
{
T delegate;
ref->Resolve(guid_of<T>(), put_abi(delegate));
ref->Resolve(id, put_abi(delegate));
return delegate(args...);
};
}
@ -97,7 +115,7 @@ namespace winrt::impl
};
template <typename H, typename R, typename... Args>
struct variadic_delegate final : variadic_delegate_abi<R, Args...>, H, update_module_lock
struct variadic_delegate final : variadic_delegate_abi<R, Args...>, implements_delegate_base, H, update_module_lock
{
variadic_delegate(H&& handler) : H(std::forward<H>(handler))
{
@ -117,25 +135,17 @@ namespace winrt::impl
int32_t __stdcall QueryInterface(guid const& id, void** result) noexcept final
{
if (is_guid_of<Windows::Foundation::IUnknown>(id) || is_guid_of<IAgileObject>(id))
{
*result = static_cast<unknown_abi*>(this);
AddRef();
return 0;
}
*result = nullptr;
return error_no_interface;
return query_interface(id, result, static_cast<unknown_abi*>(this), guid_of<Windows::Foundation::IUnknown>());
}
uint32_t __stdcall AddRef() noexcept final
{
return ++m_references;
return increment_reference();
}
uint32_t __stdcall Release() noexcept final
{
auto const remaining = --m_references;
auto const remaining = decrement_reference();
if (remaining == 0)
{
@ -144,10 +154,6 @@ namespace winrt::impl
return remaining;
}
private:
atomic_ref_count m_references{ 1 };
};
template <typename R, typename... Args>

Просмотреть файл

@ -342,6 +342,24 @@ namespace winrt::impl
return 1;
}
WINRT_IMPL_NOINLINE inline bool report_failed_invoke()
{
int32_t const code = to_hresult();
static int32_t(__stdcall * handler)(int32_t, int32_t, void*) noexcept;
impl::load_runtime_function(L"combase.dll", "RoTransformError", handler, fallback_RoTransformError);
handler(code, 0, nullptr);
if (code == static_cast<int32_t>(0x80010108) || // RPC_E_DISCONNECTED
code == static_cast<int32_t>(0x800706BA) || // HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)
code == static_cast<int32_t>(0x89020001)) // JSCRIPT_E_CANTEXECUTE
{
return false;
}
return true;
}
template <typename Delegate, typename... Arg>
bool invoke(Delegate const& delegate, Arg const&... args) noexcept
{
@ -351,18 +369,7 @@ namespace winrt::impl
}
catch (...)
{
int32_t const code = to_hresult();
static int32_t(__stdcall * handler)(int32_t, int32_t, void*) noexcept;
impl::load_runtime_function(L"combase.dll", "RoTransformError", handler, fallback_RoTransformError);
handler(code, 0, nullptr);
if (code == static_cast<int32_t>(0x80010108) || // RPC_E_DISCONNECTED
code == static_cast<int32_t>(0x800706BA) || // HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE)
code == static_cast<int32_t>(0x89020001)) // JSCRIPT_E_CANTEXECUTE
{
return false;
}
return report_failed_invoke();
}
return true;
@ -387,28 +394,7 @@ WINRT_EXPORT namespace winrt
event_token add(delegate_type const& delegate)
{
event_token token{};
// Extends life of old targets array to release delegates outside of lock.
delegate_array temp_targets;
{
slim_lock_guard const change_guard(m_change);
delegate_array new_targets = impl::make_event_array<delegate_type>((!m_targets) ? 1 : m_targets->size() + 1);
if (m_targets)
{
std::copy_n(m_targets->begin(), m_targets->size(), new_targets->begin());
}
new_targets->back() = impl::make_agile_delegate(delegate);
token = get_token(new_targets->back());
slim_lock_guard const swap_guard(m_swap);
temp_targets = std::exchange(m_targets, std::move(new_targets));
}
return token;
return add_agile(impl::make_agile_delegate(delegate));
}
void remove(event_token const token)
@ -510,6 +496,32 @@ WINRT_EXPORT namespace winrt
private:
WINRT_IMPL_NOINLINE event_token add_agile(delegate_type delegate)
{
event_token token{};
// Extends life of old targets array to release delegates outside of lock.
delegate_array temp_targets;
{
slim_lock_guard const change_guard(m_change);
delegate_array new_targets = impl::make_event_array<delegate_type>((!m_targets) ? 1 : m_targets->size() + 1);
if (m_targets)
{
std::copy_n(m_targets->begin(), m_targets->size(), new_targets->begin());
}
new_targets->back() = std::move(delegate);
token = get_token(new_targets->back());
slim_lock_guard const swap_guard(m_swap);
temp_targets = std::exchange(m_targets, std::move(new_targets));
}
return token;
}
event_token get_token(delegate_type const& delegate) const noexcept
{
return event_token{ reinterpret_cast<int64_t>(WINRT_IMPL_EncodePointer(get_abi(delegate))) };

Просмотреть файл

@ -1156,19 +1156,16 @@ namespace winrt::impl
return 0;
}
if constexpr (is_agile::value)
{
if (is_guid_of<IAgileObject>(id))
{
*object = get_unknown();
AddRef();
return 0;
}
return query_interface_common(id, object);
}
if (is_guid_of<IMarshal>(id))
{
return make_marshaler(get_unknown(), object);
}
WINRT_IMPL_NOINLINE int32_t query_interface_common(guid const& id, void** object) noexcept
{
if (is_guid_of<Windows::Foundation::IUnknown>(id))
{
*object = get_unknown();
AddRef();
return 0;
}
if constexpr (is_inspectable::value)
@ -1181,13 +1178,6 @@ namespace winrt::impl
}
}
if (is_guid_of<Windows::Foundation::IUnknown>(id))
{
*object = get_unknown();
AddRef();
return 0;
}
if constexpr (is_weak_ref_source::value)
{
if (is_guid_of<impl::IWeakReferenceSource>(id))
@ -1196,6 +1186,21 @@ namespace winrt::impl
return *object ? error_ok : error_bad_alloc;
}
}
if constexpr (is_agile::value)
{
if (is_guid_of<impl::IAgileObject>(id))
{
*object = get_unknown();
AddRef();
return 0;
}
if (is_guid_of<IMarshal>(id))
{
return make_marshaler(get_unknown(), object);
}
}
return query_interface_tearoff(id, object);
}