Skip to content

Commit eb0867c

Browse files
committed
port
1 parent 45887a4 commit eb0867c

15 files changed

+318
-334
lines changed

cppwinrt.props

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
3737

3838
<PropertyGroup>
39-
<XlangBuildVersion Condition="'$(XlangBuildVersion)'==''">2.3.4.5</XlangBuildVersion>
39+
<CppWinRTBuildVersion Condition="'$(CppWinRTBuildVersion)'==''">2.3.4.5</CppWinRTBuildVersion>
4040
<CmakePlatform>$(Platform)</CmakePlatform>
4141
<CmakePlatform Condition="'$(Platform)'=='Win32'">x86</CmakePlatform>
4242
<CmakeOutDir Condition="'$(CmakeOutDir)'==''">$(SolutionDir)build\$(CmakePlatform)\$(Configuration)</CmakeOutDir>
@@ -53,7 +53,7 @@
5353
<LanguageStandard>stdcpp17</LanguageStandard>
5454
<PrecompiledHeader>Use</PrecompiledHeader>
5555
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
56-
<PreprocessorDefinitions>XLANG_VERSION_STRING="$(XlangBuildVersion)";NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
56+
<PreprocessorDefinitions>CPPWINRT_VERSION_STRING="$(CppWinRTBuildVersion)";NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
5757
<MultiProcessorCompilation>true</MultiProcessorCompilation>
5858
<AdditionalOptions>/await /bigobj</AdditionalOptions>
5959
<AdditionalOptions Condition="'$(Clang)'=='1'">-Wno-unused-command-line-argument -fno-delayed-template-parsing -Xclang -fcoroutines-ts -mcx16</AdditionalOptions>
@@ -62,7 +62,7 @@
6262
<AdditionalDependencies>onecore.lib</AdditionalDependencies>
6363
</Link>
6464
<ResourceCompile>
65-
<PreprocessorDefinitions>XLANG_VERSION_STRING="$(XlangBuildVersion)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
65+
<PreprocessorDefinitions>CPPWINRT_VERSION_STRING="$(CppWinRTBuildVersion)";%(PreprocessorDefinitions)</PreprocessorDefinitions>
6666
</ResourceCompile>
6767
</ItemDefinitionGroup>
6868

cppwinrt/cmd_reader.h

Lines changed: 262 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#pragma once
22

3+
#include <assert.h>
34
#include <array>
45
#include <limits>
56
#include <stdint.h>
@@ -14,10 +15,263 @@
1415
#include <Windows.h>
1516
#include <shlwapi.h>
1617
#include <XmlLite.h>
17-
#include "cmd_reader_windows.h"
1818

