Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a346936
cppwinrt should not call LoadLibrary anywhere unless new WINRT_REG_FR…
dmachaj Nov 6, 2024
dcc74d4
Add some new testcases for when WINRT_REG_FREE is undefined
dmachaj Nov 6, 2024
ad6dace
Fix some breaks. Add missing build order dependency. Add inline keyw…
dmachaj Nov 6, 2024
266741a
Add one other missing test project to test component build dependency
dmachaj Nov 6, 2024
3734b0e
Remove issameinterface bool and add a class_not_registered restrictio…
dmachaj Nov 6, 2024
2ead2c5
Add a test case where fusion manifest is used to support activation w…
dmachaj Nov 7, 2024
2f7150c
Merge branch 'master' into user/dmachaj/no-loadlibrary
dmachaj Nov 8, 2024
c695204
Add error_class_not_available to the condition for regfree fallback
dmachaj Nov 8, 2024
04b00f4
Revert "Add error_class_not_available to the condition for regfree fa…
dmachaj Nov 8, 2024
8f5edf6
Add a define (WINRT_NEVER_REG_FREE) that will break the build if link…
dmachaj Nov 8, 2024
d7292ac
Merge branch 'master' into user/dmachaj/no-loadlibrary
dmachaj Nov 12, 2024
8f9d77b
Merge branch 'master' into user/dmachaj/no-loadlibrary
dmachaj Nov 16, 2024
ed2302e
Merge remote-tracking branch 'origin/master' into user/dmachaj/no-loa…
dmachaj Nov 19, 2024
98ff9f3
Merge branch 'master' into user/dmachaj/no-loadlibrary
dmachaj Nov 20, 2024
db7693b
Merge branch 'master' into user/dmachaj/no-loadlibrary
jonwis Mar 24, 2025
b9d7ec5
Merge branch 'master' into user/dmachaj/no-loadlibrary
dmachaj Aug 6, 2025
c930243
Merge branch 'master' into user/dmachaj/no-loadlibrary
dmachaj Sep 22, 2025
a9346fd
Merge branch 'master' into user/dmachaj/no-loadlibrary
dmachaj Oct 16, 2025
364259c
Merge branch 'master' into user/dmachaj/no-loadlibrary
dmachaj Oct 30, 2025
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
{
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);
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)
{
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