// 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
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using SharpGen.Runtime.Diagnostics;
namespace SharpGen.Runtime
{
///
/// Root IUnknown class to interop with COM object
///
public partial class ComObject
{
///
/// Initializes a new instance of the class from a IUnknown object.
///
/// Reference to a IUnknown object
public ComObject(object iunknownObject)
{
NativePointer = Marshal.GetIUnknownForObject(iunknownObject);
}
///
/// Initializes a new instance of the class.
///
protected ComObject()
{
}
///
/// Query instance for a particular COM GUID/interface support.
///
/// GUID query interface
/// If this object doesn't support the interface
/// ms682521
/// IUnknown::QueryInterface
/// IUnknown::QueryInterface
public virtual IntPtr QueryInterfaceOrNull(Guid guid)
{
var pointer = IntPtr.Zero;
QueryInterface(guid, out pointer);
return pointer;
}
///
/// Compares 2 COM objects and return true if the native pointer is the same.
///
/// The left.
/// The right.
/// true if the native pointer is the same, false otherwise
public static bool EqualsComObject(T left, T right) where T : ComObject
{
if (Equals(left, right))
{
return true;
}
if (left == null || right == null)
{
return false;
}
return (left.NativePointer == right.NativePointer);
}
///
/// Query this instance for a particular COM interface support.
///
///The type of the COM interface to query
///An instance of the queried interface
/// If this object doesn't support the interface
/// ms682521
/// IUnknown::QueryInterface
/// IUnknown::QueryInterface
public virtual T QueryInterface() where T : ComObject
{
IntPtr parentPtr;
var result = this.QueryInterface(typeof(T).GetTypeInfo().GUID, out parentPtr);
result.CheckError();
return FromPointer(parentPtr);
}
///
/// Queries a managed object for a particular COM interface support (This method is a shortcut to )
///
///The type of the COM interface to query
/// The managed COM object.
///An instance of the queried interface
/// ms682521
/// IUnknown::QueryInterface
/// IUnknown::QueryInterface
public static T As(object comObject) where T : ComObject
{
using (var tempObject = new ComObject(Marshal.GetIUnknownForObject(comObject)))
{
return tempObject.QueryInterface();
}
}
///
/// Queries a managed object for a particular COM interface support (This method is a shortcut to )
///
///The type of the COM interface to query
/// The managed COM object.
///An instance of the queried interface
/// ms682521
/// IUnknown::QueryInterface
/// IUnknown::QueryInterface
public static T As(IntPtr iunknownPtr) where T : ComObject
{
using (var tempObject = new ComObject(iunknownPtr))
{
return tempObject.QueryInterface();
}
}
///
/// Queries a managed object for a particular COM interface support.
///
///The type of the COM interface to query
/// The managed COM object.
///An instance of the queried interface
/// ms682521
/// IUnknown::QueryInterface
/// IUnknown::QueryInterface
public static T QueryInterface(object comObject) where T : ComObject
{
using (var tempObject = new ComObject(Marshal.GetIUnknownForObject(comObject)))
{
return tempObject.QueryInterface();
}
}
///
/// Queries a managed object for a particular COM interface support.
///
///The type of the COM interface to query
/// A pointer to a COM object.
///An instance of the queried interface
/// ms682521
/// IUnknown::QueryInterface
/// IUnknown::QueryInterface
public static T QueryInterfaceOrNull(IntPtr comPointer) where T : ComObject
{
if (comPointer == IntPtr.Zero)
{
return null;
}
var guid = typeof(T).GetTypeInfo().GUID;
IntPtr pointerT;
var result = (Result)Marshal.QueryInterface(comPointer, ref guid, out pointerT);
return (result.Failure) ? null : FromPointer(pointerT);
}
///
/// Query Interface for a particular interface support.
///
///An instance of the queried interface or null if it is not supported
///
/// ms682521
/// IUnknown::QueryInterface
/// IUnknown::QueryInterface
public virtual T QueryInterfaceOrNull() where T : ComObject
{
return FromPointer(QueryInterfaceOrNull(typeof(T).GetTypeInfo().GUID));
}
///
/// Query Interface for a particular interface support and attach to the given instance.
///
///
///
protected void QueryInterfaceFrom(T fromObject) where T : ComObject
{
IntPtr parentPtr;
fromObject.QueryInterface(this.GetType().GetTypeInfo().GUID, out parentPtr);
NativePointer = parentPtr;
}
///
/// Releases unmanaged and - optionally - managed resources
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
/// ms682317
/// IUnknown::Release
/// IUnknown::Release
protected unsafe override void Dispose(bool disposing)
{
// Only dispose non-zero object
if (NativePointer != IntPtr.Zero)
{
// If object is disposed by the finalizer, emits a warning
if(!disposing && Configuration.EnableTrackingReleaseOnFinalizer)
{
if(!Configuration.EnableReleaseOnFinalizer)
{
var objectReference = ObjectTracker.Find(this);
LogMemoryLeakWarning?.Invoke(string.Format("Warning: Live ComObject [0x{0:X}], potential memory leak: {1}", NativePointer.ToInt64(), objectReference));
}
}
// Release the object
if (disposing || Configuration.EnableReleaseOnFinalizer)
((IUnknown)this).Release();
// Untrack the object
if (Configuration.EnableObjectTracking)
ObjectTracker.UnTrack(this);
// Set pointer to null (using protected members in order to avoid NativePointerUpdat* callbacks.
_nativePointer = (void*)0;
}
base.Dispose(disposing);
}
}
}