Skip to content

Commit a2c65b4

Browse files
authored
Support for Windows 7 (#469)
1 parent 39d65cb commit a2c65b4

25 files changed

+626
-563
lines changed

cppwinrt/component_writers.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,7 @@ int32_t __stdcall WINRT_CanUnloadNow() noexcept
186186
187187
int32_t __stdcall WINRT_GetActivationFactory(void* classId, void** factory) noexcept try
188188
{
189-
uint32_t length{};
190-
wchar_t const* const buffer = WINRT_WindowsGetStringRawBuffer(classId, &length);
191-
std::wstring_view const name{ buffer, length };
189+
std::wstring_view const name{ *reinterpret_cast<winrt::hstring*>(&classId) };
192190
*factory = %_get_activation_factory(name);
193191
194192
if (*factory)

cppwinrt/cppwinrt.vcxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3-
<Import Project="..\packages\Microsoft.Windows.WinMD.1.0.191006.1\build\native\Microsoft.Windows.WinMD.props" Condition="Exists('..\packages\Microsoft.Windows.WinMD.1.0.191006.1\build\native\Microsoft.Windows.WinMD.props')" />
3+
<Import Project="..\packages\Microsoft.Windows.WinMD.1.0.191022.1\build\native\Microsoft.Windows.WinMD.props" Condition="Exists('..\packages\Microsoft.Windows.WinMD.1.0.191022.1\build\native\Microsoft.Windows.WinMD.props')" />
44
<ItemGroup Label="ProjectConfigurations">
55
<ProjectConfiguration Include="Debug|ARM">
66
<Configuration>Debug</Configuration>
@@ -351,6 +351,6 @@
351351
<PropertyGroup>
352352
<ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
353353
</PropertyGroup>
354-
<Error Condition="!Exists('..\packages\Microsoft.Windows.WinMD.1.0.191006.1\build\native\Microsoft.Windows.WinMD.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.WinMD.1.0.191006.1\build\native\Microsoft.Windows.WinMD.props'))" />
354+
<Error Condition="!Exists('..\packages\Microsoft.Windows.WinMD.1.0.191022.1\build\native\Microsoft.Windows.WinMD.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Windows.WinMD.1.0.191022.1\build\native\Microsoft.Windows.WinMD.props'))" />
355355
</Target>
356356
</Project>

cppwinrt/packages.config

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<packages>
3-
<package id="Microsoft.Windows.WinMD" version="1.0.191006.1" targetFramework="native" />
3+
<package id="Microsoft.Windows.WinMD" version="1.0.191022.1" targetFramework="native" />
44
</packages>

strings/base_abi.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ namespace winrt::impl
5050
virtual int32_t __stdcall DisconnectObject(uint32_t dwReserved) noexcept = 0;
5151
};
5252

53+
struct __declspec(novtable) IGlobalInterfaceTable : unknown_abi
54+
{
55+
virtual int32_t __stdcall RegisterInterfaceInGlobal(void* object, guid const& iid, uint32_t* cookie) noexcept = 0;
56+
virtual int32_t __stdcall RevokeInterfaceFromGlobal(uint32_t cookie) noexcept = 0;
57+
virtual int32_t __stdcall GetInterfaceFromGlobal(uint32_t cookie, guid const& iid, void** object) noexcept = 0;
58+
};
59+
5360
struct __declspec(novtable) IStaticLifetime : inspectable_abi
5461
{
5562
virtual int32_t __stdcall unused() noexcept = 0;
@@ -134,7 +141,9 @@ namespace winrt::impl
134141
template <> inline constexpr guid guid_v<Windows::Foundation::IInspectable>{ 0xAF86E2E0, 0xB12D, 0x4C6A, { 0x9C,0x5A,0xD7,0xAA,0x65,0x10,0x1E,0x90 } };
135142
template <> inline constexpr guid guid_v<Windows::Foundation::IActivationFactory>{ 0x00000035, 0x0000, 0x0000, { 0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
136143
template <> inline constexpr guid guid_v<IAgileObject>{ 0x94EA2B94, 0xE9CC, 0x49E0, { 0xC0,0xFF,0xEE,0x64,0xCA,0x8F,0x5B,0x90 } };
144+
template <> inline constexpr guid guid_v<IAgileReference>{ 0xC03F6A43, 0x65A4, 0x9818, { 0x98,0x7E,0xE0,0xB8,0x10,0xD2,0xA6,0xF2 } };
137145
template <> inline constexpr guid guid_v<IMarshal>{ 0x00000003, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
146+
template <> inline constexpr guid guid_v<IGlobalInterfaceTable>{ 0x00000146, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
138147
template <> inline constexpr guid guid_v<IStaticLifetime>{ 0x17b0e613, 0x942a, 0x422d, { 0x90,0x4c,0xf9,0x0d,0xc7,0x1a,0x7d,0xae } };
139148
template <> inline constexpr guid guid_v<IStaticLifetimeCollection>{ 0x1b0d3570, 0x0877, 0x5ec2, { 0x8a,0x2c,0x3b,0x95,0x39,0x50,0x6a,0xca } };
140149
template <> inline constexpr guid guid_v<IWeakReference>{ 0x00000037, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };

strings/base_activation.h

Lines changed: 95 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,102 @@
11

2-
WINRT_EXPORT namespace winrt
2+
namespace winrt::impl
33
{
4-
template <typename Interface = Windows::Foundation::IActivationFactory>
5-
impl::com_ref<Interface> get_activation_factory(param::hstring const& name)
4+
struct library_traits
65
{
7-
void* result{};
8-
hresult hr = WINRT_RoGetActivationFactory(*(void**)(&name), guid_of<Interface>(), &result);
6+
using type = void*;
7+
8+
static void close(type value) noexcept
9+
{
10+
WINRT_FreeLibrary(value);
11+
}
12+
13+
static constexpr type invalid() noexcept
14+
{
15+
return nullptr;
16+
}
17+
};
18+
19+
using library_handle = handle_type<library_traits>;
20+
21+
template <typename Interface>
22+
hresult get_runtime_activation_factory(param::hstring const& name, void** result) noexcept
23+
{
24+
static int32_t(__stdcall * handler)(void* classId, guid const& iid, void** factory) noexcept;
25+
26+
impl::load_runtime_function("RoGetActivationFactory", handler,
27+
[](void*, guid const&, void** factory) noexcept -> int32_t
28+
{
29+
*factory = nullptr;
30+
return error_class_not_available;
31+
});
32+
33+
hresult hr = handler(*(void**)(&name), guid_of<Interface>(), result);
934

1035
if (hr == impl::error_not_initialized)
1136
{
1237
void* cookie;
1338
WINRT_CoIncrementMTAUsage(&cookie);
14-
hr = WINRT_RoGetActivationFactory(*(void**)(&name), guid_of<Interface>(), &result);
39+
hr = handler(*(void**)(&name), guid_of<Interface>(), result);
40+
}
41+
42+
if (hr == 0)
43+
{
44+
return 0;
45+
}
46+
47+
std::wstring path{ static_cast<hstring const&>(name) };
48+
std::size_t count{};
49+
50+
while (-1 != (count = path.rfind('.')))
51+
{
52+
path.resize(count);
53+
path += L".dll";
54+
library_handle library(WINRT_LoadLibraryW(path.c_str()));
55+
path.resize(path.size() - 4);
56+
57+
if (!library)
58+
{
59+
continue;
60+
}
61+
62+
auto library_call = reinterpret_cast<int32_t(__stdcall*)(void* classId, void** factory)>(WINRT_GetProcAddress(library.get(), "DllGetActivationFactory"));
63+
64+
if (!library_call)
65+
{
66+
continue;
67+
}
68+
69+
com_ptr<abi_t<Windows::Foundation::IActivationFactory>> library_factory;
70+
71+
if (0 != library_call(*(void**)(&name), library_factory.put_void()))
72+
{
73+
continue;
74+
}
75+
76+
if constexpr (std::is_same_v< Interface, Windows::Foundation::IActivationFactory>)
77+
{
78+
*result = library_factory.detach();
79+
library.detach();
80+
return 0;
81+
}
82+
else if (0 == library_factory.as(guid_of<Interface>(), result))
83+
{
84+
library.detach();
85+
return 0;
86+
}
1587
}
1688

17-
check_hresult(hr);
89+
return error_class_not_available;
90+
}
91+
}
92+
93+
WINRT_EXPORT namespace winrt
94+
{
95+
template <typename Interface = Windows::Foundation::IActivationFactory>
96+
impl::com_ref<Interface> get_activation_factory(param::hstring const& name)
97+
{
98+
void* result{};
99+
check_hresult(impl::get_runtime_activation_factory<Interface>(name, &result));
18100
return { result, take_ownership_from_abi };
19101
}
20102
}
@@ -304,11 +386,11 @@ namespace winrt::impl
304386
}
305387

306388
template <typename Class, typename Interface = Windows::Foundation::IActivationFactory>
307-
impl::com_ref<Interface> try_get_activation_factory(hresult_error* exception = nullptr) noexcept
389+
com_ref<Interface> try_get_activation_factory(hresult_error* exception = nullptr) noexcept
308390
{
309391
param::hstring const name{ name_of<Class>() };
310392
void* result{};
311-
hresult const hr = WINRT_RoGetActivationFactory(get_abi(name), guid_of<Interface>(), &result);
393+
hresult const hr = get_runtime_activation_factory<Interface>(name, &result);
312394

313395
if (hr < 0)
314396
{
@@ -342,13 +424,13 @@ WINRT_EXPORT namespace winrt
342424
{
343425
enum class apartment_type : int32_t
344426
{
345-
single_threaded,
346-
multi_threaded
427+
multi_threaded = 0,
428+
single_threaded = 2,
347429
};
348430

349431
inline void init_apartment(apartment_type const type = apartment_type::multi_threaded)
350432
{
351-
hresult const result = WINRT_RoInitialize(static_cast<uint32_t>(type));
433+
hresult const result = WINRT_CoInitializeEx(nullptr, static_cast<uint32_t>(type));
352434

353435
if (result < 0)
354436
{
@@ -358,7 +440,7 @@ WINRT_EXPORT namespace winrt
358440

359441
inline void uninit_apartment() noexcept
360442
{
361-
WINRT_RoUninitialize();
443+
WINRT_CoUninitialize();
362444
}
363445

364446
template <typename Class, typename Interface = Windows::Foundation::IActivationFactory>

strings/base_agile_ref.h

Lines changed: 155 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,158 @@
11

2+
WINRT_EXPORT namespace winrt
3+
{
4+
#if defined (WINRT_NO_MODULE_LOCK)
5+
6+
// Defining WINRT_NO_MODULE_LOCK is appropriate for apps (executables) that don't implement something like DllCanUnloadNow
7+
// and can thus avoid the synchronization overhead imposed by the default module lock.
8+
9+
constexpr auto get_module_lock() noexcept
10+
{
11+
struct lock
12+
{
13+
constexpr uint32_t operator++() noexcept
14+
{
15+
return 1;
16+
}
17+
18+
constexpr uint32_t operator--() noexcept
19+
{
20+
return 0;
21+
}
22+
};
23+
24+
return lock{};
25+
}
26+
27+
#elif defined (WINRT_CUSTOM_MODULE_LOCK)
28+
29+
// When WINRT_CUSTOM_MODULE_LOCK is defined, you must provide an implementation of winrt::get_module_lock()
30+
// that returns an object that implements operator++ and operator--.
31+
32+
#else
33+
34+
// This is the default implementation for use with DllCanUnloadNow.
35+
36+
inline impl::atomic_ref_count& get_module_lock() noexcept
37+
{
38+
static impl::atomic_ref_count s_lock;
39+
return s_lock;
40+
}
41+
42+
#endif
43+
}
44+
45+
namespace winrt::impl
46+
{
47+
struct agile_ref_fallback final : IAgileReference
48+
{
49+
agile_ref_fallback(com_ptr<IGlobalInterfaceTable>&& git, uint32_t cookie) noexcept :
50+
m_git(std::move(git)),
51+
m_cookie(cookie)
52+
{
53+
++get_module_lock();
54+
}
55+
56+
~agile_ref_fallback() noexcept
57+
{
58+
m_git->RevokeInterfaceFromGlobal(m_cookie);
59+
--get_module_lock();
60+
}
61+
62+
int32_t __stdcall QueryInterface(guid const& id, void** object) noexcept final
63+
{
64+
if (is_guid_of<IAgileReference>(id) || is_guid_of<Windows::Foundation::IUnknown>(id) || is_guid_of<IAgileObject>(id))
65+
{
66+
*object = static_cast<IAgileReference*>(this);
67+
AddRef();
68+
return 0;
69+
}
70+
71+
*object = nullptr;
72+
return error_no_interface;
73+
}
74+
75+
uint32_t __stdcall AddRef() noexcept final
76+
{
77+
return ++m_references;
78+
}
79+
80+
uint32_t __stdcall Release() noexcept final
81+
{
82+
auto const remaining = --m_references;
83+
84+
if (remaining == 0)
85+
{
86+
delete this;
87+
}
88+
89+
return remaining;
90+
}
91+
92+
int32_t __stdcall Resolve(guid const& id, void** object) noexcept final
93+
{
94+
return m_git->GetInterfaceFromGlobal(m_cookie, id, object);
95+
}
96+
97+
private:
98+
99+
com_ptr<IGlobalInterfaceTable> m_git;
100+
uint32_t m_cookie{};
101+
atomic_ref_count m_references{ 1 };
102+
};
103+
104+
template <typename F, typename L>
105+
void load_runtime_function(char const* name, F& result, L fallback) noexcept
106+
{
107+
if (result)
108+
{
109+
return;
110+
}
111+
112+
result = static_cast<F>(WINRT_GetProcAddress(WINRT_LoadLibraryW(L"combase.dll"), name));
113+
114+
if (result)
115+
{
116+
return;
117+
}
118+
119+
result = fallback;
120+
}
121+
122+
inline hresult get_agile_reference(winrt::guid const& iid, void* object, void** result) noexcept
123+
{
124+
static int32_t(__stdcall * handler)(uint32_t options, winrt::guid const& iid, void* object, void** result) noexcept;
125+
126+
load_runtime_function("RoGetAgileReference", handler,
127+
[](uint32_t, winrt::guid const& iid, void* object, void** result) noexcept -> int32_t
128+
{
129+
*result = nullptr;
130+
static constexpr guid git_clsid{ 0x00000323, 0x0000, 0x0000, { 0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46 } };
131+
132+
com_ptr<IGlobalInterfaceTable> git;
133+
hresult hr = WINRT_CoCreateInstance(git_clsid, nullptr, 1 /*CLSCTX_INPROC_SERVER*/, guid_of<IGlobalInterfaceTable>(), git.put_void());
134+
135+
if (result < 0)
136+
{
137+
return hr;
138+
}
139+
140+
uint32_t cookie{};
141+
hr = git->RegisterInterfaceInGlobal(object, iid, &cookie);
142+
143+
if (result < 0)
144+
{
145+
return hr;
146+
}
147+
148+
*result = new agile_ref_fallback(std::move(git), cookie);
149+
return 0;
150+
});
151+
152+
return handler(0, iid, object, result);
153+
}
154+
}
155+
2156
WINRT_EXPORT namespace winrt
3157
{
4158
template <typename T>
@@ -10,7 +164,7 @@ WINRT_EXPORT namespace winrt
10164
{
11165
if (object)
12166
{
13-
check_hresult(WINRT_RoGetAgileReference(0, guid_of<T>(), winrt::get_abi(object), m_ref.put_void()));
167+
check_hresult(impl::get_agile_reference(guid_of<T>(), winrt::get_abi(object), m_ref.put_void()));
14168
}
15169
}
16170

0 commit comments

Comments
 (0)