I'm working with a C++ solution, based on STL, and I'm using CPtrList collections.
I have here a CPtrList collection, containing void *
entries, and I would like to typecast those automatically using a natvis file.
Currently, my natvis looks as follows:
<Type Name="CList<*,*>">
<AlternativeType Name="CObList"></AlternativeType>
<AlternativeType Name="CPtrList"></AlternativeType>
<AlternativeType Name="CStringList"></AlternativeType>
<AlternativeType Name="CTypedPtrList<*,*>"></AlternativeType>
<DisplayString>{{iets anders Count = {m_nCount}}}</DisplayString>
<Expand>
<Item Name="Count">m_nCount</Item>
<LinkedListItems>
<Size>m_nCount</Size>
<HeadPointer>m_pNodeHead</HeadPointer>
<NextPointer>pNext</NextPointer>
<ValueNode>data</ValueNode>
</LinkedListItems>
</Expand>
</Type>
As a result the entries of my CPtrList look like the following:
0x<something> void *
0x<something else> void *
...
I would like to have the entries typecasted into something like this:
<information> CElement::SL_SET_PARAMETER*
<information else> CElement::SL_SET_PARAMETER*
Once I know how to get this done, I can add a "SL_SET_PARAMETER" entry in my natvis and decide how to display this, but therefore I first need to explain to natvis that every CPtrList entry should be casted into a "SL_SET_PARAMETER" object.
Does anybody know how to do this?
You would have to use a <CustomListItems>
tag (see CustomListItems expansion item in the MS documentation for more details). This is the most generic specification of a displayed type which allows local variables and looping.
The example that they use in their documentation is as follows:
<Type Name="ATL::CAtlMap<*,*,*,*>">
<AlternativeType Name="ATL::CMapToInterface<*,*,*>"/>
<AlternativeType Name="ATL::CMapToAutoPtr<*,*,*>"/>
<DisplayString>{{Count = {m_nElements}}}</DisplayString>
<Expand>
<CustomListItems MaxItemsPerView="5000" ExcludeView="Test">
<Variable Name="iBucket" InitialValue="-1" />
<Variable Name="pBucket" InitialValue="m_ppBins == nullptr ? nullptr : *m_ppBins" />
<Variable Name="iBucketIncrement" InitialValue="-1" />
<Size>m_nElements</Size>
<Exec>pBucket = nullptr</Exec>
<Loop>
<If Condition="pBucket == nullptr">
<Exec>iBucket++</Exec>
<Exec>iBucketIncrement = __findnonnull(m_ppBins + iBucket, m_nBins - iBucket)</Exec>
<Break Condition="iBucketIncrement == -1" />
<Exec>iBucket += iBucketIncrement</Exec>
<Exec>pBucket = m_ppBins[iBucket]</Exec>
</If>
<Item>pBucket,na</Item>
<Exec>pBucket = pBucket->m_pNext</Exec>
</Loop>
</CustomListItems>
</Expand>
</Type>
The only minor issue it has is that if you copy the expression that this creates from a watch window, it will look like a number casted to a pointer of the type you wanted, instead of having a nice looking array like syntax and as such will result in it not being updated if the memory location moves. If you reference a parent containing object, this isn't a big deal, just annoying.