Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cppwinrt should not call LoadLibrary anywhere unless new WINRT_REG_FREE define is defined, re-activating regfree behavior #1446

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cppwinrt.sln
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{3C7EA5F8-6
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_cpp20", "test\test_cpp20\test_cpp20.vcxproj", "{5FF6CD6C-515A-4D55-97B6-62AD9BCB77EA}"
ProjectSection(ProjectDependencies) = postProject
{559A7CF4-DC5F-4D62-BA6B-0C2B025593F8} = {559A7CF4-DC5F-4D62-BA6B-0C2B025593F8}
{A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270} = {A91B8BF3-28E4-4D9E-8DBA-64B70E4F0270}
{D613FB39-5035-4043-91E2-BAB323908AF4} = {D613FB39-5035-4043-91E2-BAB323908AF4}
{F1C915B3-2C64-4992-AFB7-7F035B1A7607} = {F1C915B3-2C64-4992-AFB7-7F035B1A7607}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_cpp20_no_sourcelocation", "test\test_cpp20_no_sourcelocation\test_cpp20_no_sourcelocation.vcxproj", "{D4C8F881-84D5-4A7B-8BDE-AB4E34A05374}"
Expand Down
52 changes: 33 additions & 19 deletions strings/base_activation.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,11 @@ namespace winrt::impl

using library_handle = handle_type<library_traits>;

template <bool isSameInterfaceAsIActivationFactory>
WINRT_IMPL_NOINLINE hresult get_runtime_activation_factory_impl(param::hstring const& name, winrt::guid const& guid, void** result) noexcept
// This function pointer will be null unless one or more translation units in a binary define WINRT_REG_FREE before
// including winrt/base.h. If that is defined then the overall binary will support regfree COM activation.
inline hresult(*reg_free_factory_getter)(param::hstring const&, guid const&, void**) = nullptr;

WINRT_IMPL_NOINLINE inline hresult get_runtime_activation_factory_impl(param::hstring const& name, winrt::guid const& guid, void** result) noexcept
oldnewthing marked this conversation as resolved.
Show resolved Hide resolved
{
if (winrt_activation_handler)
{
Expand All @@ -30,15 +33,8 @@ namespace winrt::impl

if (hr == impl::error_not_initialized)
{
auto usage = reinterpret_cast<int32_t(__stdcall*)(void** cookie) noexcept>(WINRT_IMPL_GetProcAddress(load_library(L"combase.dll"), "CoIncrementMTAUsage"));

if (!usage)
{
return hr;
}

void* cookie;
usage(&cookie);
WINRT_IMPL_CoIncrementMTAUsage(&cookie);
dmachaj marked this conversation as resolved.
Show resolved Hide resolved
hr = WINRT_IMPL_RoGetActivationFactory(*(void**)(&name), guid, result);
}

Expand All @@ -47,6 +43,21 @@ namespace winrt::impl
return 0;
}

// If the class is not registered, and regfree support is enabled, give that a chance to make the activation succeed.
// We should not attempt to fallback to regfree for error codes besides class not registered. If the activation is out
// of process then we could have RPC error codes. It would be bad if a class that should only ever be used out of proc
// is erroneously activated inproc.
if ((hr == error_class_not_registered) && reg_free_factory_getter)
dmachaj marked this conversation as resolved.
Show resolved Hide resolved
{
return reg_free_factory_getter(name, guid, result);
}

return hr;
}

#ifdef WINRT_REG_FREE
WINRT_IMPL_NOINLINE inline hresult reg_free_get_activation_factory(param::hstring const& name, winrt::guid const& guid, void** result) noexcept
{
com_ptr<IErrorInfo> error_info;
WINRT_IMPL_GetErrorInfo(0, error_info.put_void());

Expand Down Expand Up @@ -79,27 +90,30 @@ namespace winrt::impl
continue;
}

if constexpr (isSameInterfaceAsIActivationFactory)
{
*result = library_factory.detach();
library.detach();
return 0;
}
else if (0 == library_factory.as(guid, result))
if (0 == library_factory.as(guid, result))
{
library.detach();
return 0;
}
}

WINRT_IMPL_SetErrorInfo(0, error_info.get());
return hr;
return error_class_not_registered;
}

