diff --git a/ComMarshallingHelpers.cs b/ComMarshallingHelpers.cs
new file mode 100644
index 0000000..5cae1db
--- /dev/null
+++ b/ComMarshallingHelpers.cs
@@ -0,0 +1,88 @@
+using System;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+namespace SharpGen.Runtime
+{
+ public static class ComMarshallingHelpers
+ {
+ ///
+ /// Instantiate a CppObject from a native pointer.
+ ///
+ /// The CppObject class that will be returned
+ /// The native pointer to a com object.
+ /// An instance of T binded to the native pointer
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static T FromPointer(IntPtr cppObjectPtr) where T : CppObject
+ {
+ return MarshallingHelpers.FromPointer(cppObjectPtr);
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static IntPtr ToCallbackPtr(ComObject comObject)
+ where TCallback : ICallbackable
+ {
+ if (comObject == null)
+ return IntPtr.Zero;
+ // do not create extra object in case of the same type
+ if (comObject.GetType() != typeof(TCallback))
+ {
+ var interfacePtr = comObject.QueryInterfaceOrNull(typeof (TCallback).GetTypeInfo().GUID);
+ var newInterface = (TCallback)Activator.CreateInstance(typeof(TCallback), interfacePtr);
+ // New pointer given from QI has one extra reference, so we need to release it, but we also need to create a holder for this pointer to make proper AddRef/Release in finalizer
+ if (!(newInterface is ComObject newComObject))
+ throw new InvalidOperationException("Created object is now COM object");
+ newComObject.Release();
+ return newComObject.NativePointer;
+ }
+ return comObject.NativePointer;
+ }
+
+ ///
+ /// Return the unmanaged C++ pointer from a instance.
+ ///
+ /// The type of the callback.
+ /// The callback.
+ /// A pointer to the unmanaged C++ object of the callback
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static IntPtr ToCallbackPtr(ICallbackable callback)
+ where TCallback : ICallbackable
+ {
+ // we have to make QI to normalize pointer when passing COM object into COM call
+ if (callback is ComObject comObject)
+ {
+ return ToCallbackPtr(comObject);
+ }
+ return MarshallingHelpers.ToCallbackPtr(callback);
+ }
+
+ ///
+ /// Return the unmanaged C++ pointer from a instance.
+ ///
+ /// The type of the callback.
+ /// The object.
+ /// A pointer to the unmanaged C++ object of the callback
+ /// This method is meant as a fast-path for codegen to use to reduce the number of casts.
+ public static IntPtr ToCallbackPtr(CppObject obj)
+ where TCallback : ICallbackable
+ {
+ return ToCallbackPtr((ICallbackable) obj);
+ }
+
+ ///
+ /// Makes additional transformation for the object which was unmarshalled from unmanaged code
+ ///
+ ///
+ /// Indicates that the object was obtained via 'Obj**' parameter
+ /// Transformed object
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static T TransformObjectFromUnmanaged(T obj, bool isOutParam) where T : CppObject
+ {
+ // objects returned via Obj** has one extra AddRef, so we need to call Release to balance references
+ if (isOutParam && obj is ComObject comObject)
+ comObject.Release();
+ return obj;
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/ComObject.cs b/ComObject.cs
index 99899a0..b8b7b52 100644
--- a/ComObject.cs
+++ b/ComObject.cs
@@ -1,4 +1,4 @@
-// Copyright (c) 2010-2014 SharpDX - Alexandre Mutel
+// Copyright (c) 2010-2014 SharpDX - Alexandre Mutel
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -95,7 +95,7 @@ public virtual T QueryInterface() where T : ComObject
IntPtr parentPtr;
var result = this.QueryInterface(typeof(T).GetTypeInfo().GUID, out parentPtr);
result.CheckError();
- return FromPointer(parentPtr);
+ return MarshallingHelpers.FromPointer(parentPtr);
}
///
@@ -168,7 +168,7 @@ public static T QueryInterfaceOrNull(IntPtr comPointer) where T : ComObject
var guid = typeof(T).GetTypeInfo().GUID;
IntPtr pointerT;
var result = (Result)Marshal.QueryInterface(comPointer, ref guid, out pointerT);
- return (result.Failure) ? null : FromPointer(pointerT);
+ return (result.Failure) ? null : ComMarshallingHelpers.FromPointer(pointerT);
}
///
@@ -181,7 +181,7 @@ public static T QueryInterfaceOrNull(IntPtr comPointer) where T : ComObject
/// IUnknown::QueryInterface
public virtual T QueryInterfaceOrNull() where T : ComObject
{
- return FromPointer(QueryInterfaceOrNull(typeof(T).GetTypeInfo().GUID));
+ return ComMarshallingHelpers.FromPointer(QueryInterfaceOrNull(typeof(T).GetTypeInfo().GUID));
}
///
@@ -196,6 +196,24 @@ protected void QueryInterfaceFrom(T fromObject) where T : ComObject
NativePointer = parentPtr;
}
+ // Called with old ptr
+ protected override unsafe void NativePointerUpdating()
+ {
+ // make Release when dropping the pointer
+ if (_nativePointer != null)
+ Release();
+ base.NativePointerUpdating();
+ }
+
+ // Called with new ptr
+ protected override unsafe void NativePointerUpdated(IntPtr oldNativePointer)
+ {
+ // when taking new pointer need to make AddRef
+ if (_nativePointer != null)
+ AddRef();
+ base.NativePointerUpdated(oldNativePointer);
+ }
+
///
/// Releases unmanaged and - optionally - managed resources
///
diff --git a/SharpGen.Runtime.COM.csproj b/SharpGen.Runtime.COM.csproj
index ace4edf..50ef33d 100644
--- a/SharpGen.Runtime.COM.csproj
+++ b/SharpGen.Runtime.COM.csproj
@@ -15,5 +15,7 @@
-
+
+
+