using System;
using System.Runtime.InteropServices;
using Vanara.Extensions;
using Vanara.PInvoke;
using static Vanara.PInvoke.Ole32;
using static Vanara.PInvoke.Shell32;
namespace Vanara.Windows.Shell
{
/// Exposed methods from .
[ComVisible(false)]
public interface IComObject
{
/// Creates an uninitialized object.
///
/// A reference to the identifier of the interface to be used to communicate with the newly created object. This parameter is
/// generally the IID of the initializing interface.
///
///
/// The interface pointer requested in . If the object does not support the interface specified in
/// , the implementation must return .
///
object QueryInterface(in Guid riid);
/// Quits the message loop by sending PostQuitMessage.
/// The exit code.
void QuitMessageLoop(int exitCode = 0);
/// Runs the message loop.
///
/// The time span after which the message loop will be terminated. If this value equals TimeSpan.Zero or is not specified, the
/// message loop will run until the method is called or the message loop receives a quit message.
///
void Run(TimeSpan timeout = default);
}
///
/// Base class for all COM objects which handles calling AddRef and Release for the assembly, connection to IClassFactory, implements
/// IObjectWithSite, using an internal message loop, and a mechanism to issue a non-blocking call to itself. Once implemented, you only
/// need to implement your own interfaces. The IClassFactory implementation can get any derived interfaces through casting for calls to
/// its QueryInterface method. If you want more control, override the QueryInterface method in this class.
///
///
///
public abstract class ComObject : IComObject, IDisposable, IObjectWithSite
{
private readonly CLSCTX ctx;
private readonly REGCLS use;
private bool disposedValue = false;
private MessageLoop msgLoop = new();
/// Initializes a new instance of the class.
protected ComObject() : this(CLSCTX.CLSCTX_LOCAL_SERVER, REGCLS.REGCLS_MULTIPLEUSE | REGCLS.REGCLS_SUSPENDED)
{
}
/// Initializes a new instance of the class.
/// The context within which the COM object is to be run.
/// Indicates how connections are made to the class object.
protected ComObject(CLSCTX classContext, REGCLS classUse)
{
ctx = classContext;
use = classUse;
CoAddRefServerProcess();
}
/// Gets or sets the site exposed by .
/// The site object.
public virtual object Site { get; set; }
///
/// Cancels the timeout specified in the method. This should be called when the application knows that it wants to
/// keep running, for example when it receives the incoming call to invoke the verb.
///
public void CancelTimeout() => msgLoop.CancelTimeout();
/// Creates an uninitialized object.
///
/// A reference to the identifier of the interface to be used to communicate with the newly created object. This parameter is
/// generally the IID of the initializing interface.
///
///
/// The interface pointer requested in . If the object does not support the interface specified in
/// , the implementation must return .
///
public virtual object QueryInterface(in Guid riid) => ShellUtil.QueryInterface(this, riid);
///
/// Queues a non-blocking callback. This is useful in situations where a method cannot block an implemented method but further
/// processing is needed. For example, IDropTarget::DragDrop and IExecuteCommand::Execute.
///
/// The callback method.
/// An optional object that will be passed to the callback.
public void QueueNonBlockingCallback(Action