19-
namespace xlang::cmd
19+
namespace cppwinrt
2020
{
21+
struct registry_key
22+
{
23+
HKEY handle{};
24+
25+
registry_key(registry_key const&) = delete;
26+
registry_key& operator=(registry_key const&) = delete;
27+
28+
~registry_key() noexcept
29+
{
30+
if (handle)
31+
{
32+
RegCloseKey(handle);
33+
}
34+
}
35+
};
36+
37+
template <typename T>
38+
struct com_ptr
39+
{
40+
T* ptr{};
41+
42+
com_ptr(com_ptr const&) = delete;
43+
com_ptr& operator=(com_ptr const&) = delete;
44+
45+
com_ptr() noexcept = default;
46+
47+
~com_ptr() noexcept
48+
{
49+
if (ptr)
50+
{
51+
ptr->Release();
52+
}
53+
}
54+
55+
auto operator->() const noexcept
56+
{
57+
return ptr;
58+
}
59+
};
60+
61+
static void check_xml(HRESULT result)
62+
{
63+
if (result < 0)
64+
{
65+
throw std::invalid_argument("Could not read the Windows SDK's Platform.xml");
66+
}
67+
}
68+
69+
inline void add_files_from_xml(
70+
std::set<std::string>& files,
71+
std::string const& sdk_version,
72+
std::filesystem::path const& xml_path,
73+
std::filesystem::path const& sdk_path)
74+
{
75+
com_ptr<IStream> stream;
76+
77+
check_xml(SHCreateStreamOnFileW(
78+
xml_path.c_str(),
79+
STGM_READ, &stream.ptr));
80+
81+
com_ptr<IXmlReader> reader;
82+
83+
check_xml(CreateXmlReader(
84+
__uuidof(IXmlReader),
85+
reinterpret_cast<void**>(&reader.ptr),
86+
nullptr));
87+
88+
check_xml(reader->SetInput(stream.ptr));
89+
XmlNodeType node_type = XmlNodeType_None;
90+
91+
while (S_OK == reader->Read(&node_type))
92+
{
93+
if (node_type != XmlNodeType_Element)
94+
{
95+
continue;
96+
}
97+
98+
wchar_t const* value{ nullptr };
99+
check_xml(reader->GetLocalName(&value, nullptr));
100+
101+
if (0 != wcscmp(value, L"ApiContract"))
102+
{
103+
continue;
104+
}
105+
106+
auto path = sdk_path;
107+
path /= L"References";
108+
path /= sdk_version;
109+
110+
check_xml(reader->MoveToAttributeByName(L"name", nullptr));
111+
check_xml(reader->GetValue(&value, nullptr));
112+
path /= value;
113+
114+
check_xml(reader->MoveToAttributeByName(L"version", nullptr));
115+
check_xml(reader->GetValue(&value, nullptr));
116+
path /= value;
117+
118+
check_xml(reader->MoveToAttributeByName(L"name", nullptr));
119+
check_xml(reader->GetValue(&value, nullptr));
120+
path /= value;
121+
122+
path += L".winmd";
123+
files.insert(path.string());
124+
}
125+
}
126+
127+
inline registry_key open_sdk()
128+
{
129+
HKEY key;
130+
131+
if (0 != RegOpenKeyExW(
132+
HKEY_LOCAL_MACHINE,
133+
L"SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots",
134+
0,
135+
KEY_READ,
136+
&key))
137+
{
138+
throw std::invalid_argument("Could not find the Windows SDK in the registry");
139+
}
140+
141+
return { key };
142+
}
143+
144+
inline std::filesystem::path get_sdk_path()
145+
{
146+
auto key = open_sdk();
147+
148+
DWORD path_size = 0;
149+
150+
if (0 != RegQueryValueExW(
151+
key.handle,
152+
L"KitsRoot10",
153+
nullptr,
154+
nullptr,
155+
nullptr,
156+
&path_size))
157+
{
158+
throw std::invalid_argument("Could not find the Windows SDK path in the registry");
159+
}
160+
161+
std::wstring root((path_size / sizeof(wchar_t)) - 1, L'?');
162+
163+
RegQueryValueExW(
164+
key.handle,
165+
L"KitsRoot10",
166+
nullptr,
167+
nullptr,
168+
reinterpret_cast<BYTE*>(root.data()),
169+
&path_size);
170+
171+
return root;
172+
}
173+
174+
inline std::string get_module_path()
175+
{
176+
std::string path(100, '?');
177+
DWORD actual_size{};
178+
179+
while (true)
180+
{
181+
actual_size = GetModuleFileNameA(nullptr, path.data(), 1 + static_cast<uint32_t>(path.size()));
182+
183+
if (actual_size < 1 + path.size())
184+
{
185+
path.resize(actual_size);
186+
break;
187+
}
188+
else
189+
{
190+
path.resize(path.size() * 2, '?');
191+
}
192+
}
193+
194+
return path;
195+
}
196+
197+
inline std::string get_sdk_version()
198+
{
199+
auto module_path = get_module_path();
200+
std::regex rx(R"(((\d+)\.(\d+)\.(\d+)\.(\d+)))");
201+
std::cmatch match;
202+
auto sdk_path = get_sdk_path();
203+
204+
if (std::regex_search(module_path.c_str(), match, rx))
205+
{
206+
auto path = sdk_path / "Platforms\\UAP" / match[1].str() / "Platform.xml";
207+
208+
if (std::filesystem::exists(path))
209+
{
210+
return match[1].str();
211+
}
212+
}
213+
214+
auto key = open_sdk();
215+
uint32_t index{};
216+
std::array<char, 100> subkey;
217+
std::array<unsigned long, 4> version_parts{};
218+
std::string result;
219+
220+
while (0 == RegEnumKeyA(key.handle, index++, subkey.data(), static_cast<uint32_t>(subkey.size())))
221+
{
222+
if (!std::regex_match(subkey.data(), match, rx))
223+
{
224+
continue;
225+
}
226+
227+
auto path = sdk_path / "Platforms\\UAP" / match[1].str() / "Platform.xml";
228+
if (!std::filesystem::exists(path))
229+
{
230+
continue;
231+
}
232+
233+
char* next_part = subkey.data();
234+
bool force_newer = false;
235+
236+
for (size_t i = 0; ; ++i)
237+
{
238+
auto version_part = strtoul(next_part, &next_part, 10);
239+
240+
if ((version_part < version_parts[i]) && !force_newer)
241+
{
242+
break;
243+
}
244+
else if (version_part > version_parts[i])
245+
{
246+
// E.g. ensure something like '2.1' is considered newer than '1.2'
247+
force_newer = true;
248+
}
249+
250+
version_parts[i] = version_part;
251+
252+
if (i == std::size(version_parts) - 1)
253+
{
254+
result = subkey.data();
255+
break;
256+
}
257+
258+
if (!next_part)
259+
{
260+
break;
261+
}
262+
263+
++next_part;
264+
}
265+
}
266+
267+
if (result.empty())
268+
{
269+
throw std::invalid_argument("Could not find the Windows SDK");
270+
}
271+
272+
return result;
273+
}
274+
21275
[[noreturn]] inline void throw_invalid(std::string const& message)
22276
{
23277
throw std::invalid_argument(message);
@@ -47,14 +301,14 @@ namespace xlang::cmd
47301
template <typename C, typename V, size_t numOptions>
48302
reader(C const argc, V const argv, const option(& options)[numOptions])
49303
{
50-
#ifdef XLANG_DEBUG
304+
#ifdef _DEBUG
51305
{
52306
std::set<std::string_view> unique;
53307

54308
for (auto&& option : options)
55309
{
56310
// If this assertion fails it means there are duplicate options.
57-
XLANG_ASSERT(unique.insert(option.name).second);
311+
assert(unique.insert(option.name).second);
58312
}
59313
}
60314
#endif
@@ -180,7 +434,7 @@ namespace xlang::cmd
180434

181435
if (path == "sdk" || path == "sdk+")
182436
{
183-
sdk_version = impl::get_sdk_version();
437+
sdk_version = get_sdk_version();
184438
}
185439
else
186440
{
@@ -195,13 +449,13 @@ namespace xlang::cmd
195449

196450
if (!sdk_version.empty())
197451
{
198-
auto sdk_path = impl::get_sdk_path();
452+
auto sdk_path = get_sdk_path();
199453
auto xml_path = sdk_path;
200454
xml_path /= L"Platforms\\UAP";
201455
xml_path /= sdk_version;
202456
xml_path /= L"Platform.xml";
203457

204-
impl::add_files_from_xml(files, sdk_version, xml_path, sdk_path);
458+
add_files_from_xml(files, sdk_version, xml_path, sdk_path);
205459

206460
if (path.back() != '+')
207461
{
@@ -213,7 +467,7 @@ namespace xlang::cmd
213467
xml_path = item.path() / sdk_version;
214468
xml_path /= L"SDKManifest.xml";
215469

216-
impl::add_files_from_xml(files, sdk_version, xml_path, sdk_path);
470+
add_files_from_xml(files, sdk_version, xml_path, sdk_path);
217471
}
218472

219473
continue;

0 commit comments

Comments
 (0)