@@ -11,8 +11,39 @@ using namespace std::filesystem;
11
11
using namespace winrt ;
12
12
using namespace winmd ::reader;
13
13
14
- std::vector<std::string> db_files;
15
- std::unique_ptr<cache> db_cache;
14
+ namespace
15
+ {
16
+ std::vector<std::string> db_files;
17
+ std::unique_ptr<cache> db_cache;
18
+ coded_index<TypeDefOrRef> guid_TypeRef{};
19
+ }
20
+
21
+ coded_index<TypeDefOrRef> FindGuidType ()
22
+ {
23
+ if (!guid_TypeRef)
24
+ {
25
+ // There is no definitive TypeDef for System.Guid. But there are a variety of TypeRefs scattered about
26
+ // This one should be relatively quick to find
27
+ auto pv = db_cache->find (" Windows.Foundation" , " IPropertyValue" );
28
+ for (auto && method : pv.MethodList ())
29
+ {
30
+ if (method.Name () == " GetGuid" )
31
+ {
32
+ auto const & sig = method.Signature ();
33
+ auto const & type = sig.ReturnType ().Type ().Type ();
34
+ XLANG_ASSERT (std::holds_alternative<coded_index<TypeDefOrRef>>(type));
35
+ if (std::holds_alternative<coded_index<TypeDefOrRef>>(type))
36
+ {
37
+ guid_TypeRef = std::get<coded_index<TypeDefOrRef>>(type);
38
+ XLANG_ASSERT (guid_TypeRef.type () == TypeDefOrRef::TypeRef);
39
+ XLANG_ASSERT (guid_TypeRef.TypeRef ().TypeNamespace () == " System" );
40
+ XLANG_ASSERT (guid_TypeRef.TypeRef ().TypeName () == " Guid" );
41
+ }
42
+ }
43
+ }
44
+ }
45
+ return guid_TypeRef;
46
+ }
16
47
17
48
void MetadataDiagnostic (DkmProcess* process, std::wstring const & status, std::filesystem::path const & path)
18
49
{
@@ -118,8 +149,9 @@ void LoadMetadata(DkmProcess* process, WCHAR const* processPath, std::string_vie
118
149
}
119
150
}
120
151
121
- TypeDef FindType (DkmProcess* process, std::string_view const & typeName)
152
+ TypeDef FindSimpleType (DkmProcess* process, std::string_view const & typeName)
122
153
{
154
+ XLANG_ASSERT (typeName.find (' <' ) == std::string_view::npos);
123
155
auto type = db_cache->find (typeName);
124
156
if (!type)
125
157
{
@@ -135,19 +167,104 @@ TypeDef FindType(DkmProcess* process, std::string_view const& typeName)
135
167
return type;
136
168
}
137
169
138
- TypeDef FindType (DkmProcess* process, std::string_view const & typeNamespace, std::string_view const & typeName)
170
+ TypeDef FindSimpleType (DkmProcess* process, std::string_view const & typeNamespace, std::string_view const & typeName)
139
171
{
172
+ XLANG_ASSERT (typeName.find (' <' ) == std::string_view::npos);
140
173
auto type = db_cache->find (typeNamespace, typeName);
141
174
if (!type)
142
175
{
143
176
std::string fullName (typeNamespace);
144
177
fullName.append (" ." );
145
178
fullName.append (typeName);
146
- FindType (process, fullName);
179
+ FindSimpleType (process, fullName);
147
180
}
148
181
return type;
149
182
}
150
183
184
+ std::vector<std::string> ParseTypeName (std::string_view name)
185
+ {
186
+ DWORD count;
187
+ HSTRING* parts;
188
+ auto wide_name = winrt::to_hstring (name);
189
+ winrt::check_hresult (::RoParseTypeName (static_cast <HSTRING>(get_abi (wide_name)), &count, &parts));
190
+
191
+ winrt::com_array<winrt::hstring> wide_parts{ parts, count, winrt::take_ownership_from_abi };
192
+ std::vector<std::string> result;
193
+ for (auto && part : wide_parts)
194
+ {
195
+ result.push_back (winrt::to_string (part));
196
+ }
197
+ return result;
198
+ }
199
+
200
+ template <std::input_iterator iter, std::sentinel_for<iter> sent>
201
+ TypeSig ResolveGenericTypePart (DkmProcess* process, iter& it, sent const & end)
202
+ {
203
+ constexpr std::pair<std::string_view, ElementType> elementNames[] = {
204
+ {" Boolean" , ElementType::Boolean},
205
+ {" Int8" , ElementType::I1},
206
+ {" Int16" , ElementType::I2},
207
+ {" Int32" , ElementType::I4},
208
+ {" Int64" , ElementType::I8},
209
+ {" UInt8" , ElementType::U1},
210
+ {" UInt16" , ElementType::U2},
211
+ {" UInt32" , ElementType::U4},
212
+ {" UInt64" , ElementType::U8},
213
+ {" Single" , ElementType::R4},
214
+ {" Double" , ElementType::R8},
215
+ {" String" , ElementType::String},
216
+ {" Char16" , ElementType::Char},
217
+ {" Object" , ElementType::Object}
218
+ };
219
+ std::string_view partName = *it;
220
+ auto basic_type_pos = std::find_if (std::begin (elementNames), std::end (elementNames), [&partName](auto && elem) { return elem.first == partName; });
221
+ if (basic_type_pos != std::end (elementNames))
222
+ {
223
+ return TypeSig{ basic_type_pos->second };
224
+ }
225
+
226
+ if (partName == " Guid" )
227
+ {
228
+ return TypeSig{ FindGuidType () };
229
+ }
230
+
231
+ TypeDef type = FindSimpleType (process, partName);
232
+ auto tickPos = partName.rfind (' `' );
233
+ if (tickPos == partName.npos )
234
+ {
235
+ return TypeSig{ type.coded_index <TypeDefOrRef>() };
236
+ }
237
+
238
+ int paramCount = 0 ;
239
+ std::from_chars (partName.data () + tickPos + 1 , partName.data () + partName.size (), paramCount);
240
+ std::vector<TypeSig> genericArgs;
241
+ for (int i = 0 ; i < paramCount; ++i)
242
+ {
243
+ genericArgs.push_back (ResolveGenericTypePart (process, ++it, end));
244
+ }
245
+ return TypeSig{ GenericTypeInstSig{ type.coded_index <TypeDefOrRef>(), std::move (genericArgs) } };
246
+ }
247
+
248
+ TypeSig ResolveGenericType (DkmProcess* process, std::string_view genericName)
249
+ {
250
+ auto parts = ParseTypeName (genericName);
251
+ auto begin = parts.begin ();
252
+ return ResolveGenericTypePart (process, begin, parts.end ());
253
+ }
254
+
255
+ TypeSig FindType (DkmProcess* process, std::string_view const & typeName)
256
+ {
257
+ auto paramIndex = typeName.find (' <' );
258
+ if (paramIndex == std::string_view::npos)
259
+ {
260
+ return TypeSig{ FindSimpleType (process, typeName).coded_index <TypeDefOrRef>() };
261
+ }
262
+ else
263
+ {
264
+ return ResolveGenericType (process, typeName);
265
+ }
266
+ }
267
+
151
268
cppwinrt_visualizer::cppwinrt_visualizer ()
152
269
{
153
270
try
@@ -187,13 +304,14 @@ cppwinrt_visualizer::cppwinrt_visualizer()
187
304
cppwinrt_visualizer::~cppwinrt_visualizer ()
188
305
{
189
306
ClearTypeResolver ();
307
+ guid_TypeRef = {};
190
308
db_files.clear ();
191
309
db_cache.reset ();
192
310
}
193
311
194
312
HRESULT cppwinrt_visualizer::EvaluateVisualizedExpression (
195
313
_In_ DkmVisualizedExpression* pVisualizedExpression,
196
- _Deref_out_ DkmEvaluationResult** ppResultObject
314
+ _COM_Outptr_result_maybenull_ DkmEvaluationResult** ppResultObject
197
315
)
198
316
{
199
317
try
@@ -233,6 +351,7 @@ HRESULT cppwinrt_visualizer::EvaluateVisualizedExpression(
233
351
// unrecognized type
234
352
NatvisDiagnostic (pVisualizedExpression,
235
353
std::wstring (L" Unrecognized type: " ) + (LPWSTR)bstrTypeName, NatvisDiagnosticLevel::Error);
354
+ *ppResultObject = nullptr ;
236
355
return S_OK;
237
356
}
238
357
0 commit comments