@@ -11,8 +11,39 @@ using namespace std::filesystem;
1111using namespace winrt ;
1212using namespace winmd ::reader;
1313
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+ }
1647
1748void MetadataDiagnostic (DkmProcess* process, std::wstring const & status, std::filesystem::path const & path)
1849{
@@ -118,8 +149,9 @@ void LoadMetadata(DkmProcess* process, WCHAR const* processPath, std::string_vie
118149 }
119150}
120151
121- TypeDef FindType (DkmProcess* process, std::string_view const & typeName)
152+ TypeDef FindSimpleType (DkmProcess* process, std::string_view const & typeName)
122153{
154+ XLANG_ASSERT (typeName.find (' <' ) == std::string_view::npos);
123155 auto type = db_cache->find (typeName);
124156 if (!type)
125157 {
@@ -135,19 +167,104 @@ TypeDef FindType(DkmProcess* process, std::string_view const& typeName)
135167 return type;
136168}
137169
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)
139171{
172+ XLANG_ASSERT (typeName.find (' <' ) == std::string_view::npos);
140173 auto type = db_cache->find (typeNamespace, typeName);
141174 if (!type)
142175 {
143176 std::string fullName (typeNamespace);
144177 fullName.append (" ." );
145178 fullName.append (typeName);
146- FindType (process, fullName);
179+ FindSimpleType (process, fullName);
147180 }
148181 return type;
149182}
150183
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+
151268cppwinrt_visualizer::cppwinrt_visualizer ()
152269{
153270 try
@@ -187,13 +304,14 @@ cppwinrt_visualizer::cppwinrt_visualizer()
187304cppwinrt_visualizer::~cppwinrt_visualizer ()
188305{
189306 ClearTypeResolver ();
307+ guid_TypeRef = {};
190308 db_files.clear ();
191309 db_cache.reset ();
192310}
193311
194312HRESULT cppwinrt_visualizer::EvaluateVisualizedExpression (
195313 _In_ DkmVisualizedExpression* pVisualizedExpression,
196- _Deref_out_ DkmEvaluationResult** ppResultObject
314+ _COM_Outptr_result_maybenull_ DkmEvaluationResult** ppResultObject
197315)
198316{
199317 try
@@ -233,6 +351,7 @@ HRESULT cppwinrt_visualizer::EvaluateVisualizedExpression(
233351 // unrecognized type
234352 NatvisDiagnostic (pVisualizedExpression,
235353 std::wstring (L" Unrecognized type: " ) + (LPWSTR)bstrTypeName, NatvisDiagnosticLevel::Error);
354+ *ppResultObject = nullptr ;
236355 return S_OK;
237356 }
238357
0 commit comments