mirror of https://github.com/dahall/Vanara.git
Removed OnXXX methods in favor of events, fixed bug in Drop, added example in docs
parent
7dcab68cd3
commit
15b3a02b86
|
@ -13,12 +13,95 @@ namespace Vanara.Windows.Shell
|
|||
/// their equivalent On[MethodName] equivalents. To specialize their handling, simply override the On[MethodName] method or hook an event
|
||||
/// to the corresponding event.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This class provides an easy means of creating a COM based out-of-process DropTarget.
|
||||
/// <list type="number">
|
||||
/// <item>Create a .NET application project.</item>
|
||||
/// <item>Delete the Program.cs file that includes the Main method.</item>
|
||||
/// <item>Create a new class and derive it from <see cref="ShellDropTarget"/> with the attributes in the example below.</item>
|
||||
/// </list>
|
||||
/// <para><b>Example:</b></para>
|
||||
/// <code title="Example">[Guid("<Your GUID here>"), ClassInterface(ClassInterfaceType.None)]
|
||||
///public class MyDropTarget : ShellDropTarget
|
||||
///{
|
||||
/// // In your constructor, be sure to override the DragEnter and DragDrop events and set the effect you desire.
|
||||
/// public MyDropTarget() : base()
|
||||
/// {
|
||||
/// // Setting the effect to Copy here ensure we continue to get drag/drop messages
|
||||
/// DragEnter += (s, e) => e.Effect = DragDropEffects.Copy;
|
||||
///
|
||||
/// DragDrop += MyDragDrop;
|
||||
/// }
|
||||
///
|
||||
/// // This event handler for DragDrop should never hold up the shell. To accommodate a non-blocking response,
|
||||
/// // use the 'QueueNonBlockingCallback' method which uses PostThreadMessage to run a delegate as shown below.
|
||||
/// private void MyDragDrop(object sender, DragEventArgs e)
|
||||
/// {
|
||||
/// // Setting the effect to None here ends drag/drop messages
|
||||
/// e.Effect = DragDropEffects.None;
|
||||
/// // Notice we're passing in the DragEventArgs.Data property that contains the shell item array from the Shell.
|
||||
/// QueueNonBlockingCallback(DisplayData, e.Data);
|
||||
/// }
|
||||
///
|
||||
/// // This delegate will get run outside of the Shell's calling path and can display a UI or perform any other
|
||||
/// // function on the list of shell items passed to it.
|
||||
/// private void DisplayData(object ido)
|
||||
/// {
|
||||
/// // *** Replace with your functionality ***
|
||||
/// using (var shia = ShellItemArray.FromDataObject(ido as DataObject))
|
||||
/// {
|
||||
/// var szMsg = $"Found {shia.Count} item(s): " + string.Join(", ", shia.Select(i => i.Name));
|
||||
/// MessageBox.Show(szMsg, "MyDropTarget");
|
||||
/// }
|
||||
/// // Don't fail to call QuitMessageLoop once you're done processing the Shell call.
|
||||
/// QuitMessageLoop();
|
||||
/// }
|
||||
///
|
||||
/// // This is the main thread of the application. When called from the Shell, it will append the -embedding argument to indicate that
|
||||
/// // a message loop needs to start running and the COM server registered. All that is accomplished by calling the 'Run' method
|
||||
/// // on your new class.
|
||||
/// [STAThread]
|
||||
/// private static void Main(string[] args)
|
||||
/// {
|
||||
/// // *** Replace with your ProgID, name and display name ***
|
||||
/// const string progID = "txtfile";
|
||||
/// const string verbDisplayName = "DropTarget Verb Sample";
|
||||
/// const string verbName = "DropTargetVerb";
|
||||
///
|
||||
/// var arg = args.Length > 0 ? args[0].TrimStart('-', '/').ToLowerInvariant() : null;
|
||||
/// switch (arg)
|
||||
/// {
|
||||
/// // Handle a call from the Shell launching this out-of-proc server
|
||||
/// case "embedding":
|
||||
/// new MyDropTarget().Run(TimeSpan.FromSeconds(30));
|
||||
/// break;
|
||||
///
|
||||
/// // Unregister this out-of-proc server from handling the DropTarget. This can be ommitted if done by an installer.
|
||||
/// case "unregister":
|
||||
/// using (var progid = new ProgId(progID, false))
|
||||
/// progid.Verbs.Remove(verbName);
|
||||
/// ShellRegistrar.UnregisterLocalServer<MyDropTarget>(false);
|
||||
/// break;
|
||||
///
|
||||
/// // Register this out-of-proc server to handle the DropTarget. This can be ommitted if done by an installer.
|
||||
/// default:
|
||||
/// ShellRegistrar.RegisterLocalServer<MyDropTarget>("MyTestDropTarget", systemWide: false);
|
||||
/// using (var progid = new ProgId(progID, false))
|
||||
/// using (var verb = progid.Verbs.Add(verbName, verbDisplayName))
|
||||
/// {
|
||||
/// verb.DropTarget = Marshal.GenerateGuidForType(typeof(MyDropTarget));
|
||||
/// verb.NeverDefault = true;
|
||||
/// }
|
||||
/// break;
|
||||
/// }
|
||||
/// }
|
||||
///}</code></remarks>
|
||||
/// <seealso cref="Vanara.Windows.Shell.ComObject"/>
|
||||
/// <seealso cref="Vanara.PInvoke.Ole32.IDropTarget"/>
|
||||
public abstract class ShellDropTarget : ComObject, IDropTarget
|
||||
{
|
||||
private DataObject lastDataObject;
|
||||
private DROPEFFECT lastEffect;
|
||||
private DROPEFFECT lastEffect = DROPEFFECT.DROPEFFECT_NONE;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="ShellDropTarget"/> class.</summary>
|
||||
protected ShellDropTarget() : base() { }
|
||||
|
@ -31,9 +114,6 @@ namespace Vanara.Windows.Shell
|
|||
/// <summary>Occurs when a drag-and-drop operation is started. All calls from this event must be non-blocking.</summary>
|
||||
public event DragEventHandler DragDrop;
|
||||
|
||||
/// <summary>Occurs when a drag-and-drop operation is completed.</summary>
|
||||
public event DragEventHandler DragDropComplete;
|
||||
|
||||
/// <summary>Occurs to request whether a drop can be accepted, and, if so, the effect of the drop.</summary>
|
||||
public event DragEventHandler DragEnter;
|
||||
|
||||
|
@ -49,16 +129,18 @@ namespace Vanara.Windows.Shell
|
|||
/// <inheritdoc/>
|
||||
HRESULT IDropTarget.DragEnter(IDataObject pDataObj, uint grfKeyState, Point pt, ref DROPEFFECT pdwEffect)
|
||||
{
|
||||
var arg = CreateDragEventArgs(pDataObj, grfKeyState, pt, pdwEffect);
|
||||
OnDragEnter(arg);
|
||||
lastEffect = pdwEffect = (DROPEFFECT)arg.Effect;
|
||||
System.Diagnostics.Debug.WriteLine($"IDropTarget.DragEnter: effect={pdwEffect}");
|
||||
var drgevent = CreateDragEventArgs(pDataObj, grfKeyState, pt, pdwEffect);
|
||||
DragEnter?.Invoke(this, drgevent);
|
||||
lastEffect = pdwEffect = (DROPEFFECT)drgevent.Effect;
|
||||
return HRESULT.S_OK;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
HRESULT IDropTarget.DragLeave()
|
||||
{
|
||||
OnDragLeave(EventArgs.Empty);
|
||||
System.Diagnostics.Debug.WriteLine("IDropTarget.DragLeave");
|
||||
DragLeave?.Invoke(this, EventArgs.Empty);
|
||||
lastDataObject = null;
|
||||
return HRESULT.S_OK;
|
||||
}
|
||||
|
@ -66,42 +148,23 @@ namespace Vanara.Windows.Shell
|
|||
/// <inheritdoc/>
|
||||
HRESULT IDropTarget.DragOver(uint grfKeyState, Point pt, ref DROPEFFECT pdwEffect)
|
||||
{
|
||||
var arg = CreateDragEventArgs(null, grfKeyState, pt, pdwEffect);
|
||||
OnDragOver(arg);
|
||||
lastEffect = pdwEffect = (DROPEFFECT)arg.Effect;
|
||||
System.Diagnostics.Debug.WriteLine($"IDropTarget.DragOver: effect={pdwEffect}");
|
||||
var drgevent = CreateDragEventArgs(null, grfKeyState, pt, pdwEffect);
|
||||
DragOver?.Invoke(this, drgevent);
|
||||
lastEffect = pdwEffect = (DROPEFFECT)drgevent.Effect;
|
||||
return HRESULT.S_OK;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
HRESULT IDropTarget.Drop(IDataObject pDataObj, uint grfKeyState, Point pt, ref DROPEFFECT pdwEffect)
|
||||
{
|
||||
var arg = CreateDragEventArgs(pDataObj, grfKeyState, pt, pdwEffect);
|
||||
OnDragDrop(arg);
|
||||
lastEffect = pdwEffect = (DROPEFFECT)arg.Effect;
|
||||
QueueNonBlockingCallback(o => OnDragDropComplete((DragEventArgs)o), arg);
|
||||
System.Diagnostics.Debug.WriteLine($"IDropTarget.Drop: effect={pdwEffect}");
|
||||
var drgevent = CreateDragEventArgs(pDataObj, grfKeyState, pt, pdwEffect);
|
||||
DragDrop?.Invoke(this, drgevent);
|
||||
pdwEffect = (DROPEFFECT)drgevent.Effect;
|
||||
return HRESULT.S_OK;
|
||||
}
|
||||
|
||||
/// <summary>Raises the <see cref="E:DragDrop"/> event.</summary>
|
||||
/// <param name="drgevent">The <see cref="DragEventArgs"/> instance containing the event data.</param>
|
||||
protected virtual void OnDragDrop(DragEventArgs drgevent) => DragDrop?.Invoke(this, drgevent);
|
||||
|
||||
/// <summary>Raises the <see cref="E:DragDropComplete"/> event.</summary>
|
||||
/// <param name="drgevent">The <see cref="DragEventArgs"/> instance containing the event data.</param>
|
||||
protected virtual void OnDragDropComplete(DragEventArgs drgevent) => DragDropComplete?.Invoke(this, drgevent);
|
||||
|
||||
/// <summary>Raises the <see cref="E:DragEnter"/> event.</summary>
|
||||
/// <param name="drgevent">The <see cref="DragEventArgs"/> instance containing the event data.</param>
|
||||
protected virtual void OnDragEnter(DragEventArgs drgevent) => DragEnter?.Invoke(this, drgevent);
|
||||
|
||||
/// <summary>Raises the <see cref="E:DragLeave"/> event.</summary>
|
||||
/// <param name="ev">The <see cref="EventArgs"/> instance containing the event data.</param>
|
||||
protected virtual void OnDragLeave(EventArgs ev) => DragLeave?.Invoke(this, ev);
|
||||
|
||||
/// <summary>Raises the <see cref="E:DragOver"/> event.</summary>
|
||||
/// <param name="drgevent">The <see cref="DragEventArgs"/> instance containing the event data.</param>
|
||||
protected virtual void OnDragOver(DragEventArgs drgevent) => DragOver?.Invoke(this, drgevent);
|
||||
|
||||
private DragEventArgs CreateDragEventArgs(IDataObject pDataObj, uint grfKeyState, Point pt, DROPEFFECT pdwEffect)
|
||||
{
|
||||
var data = pDataObj == null ? lastDataObject : new DataObject(pDataObj);
|
||||
|
|
Loading…
Reference in New Issue