2019-01-27 00:47:46 -05:00
using System ;
using System.Runtime.InteropServices ;
2019-08-17 16:42:49 -04:00
using Vanara.Extensions.Reflection ;
2019-01-29 21:59:16 -05:00
using Vanara.PInvoke ;
2019-01-27 00:47:46 -05:00
using static Vanara . PInvoke . Ole32 ;
namespace Vanara.Windows.Shell
{
2019-01-31 13:37:30 -05:00
/// <summary>An implementation of <see cref="IClassFactory"/> to be used in conjunction with <see cref="IComObject"/> derivatives.</summary>
2019-01-27 00:47:46 -05:00
/// <seealso cref="Vanara.PInvoke.Ole32.IClassFactory"/>
/// <seealso cref="System.IDisposable"/>
2019-01-31 13:37:30 -05:00
[ComVisible(true)]
public class ComClassFactory : IClassFactory , IDisposable
2019-01-27 00:47:46 -05:00
{
2019-01-31 13:37:30 -05:00
private readonly IComObject comObj ;
2019-01-27 00:47:46 -05:00
private uint registrationId ;
/// <summary>Initializes a new instance of the <see cref="ComClassFactory"/> class.</summary>
/// <param name="punkObject">The COM object that is to be registered as a class object and queried for interfaces.</param>
2019-01-29 21:59:16 -05:00
/// <param name="classContext">The context within which the COM object is to be run.</param>
2019-01-27 00:47:46 -05:00
/// <param name="classUse">Indicates how connections are made to the class object.</param>
2019-01-31 13:37:30 -05:00
public ComClassFactory ( IComObject punkObject , CLSCTX classContext , REGCLS classUse )
2019-01-27 00:47:46 -05:00
{
comObj = punkObject ? ? throw new ArgumentNullException ( nameof ( punkObject ) ) ;
2019-01-31 13:37:30 -05:00
CoRegisterClassObject ( comObj . GetType ( ) . CLSID ( ) , this , classContext , classUse , out registrationId ) . ThrowIfFailed ( ) ;
2019-01-27 00:47:46 -05:00
}
2019-01-31 13:37:30 -05:00
/// <summary>
/// Resumes activation requests for class objects using <see cref="CoResumeClassObjects"/>. Must use
/// <see cref="REGCLS.REGCLS_SUSPENDED"/> in the constructor.
/// </summary>
public void Resume ( ) = > CoResumeClassObjects ( ) . ThrowIfFailed ( ) ;
2019-01-27 00:47:46 -05:00
/// <summary>Creates an uninitialized object.</summary>
/// <param name="pUnkOuter">
2019-01-29 21:59:16 -05:00
/// If the object is being created as part of an aggregate, specify a pointer to the controlling IUnknown interface of the aggregate.
/// Otherwise, this parameter must be <c>NULL</c>.
2019-01-27 00:47:46 -05:00
/// </param>
/// <param name="riid">
/// A reference to the identifier of the interface to be used to communicate with the newly created object. If pUnkOuter is
2019-01-29 21:59:16 -05:00
/// <c>NULL</c>, this parameter is generally the IID of the initializing interface; if pUnkOuter is non- <c>NULL</c>, <paramref name="riid"/>
/// must be IID_IUnknown.
2019-01-27 00:47:46 -05:00
/// </param>
2019-06-25 19:28:19 -04:00
/// <param name="ppv">
2019-01-29 21:59:16 -05:00
/// The address of pointer variable that receives the interface pointer requested in <paramref name="riid"/>. Upon successful return, *ppvObject
/// contains the requested interface pointer. If the object does not support the interface specified in <paramref name="riid"/>, the implementation must
/// set *ppvObject to <c>NULL</c>.
2019-01-27 00:47:46 -05:00
/// </param>
/// <returns>
/// <para>
/// This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, and E_UNEXPECTED, as well as the following values.
/// </para>
/// <list type="table">
/// <listheader>
/// <term>Return code</term>
/// <term>Description</term>
/// </listheader>
/// <item>
/// <term>S_OK</term>
/// <term>The specified object was created.</term>
/// </item>
/// <item>
/// <term>CLASS_E_NOAGGREGATION</term>
/// <term>The pUnkOuter parameter was non-NULL and the object does not support aggregation.</term>
/// </item>
/// <item>
/// <term>E_NOINTERFACE</term>
2019-01-29 21:59:16 -05:00
/// <term>The object that ppvObject points to does not support the interface identified by <paramref name="riid"/>.</term>
2019-01-27 00:47:46 -05:00
/// </item>
/// </list>
/// </returns>
2019-06-25 19:28:19 -04:00
HRESULT IClassFactory . CreateInstance ( object pUnkOuter , in Guid riid , out object ppv )
2019-01-27 00:47:46 -05:00
{
2019-01-31 13:37:30 -05:00
System . Diagnostics . Debug . WriteLine ( $"IClassFactory.CreateInstance: riid={riid:B}" ) ;
2019-01-27 00:47:46 -05:00
ppv = null ;
2019-06-25 19:28:19 -04:00
if ( ! ( pUnkOuter is null ) ) return HRESULT . CLASS_E_NOAGGREGATION ;
2019-01-27 00:47:46 -05:00
try
{
ppv = comObj . QueryInterface ( riid ) ;
2019-01-31 13:37:30 -05:00
System . Diagnostics . Debug . WriteLine ( $"IClassFactory.CreateInstance: out ppv={ppv?.GetType().Name}" ) ;
2019-01-27 00:47:46 -05:00
}
catch ( Exception e )
{
return e . GetPropertyValue < int > ( "HResult" ) ;
}
return HRESULT . S_OK ;
}
2019-01-29 21:59:16 -05:00
/// <inheritdoc/>
2019-01-31 13:37:30 -05:00
void IDisposable . Dispose ( )
2019-01-29 21:59:16 -05:00
{
if ( registrationId = = 0 ) return ;
CoRevokeClassObject ( registrationId ) ;
registrationId = 0 ;
}
2019-01-27 00:47:46 -05:00
/// <summary>Locks an object application open in memory. This enables instances to be created more quickly.</summary>
/// <param name="fLock">If <c>TRUE</c>, increments the lock count; if <c>FALSE</c>, decrements the lock count.</param>
/// <returns>This method can return the standard return values E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK.</returns>
/// <remarks>
2019-01-29 21:59:16 -05:00
/// <c>IClassFactory::LockServer</c> controls whether an object's server is kept in memory. Keeping the application alive in memory
/// allows instances to be created more quickly.
2019-01-27 00:47:46 -05:00
/// </remarks>
2019-01-31 13:37:30 -05:00
HRESULT IClassFactory . LockServer ( bool fLock )
2019-01-27 00:47:46 -05:00
{
if ( fLock )
2019-01-31 13:37:30 -05:00
{
2019-01-27 00:47:46 -05:00
CoAddRefServerProcess ( ) ;
2019-01-31 13:37:30 -05:00
}
2019-01-27 00:47:46 -05:00
else
{
if ( 0 = = CoReleaseServerProcess ( ) )
comObj ? . QuitMessageLoop ( ) ;
}
return HRESULT . S_OK ;
}
}
}