1
1
using System ;
2
2
using System . Collections . Concurrent ;
3
+ using System . Collections . Generic ;
3
4
using System . Runtime . CompilerServices ;
4
5
using Rubberduck . VBEditor . SafeComWrappers . Abstract ;
5
6
6
7
#if DEBUG
8
+ using System . Diagnostics ;
7
9
using System . Linq ;
8
10
using System . Runtime . InteropServices ;
9
11
#endif
@@ -15,14 +17,27 @@ public class WeakComSafe : IComSafe
15
17
//We use weak references to allow the GC to reclaim RCWs earlier if possible.
16
18
private readonly ConcurrentDictionary < int , ( DateTime insertTime , WeakReference < ISafeComWrapper > weakRef ) > _comWrapperCache = new ConcurrentDictionary < int , ( DateTime , WeakReference < ISafeComWrapper > ) > ( ) ;
17
19
20
+ #if DEBUG
21
+ private IEnumerable < string > trace = null ;
22
+ #endif
23
+
18
24
public void Add ( ISafeComWrapper comWrapper )
19
25
{
20
26
if ( comWrapper != null )
21
27
{
28
+ #if DEBUG
29
+ trace = GetStackTrace ( 3 , 3 ) ;
30
+ #endif
22
31
_comWrapperCache . AddOrUpdate (
23
32
GetComWrapperObjectHashCode ( comWrapper ) ,
24
33
key => ( DateTime . UtcNow , new WeakReference < ISafeComWrapper > ( comWrapper ) ) ,
25
- ( key , value ) => ( value . insertTime , new WeakReference < ISafeComWrapper > ( comWrapper ) ) ) ;
34
+ ( key , value ) =>
35
+ {
36
+ #if DEBUG
37
+ Debug . Assert ( false ) ;
38
+ #endif
39
+ return ( value . insertTime , new WeakReference < ISafeComWrapper > ( comWrapper ) ) ;
40
+ } ) ;
26
41
}
27
42
28
43
}
@@ -71,18 +86,39 @@ public void Serialize()
71
86
{
72
87
using ( var stream = System . IO . File . AppendText ( $ "comSafeOutput { DateTime . UtcNow : yyyyMMddhhmmss} .csv") )
73
88
{
74
- stream . WriteLine ( "Ordinal\t Key\t COM Wrapper Type\t Wrapping Null?\t IUnknown Pointer Address" ) ;
89
+ stream . WriteLine ( "Ordinal\t Key\t COM Wrapper Type\t Wrapping Null?\t IUnknown Pointer Address\t Level 1 \t Level 2 \t Level 3 " ) ;
75
90
var i = 0 ;
76
91
foreach ( var kvp in _comWrapperCache . OrderBy ( kvp => kvp . Value . insertTime ) )
77
92
{
78
93
var line = kvp . Value . weakRef . TryGetTarget ( out var target )
79
- ? $ "{ i ++ } \t { kvp . Key } \t \" { target . GetType ( ) . FullName } \" \t \" { target . IsWrappingNullReference } \" \t \" { ( target . IsWrappingNullReference ? "null" : GetPtrAddress ( target . Target ) ) } \" "
80
- : $ "{ i ++ } \t { kvp . Key } \t \" null\" \t \" null\" \t \" null\" ";
94
+ ? $ "{ i ++ } \t { kvp . Key } \t \" { target . GetType ( ) . FullName } \" \t \" { target . IsWrappingNullReference } \" \t \" { ( target . IsWrappingNullReference ? "null" : GetPtrAddress ( target . Target ) ) } \" \t \" { string . Join ( " \" \t \" " , trace ) } \" "
95
+ : $ "{ i ++ } \t { kvp . Key } \t \" null\" \t \" null\" \t \" null\" \t \" { string . Join ( " \" \t \" " , trace ) } \" ";
81
96
stream . WriteLine ( line ) ;
82
97
}
83
98
}
84
99
}
85
100
101
+ private static IEnumerable < string > GetStackTrace ( int frames , int offset )
102
+ {
103
+ var list = new List < string > ( ) ;
104
+ var trace = new StackTrace ( ) ;
105
+ if ( ( trace . FrameCount - offset ) < frames )
106
+ {
107
+ frames = ( trace . FrameCount - offset ) ;
108
+ }
109
+
110
+ for ( var i = 1 ; i <= frames ; i ++ )
111
+ {
112
+ var frame = trace . GetFrame ( i + offset ) ;
113
+ var typeName = frame . GetMethod ( ) . DeclaringType ? . FullName ?? string . Empty ;
114
+ var methodName = frame . GetMethod ( ) . Name ;
115
+
116
+ var qualifiedName = $ "{ typeName } { ( typeName . Length > 0 ? "::" : string . Empty ) } { methodName } ";
117
+ list . Add ( qualifiedName ) ;
118
+ }
119
+ return list ;
120
+ }
121
+
86
122
private static string GetPtrAddress ( object target )
87
123
{
88
124
if ( target == null )
0 commit comments