Skip to content

Commit 5481b58

Browse files
committed
Use SafeHandle to hold pointer to native delegates.
1 parent d6b5a18 commit 5481b58

File tree

1 file changed

+23
-20
lines changed

1 file changed

+23
-20
lines changed

Reinterop~/CustomDelegateGenerator.cs

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ private void GenerateDelegate(CppGenerationContext context, GeneratedResult resu
7272
"""
7373
));
7474

75-
// A a C# delegate type that wraps a std::function, and arrange for
75+
// A C# delegate type that wraps a std::function, and arrange for
7676
// the invoke and dispose to be implemented in C++.
7777
CSharpType csType = CSharpType.FromSymbol(context, item.Type);
7878

@@ -88,7 +88,7 @@ private void GenerateDelegate(CppGenerationContext context, GeneratedResult resu
8888
string disposeCallbackName = $"{csType.GetFullyQualifiedNamespace().Replace(".", "_")}_{item.Type.Name}{genericTypeHash}_DisposeCallback";
8989

9090
var invokeParameters = callbackParameters.Select(p => $"{p.CsType.GetFullyQualifiedName()} {p.Name}");
91-
var invokeInteropParameters = new[] { "IntPtr callbackFunction" }.Concat(callbackParameters.Select(p => $"{p.CsType.AsInteropTypeParameter().GetFullyQualifiedName()} {p.Name}"));
91+
var invokeInteropParameters = new[] { "ImplementationHandle callbackFunction" }.Concat(callbackParameters.Select(p => $"{p.CsType.AsInteropTypeParameter().GetFullyQualifiedName()} {p.Name}"));
9292
var callInvokeInteropParameters = new[] { "_callbackFunction" }.Concat(callbackParameters.Select(p => p.CsType.GetConversionToInteropType(p.Name)));
9393
var csReturnType = CSharpType.FromSymbol(context, invokeMethod.ReturnType);
9494

@@ -109,31 +109,34 @@ private void GenerateDelegate(CppGenerationContext context, GeneratedResult resu
109109
$$"""
110110
private class {{csType.Name}}{{genericTypeHash}}NativeFunction : System.IDisposable
111111
{
112-
private IntPtr _callbackFunction;
113-
114-
public {{csType.Name}}{{genericTypeHash}}NativeFunction(IntPtr callbackFunction)
112+
internal class ImplementationHandle : Microsoft.Win32.SafeHandles.SafeHandleZeroOrMinusOneIsInvalid
115113
{
116-
_callbackFunction = callbackFunction;
117-
}
114+
public ImplementationHandle(IntPtr nativeImplementation) : base(true)
115+
{
116+
SetHandle(nativeImplementation);
117+
}
118118
119-
~{{csType.Name}}{{genericTypeHash}}NativeFunction()
120-
{
121-
Dispose(false);
119+
[System.Runtime.ConstrainedExecution.ReliabilityContract(System.Runtime.ConstrainedExecution.Consistency.WillNotCorruptState, System.Runtime.ConstrainedExecution.Cer.Success)]
120+
protected override bool ReleaseHandle()
121+
{
122+
{{disposeCallbackName}}(this.handle);
123+
return true;
124+
}
122125
}
123-
124-
public void Dispose()
126+
127+
[System.NonSerialized]
128+
private ImplementationHandle _callbackFunction;
129+
130+
public {{csType.Name}}{{genericTypeHash}}NativeFunction(IntPtr callbackFunction)
125131
{
126-
Dispose(true);
127-
GC.SuppressFinalize(this);
132+
_callbackFunction = new ImplementationHandle(callbackFunction);
128133
}
129134
130-
private void Dispose(bool disposing)
135+
public void Dispose()
131136
{
132-
if (_callbackFunction != IntPtr.Zero)
133-
{
134-
{{disposeCallbackName}}(_callbackFunction);
135-
_callbackFunction = IntPtr.Zero;
136-
}
137+
if (this._callbackFunction != null && !this._callbackFunction.IsInvalid)
138+
this._callbackFunction.Dispose();
139+
this._callbackFunction = null;
137140
}
138141
139142
public {{csReturnType.GetFullyQualifiedName()}} Invoke({{string.Join(", ", invokeParameters)}})

0 commit comments

Comments
 (0)