// This file has been compiled by a translation unit with WINRT_REG_FREE defined. Fill in the reg_free_factory_getter function
// pointer so that regfree behavior is activated.
inline unsigned int reg_free_init = []() {
reg_free_factory_getter = reg_free_get_activation_factory;
return 0U;
}();

#endif // WINRT_REG_FREE

template <typename Interface>
hresult get_runtime_activation_factory(param::hstring const& name, void** result) noexcept
{
return get_runtime_activation_factory_impl<std::is_same_v<Interface, Windows::Foundation::IActivationFactory>>(name, guid_of<Interface>(), result);
return get_runtime_activation_factory_impl(name, guid_of<Interface>(), result);
}
}

Expand Down
2 changes: 2 additions & 0 deletions strings/base_agile_ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,12 @@ namespace winrt::impl

using update_module_lock = module_lock_updater<true>;

#ifdef WINRT_REG_FREE
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ifdef makes it so that there is definitely no LoadLibrary usage when regfree is inactive.

inline void* load_library(wchar_t const* library) noexcept
{
return WINRT_IMPL_LoadLibraryExW(library, nullptr, 0x00001000 /* LOAD_LIBRARY_SEARCH_DEFAULT_DIRS */);
}
#endif // WINRT_REG_FREE

inline hresult get_agile_reference(winrt::guid const& iid, void* object, void** reference) noexcept
{
Expand Down
3 changes: 3 additions & 0 deletions strings/base_extern.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,17 @@ extern "C"
int32_t __stdcall WINRT_IMPL_GetRestrictedErrorInfo(void**) noexcept WINRT_IMPL_LINK(GetRestrictedErrorInfo, 4);
int32_t __stdcall WINRT_IMPL_SetRestrictedErrorInfo(void*) noexcept WINRT_IMPL_LINK(SetRestrictedErrorInfo, 4);

#ifdef WINRT_REG_FREE
void* __stdcall WINRT_IMPL_LoadLibraryExW(wchar_t const* name, void* unused, uint32_t flags) noexcept WINRT_IMPL_LINK(LoadLibraryExW, 12);
#endif // WINRT_REG_FREE
int32_t __stdcall WINRT_IMPL_FreeLibrary(void* library) noexcept WINRT_IMPL_LINK(FreeLibrary, 4);
void* __stdcall WINRT_IMPL_GetProcAddress(void* library, char const* name) noexcept WINRT_IMPL_LINK(GetProcAddress, 8);

int32_t __stdcall WINRT_IMPL_SetErrorInfo(uint32_t reserved, void* info) noexcept WINRT_IMPL_LINK(SetErrorInfo, 8);
int32_t __stdcall WINRT_IMPL_GetErrorInfo(uint32_t reserved, void** info) noexcept WINRT_IMPL_LINK(GetErrorInfo, 8);
int32_t __stdcall WINRT_IMPL_CoInitializeEx(void*, uint32_t type) noexcept WINRT_IMPL_LINK(CoInitializeEx, 8);
void __stdcall WINRT_IMPL_CoUninitialize() noexcept WINRT_IMPL_LINK(CoUninitialize, 0);
int32_t __stdcall WINRT_IMPL_CoIncrementMTAUsage(void** cookie) noexcept WINRT_IMPL_LINK(CoIncrementMTAUsage, 4);

int32_t __stdcall WINRT_IMPL_CoCreateFreeThreadedMarshaler(void* outer, void** marshaler) noexcept WINRT_IMPL_LINK(CoCreateFreeThreadedMarshaler, 8);
int32_t __stdcall WINRT_IMPL_CoCreateInstance(winrt::guid const& clsid, void* outer, uint32_t context, winrt::guid const& iid, void** object) noexcept WINRT_IMPL_LINK(CoCreateInstance, 20);
Expand Down
3 changes: 2 additions & 1 deletion test/old_tests/UnitTests/pch.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#define WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#define WINRT_REG_FREE
#define WINRT_NATVIS
#define _SILENCE_CXX17_UNCAUGHT_EXCEPTION_DEPRECATION_WARNING

Expand Down
1 change: 1 addition & 0 deletions test/test/pch.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "mingw_com_support.h"

#define WINRT_LEAN_AND_MEAN
#define WINRT_REG_FREE
#include <unknwn.h>
#include "winrt/Windows.Foundation.Collections.h"
#include "winrt/Windows.Foundation.Numerics.h"
Expand Down
47 changes: 47 additions & 0 deletions test/test_cpp20/activation_without_regfree.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include "pch.h"
#include "winrt/test_component.h"

#ifdef WINRT_REG_FREE
#error "This test needs WINRT_REG_FREE to be undefined"
#endif

using namespace winrt;
using namespace Windows::Foundation;
using namespace test_component;

TEST_CASE("activation_withoug_regfree_system_type")
{
REQUIRE_NOTHROW(Uri(L"https://bing.com"));
}

TEST_CASE("activation_manifested_avoiding_regfree")
{
bool fusionRegistrationWorked{ false };
try
{
// app.manifest has registration for the Simple runtimeclass so activation should succeed.
Simple s{};
fusionRegistrationWorked = true;
}
catch (...)
{
}
REQUIRE(fusionRegistrationWorked);
}

TEST_CASE("activation_withoug_regfree_fails")
{
bool threwException{ false };
try
{
Class c;
REQUIRE(false);
}
catch (winrt::hresult_class_not_registered& e)
{
threwException = true;
REQUIRE(e.code() == winrt::impl::error_class_not_registered);
}

REQUIRE(threwException);
}
9 changes: 9 additions & 0 deletions test/test_cpp20/app.manifest
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<file name="test_component.dll">
<activatableClass
name="test_component.Simple"
threadingModel="both"
xmlns="urn:schemas-microsoft-com:winrt.v1"
/>
</file>
</assembly>
28 changes: 12 additions & 16 deletions test/test_cpp20/test_cpp20.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,7 @@
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PreBuildEvent>
<Command>
</Command>
<Command>$(CppWinRTDir)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
Expand All @@ -142,8 +141,7 @@
<SubSystem>Console</SubSystem>
</Link>
<PreBuildEvent>
<Command>
</Command>
<Command>$(CppWinRTDir)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
Expand All @@ -161,8 +159,7 @@
<SubSystem>Console</SubSystem>
</Link>
<PreBuildEvent>
<Command>
</Command>
<Command>$(CppWinRTDir)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
Expand All @@ -180,8 +177,7 @@
<SubSystem>Console</SubSystem>
</Link>
<PreBuildEvent>
<Command>
</Command>
<Command>$(CppWinRTDir)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
Expand All @@ -199,8 +195,7 @@
<SubSystem>Console</SubSystem>
</Link>
<PreBuildEvent>
<Command>
</Command>
<Command>$(CppWinRTDir)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
Expand All @@ -222,8 +217,7 @@
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PreBuildEvent>
<Command>
</Command>
<Command>$(CppWinRTDir)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
Expand All @@ -245,8 +239,7 @@
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PreBuildEvent>
<Command>
</Command>
<Command>$(CppWinRTDir)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
Expand All @@ -268,8 +261,7 @@
<OptimizeReferences>true</OptimizeReferences>
</Link>
<PreBuildEvent>
<Command>
</Command>
<Command>$(CppWinRTDir)cppwinrt -in $(OutputPath)test_component.winmd $(OutputPath)test_component_no_pch.winmd -out "$(ProjectDir)Generated Files" -ref sdk -verbose -fastabi</Command>
</PreBuildEvent>
<PostBuildEvent>
<Command>
Expand All @@ -280,6 +272,7 @@
<ClInclude Include="pch.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="activation_without_regfree.cpp" />
<ClCompile Include="array_span.cpp" />
<ClCompile Include="await_completed.cpp" />
<ClCompile Include="custom_error.cpp" />
Expand All @@ -293,6 +286,9 @@
</ClCompile>
<ClCompile Include="ranges.cpp" />
</ItemGroup>
<ItemGroup>
<Manifest Include="app.manifest" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
Expand Down
1 change: 1 addition & 0 deletions test/test_fast/pch.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#define WINRT_REG_FREE
#include "catch.hpp"
#include "winrt/Windows.Foundation.Collections.h"

Expand Down
1 change: 1 addition & 0 deletions test/test_slow/pch.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#define WINRT_REG_FREE
#include "catch.hpp"
#include "winrt/Windows.Foundation.Collections.h"

Expand Down
Loading