11using System ;
2+ using System . Runtime . InteropServices ;
23using System . Text ;
34using LibGit2Sharp . Core ;
45
@@ -9,45 +10,54 @@ namespace LibGit2Sharp
910 /// </summary>
1011 public sealed class Filter
1112 {
12- private GitFilter filter ;
13- private readonly string name ;
13+ private GitFilter managedFilter ;
14+ private IntPtr nativeFilter ;
15+
16+ private readonly string filterName ;
1417 private readonly string attributes ;
1518 private readonly int version ;
1619
20+
1721 /// <summary>
1822 /// Initializes a new instance of the <see cref="Filter"/> class.
23+ /// And allocates the filter natively.
1924 /// </summary>
2025 public Filter ( string name , string attributes , int version )
2126 {
2227 Ensure . ArgumentNotNullOrEmptyString ( name , "name" ) ;
2328 Ensure . ArgumentNotNullOrEmptyString ( attributes , "attributes" ) ;
2429 Ensure . ArgumentNotNull ( version , "version" ) ;
2530
26- this . name = name ;
31+ this . filterName = name ;
2732 this . attributes = attributes ;
2833 this . version = version ;
29- filter = new GitFilter
34+
35+ managedFilter = new GitFilter
3036 {
3137 attributes = EncodingMarshaler . FromManaged ( Encoding . UTF8 , attributes ) ,
32- version = ( uint ) version
38+ version = ( uint ) version ,
39+ shutdown = FilterCallbacks . ShutdownCallback ,
3340 } ;
41+
42+ nativeFilter = Marshal . AllocHGlobal ( Marshal . SizeOf ( managedFilter ) ) ;
43+ Marshal . StructureToPtr ( managedFilter , nativeFilter , false ) ;
3444 }
3545
3646 internal Filter ( string name , IntPtr filterPtr )
3747 {
38- var handle = filterPtr . MarshalAs < GitFilter > ( ) ;
39- this . name = name ;
40- this . version = ( int ) handle . version ;
41- this . attributes = LaxUtf8Marshaler . FromNative ( handle . attributes ) ;
48+ nativeFilter = filterPtr ;
49+ managedFilter = nativeFilter . MarshalAs < GitFilter > ( ) ;
50+ filterName = name ;
51+ attributes = EncodingMarshaler . FromNative ( Encoding . UTF8 , this . managedFilter . attributes ) ;
52+ version = ( int ) managedFilter . version ;
4253 }
4354
44-
4555 /// <summary>
4656 /// The name that this filter was registered with
4757 /// </summary>
4858 public string Name
4959 {
50- get { return name ; }
60+ get { return filterName ; }
5161 }
5262
5363 /// <summary>
@@ -71,15 +81,30 @@ public int Version
7181 /// </summary>
7282 public void Register ( )
7383 {
74- filter = Proxy . git_filter_register ( name , ref filter , 1 ) ;
84+ Proxy . git_filter_register ( filterName , nativeFilter , 1 ) ;
7585 }
7686
7787 /// <summary>
78- /// Remove the filter from the registry.
88+ /// Remove the filter from the registry, and frees the native heap allocation .
7989 /// </summary>
8090 public void Deregister ( )
8191 {
8292 Proxy . git_filter_unregister ( Name ) ;
93+ Marshal . FreeHGlobal ( nativeFilter ) ;
94+ }
95+
96+ private static class FilterCallbacks
97+ {
98+ // Because our GitFilter structure exists on the managed heap only for a short time (to be marshaled
99+ // to native memory with StructureToPtr), we need to bind to static delegates. If at construction time
100+ // we were to bind to the methods directly, that's the same as newing up a fresh delegate every time.
101+ // Those delegates won't be rooted in the object graph and can be collected as soon as StructureToPtr finishes.
102+ public static readonly GitFilter . git_filter_shutdown_fn ShutdownCallback = Shutdown ;
103+
104+ private static void Shutdown ( IntPtr gitFilter )
105+ {
106+ Console . WriteLine ( "Shut down mother fucker" ) ;
107+ }
83108 }
84109 }
85110
0 commit comments