using System; using System.Runtime.InteropServices; using Vanara.Extensions.Reflection; using Vanara.PInvoke; using static Vanara.PInvoke.Ole32; namespace Vanara.Windows.Shell { /// An implementation of to be used in conjunction with derivatives. /// /// [ComVisible(true)] public class ComClassFactory : IClassFactory, IDisposable { private readonly IComObject comObj; private uint registrationId; /// Initializes a new instance of the class. /// The COM object that is to be registered as a class object and queried for interfaces. /// The context within which the COM object is to be run. /// Indicates how connections are made to the class object. public ComClassFactory(IComObject punkObject, CLSCTX classContext, REGCLS classUse) { comObj = punkObject ?? throw new ArgumentNullException(nameof(punkObject)); CoRegisterClassObject(comObj.GetType().CLSID(), this, classContext, classUse, out registrationId).ThrowIfFailed(); } /// /// Resumes activation requests for class objects using . Must use /// in the constructor. /// public void Resume() => CoResumeClassObjects().ThrowIfFailed(); /// Creates an uninitialized object. /// /// 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 NULL. /// /// /// A reference to the identifier of the interface to be used to communicate with the newly created object. If pUnkOuter is /// NULL, this parameter is generally the IID of the initializing interface; if pUnkOuter is non- NULL, /// must be IID_IUnknown. /// /// /// The address of pointer variable that receives the interface pointer requested in . Upon successful return, *ppvObject /// contains the requested interface pointer. If the object does not support the interface specified in , the implementation must /// set *ppvObject to NULL. /// /// /// /// This method can return the standard return values E_INVALIDARG, E_OUTOFMEMORY, and E_UNEXPECTED, as well as the following values. /// /// /// /// Return code /// Description /// /// /// S_OK /// The specified object was created. /// /// /// CLASS_E_NOAGGREGATION /// The pUnkOuter parameter was non-NULL and the object does not support aggregation. /// /// /// E_NOINTERFACE /// The object that ppvObject points to does not support the interface identified by . /// /// /// HRESULT IClassFactory.CreateInstance(object pUnkOuter, in Guid riid, out object ppv) { System.Diagnostics.Debug.WriteLine($"IClassFactory.CreateInstance: riid={riid:B}"); ppv = null; if (!(pUnkOuter is null)) return HRESULT.CLASS_E_NOAGGREGATION; try { ppv = comObj.QueryInterface(riid); System.Diagnostics.Debug.WriteLine($"IClassFactory.CreateInstance: out ppv={ppv?.GetType().Name}"); } catch (Exception e) { return e.GetPropertyValue("HResult"); } return HRESULT.S_OK; } /// void IDisposable.Dispose() { if (registrationId == 0) return; CoRevokeClassObject(registrationId); registrationId = 0; } /// Locks an object application open in memory. This enables instances to be created more quickly. /// If TRUE, increments the lock count; if FALSE, decrements the lock count. /// This method can return the standard return values E_OUTOFMEMORY, E_UNEXPECTED, E_FAIL, and S_OK. /// /// IClassFactory::LockServer controls whether an object's server is kept in memory. Keeping the application alive in memory /// allows instances to be created more quickly. /// HRESULT IClassFactory.LockServer(bool fLock) { if (fLock) { CoAddRefServerProcess(); } else { if (0 == CoReleaseServerProcess()) comObj?.QuitMessageLoop(); } return HRESULT.S_OK; } } }