2017-12-05 1 views
0

Ich möchte C# -Code verwenden, um einen Benutzer zu simulieren, der eine Datei in einem separaten Prozess auf ein Steuerelement zieht und ablegt. Als ein Sprungbrett zu diesem Ziel versuche ich eine WM_DROPFILES-Nachricht an meine eigene TextBox zu senden und zu überprüfen, dass das DragDrop-Ereignis ausgelöst wird.Wie kann ich WM_DROPFILES von C# senden?

Mit dem folgenden Code in einem Formular, das eine einzelne TextBox und zwei Buttons enthält, wird durch Klicken auf button1 der Text von textBox1 erfolgreich auf "Hello world" gesetzt. So, es scheint, dass ich SendMessage richtig verwende und in der Lage bin, Argumente über Zeiger zu liefern. Durch das Ziehen und Ablegen einer Datei aus dem Windows Explorer auf textBox1 wird die MessageBox angezeigt, sodass textBox1 so eingerichtet ist, dass Dateien mit Drag-Drop korrekt empfangen werden. Wenn ich jedoch auf Button2 klicke, passiert nichts. Warum sehe ich keine MessageBox, wenn ich auf button2 klicke?

using System; 
using System.Data; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Windows.Forms; 

namespace StackOverflow 
{ 
    public partial class BadDragDrop : Form 
    { 
     #region WINAPI 

     [Serializable] 
     [StructLayout(LayoutKind.Sequential)] 
     struct POINT 
     { 
      public Int32 X; 
      public Int32 Y; 
     } 

     [Serializable] 
     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
     class DROPFILES 
     { 
      public Int32 size; 
      public POINT pt; 
      public Int32 fND; 
      public Int32 WIDE; 
     } 

     const uint WM_DROPFILES = 0x0233; 
     const uint WM_SETTEXT = 0x000C; 

     [DllImport("Kernel32.dll", SetLastError = true)] 
     static extern int GlobalLock(IntPtr Handle); 

     [DllImport("Kernel32.dll", SetLastError = true)] 
     static extern int GlobalUnlock(IntPtr Handle); 

     [DllImport("user32.dll", SetLastError = true)] 
     static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); 

     #endregion 

     public BadDragDrop() 
     { 
      InitializeComponent(); 
      textBox1.AllowDrop = true; 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      string textToSet = "Hello world\0"; 
      IntPtr p = Marshal.AllocHGlobal(textToSet.Length); 
      Marshal.Copy(textToSet.Select(c => (byte)c).ToArray(), 0, p, textToSet.Length); 
      int success = GlobalUnlock(p); 
      SendMessage(textBox1.Handle, WM_SETTEXT, IntPtr.Zero, p); 
      Marshal.FreeHGlobal(p); 
     } 

     private void button2_Click(object sender, EventArgs e) 
     { 
      string filePath = @"C:\Windows\win.ini" + "\0\0"; 

      DROPFILES s = new DROPFILES() 
      { 
       size = Marshal.SizeOf<DROPFILES>(), 
       pt = new POINT() { X = 10, Y = 10 }, 
       fND = 0, 
       WIDE = 0, 
      }; 

      int wparamLen = s.size + filePath.Length; 

      IntPtr p = Marshal.AllocHGlobal(wparamLen); 
      int iSuccess = GlobalLock(p); 

      Marshal.StructureToPtr(s, p, false); 
      Marshal.Copy(filePath.Select(c => (byte)c).ToArray(), 0, p + s.size, filePath.Length); 

      iSuccess = GlobalUnlock(p); 

      var verify = new byte[wparamLen]; 
      Marshal.Copy(p, verify, 0, wparamLen); 

      var ipSuccess = SendMessage(textBox1.Handle, WM_DROPFILES, p, IntPtr.Zero); 
      Marshal.FreeHGlobal(p); 
     } 

     private void textBox1_DragDrop(object sender, DragEventArgs e) 
     { 
      MessageBox.Show(this, "Drag drop!"); 
     } 

     private void textBox1_DragOver(object sender, DragEventArgs e) 
     { 
      e.Effect = DragDropEffects.Copy; 
     } 
    } 
} 

Antwort

1

Der Grund Sie nicht sehen, Ihre MessageBox erscheint wahrscheinlich, weil die TextBox nicht WM_DROPFILES Nachrichten beginnen umgehen kann. Es implementiert seine Drop-Unterstützung mit OLE Drag & Drop, indem Sie die Schnittstelle IDropTarget implementieren (siehe Drag and Drop Overview in der WPF-Dokumentation).

WM_DROPFILES wurde immer als veraltet, da DoDragDrop() in Windows 95 OLE Drag Weg zurück eingeführt wurde & Tropfen war die bevorzugt Weg Drag & Drop unter Windows für eine sehr lange Zeit zu implementieren. WM_DROPFILES wird immer noch von Windows unterstützt (aber nicht von .NET), aber nur aus Gründen der Abwärtskompatibilität mit älteren Apps.

Ziehen von Elementen aus Windows Explorer in andere Anwendungen verwendet OLE Drag & Drop unter der Haube, auch wenn der Empfänger OLE Drag & Drop nicht implementiert.

Wenn Sie & Tropfen ein IDataObject auf ein Fenster ziehen, die RegisterDragDrop() auf sie genannt hatte (wie Ihre TextBox hat), wird die IDataObject auf die für den Umgang mit IDropTarget Schnittstelle des Fensters übergeben werden.

Wenn Sie & ziehen Sie ein IDataObject auf ein Fenster löschen, die nicht IDropTarget nicht implementiert, sondern haben DragAcceptFiles() auf sie genannt haben, oder zumindest den WS_EX_ACCEPTFILES Fensterstil, wird Windows eine WM_DROPFILES Nachricht erzeugen, wenn die IDataObject enthält CF_HDROP Daten drin.

Also, um zu tun, was Sie mit Ihrem TextBox versuchen, müssen Sie das IDropSource und IDataObject Schnittstellen implementieren und DoDragDrop() mit ihnen rufen. Lassen Sie Windows das eigentliche Drag & Drop für Sie übernehmen. Siehe Shell Clipboard Formats und Handling Shell Data Transfer Scenarios.

Jetzt, mit dieser sagte, wenn Sie noch eine WM_DROPFILES Nachricht an einen anderen Prozess senden bestimmt (die Frage sagt Ihr Ziel ist), können Sie das tun, und Windows wird für Ihre DROPFILES struct über Prozessgrenzen hinweg gemarshallt Sie, aber Sie müssen PostMessage() anstelle von SendMessage() verwenden (nicht sicher warum, nur dass es erforderlich ist), und stellen Sie sicher, dass die DROPFILES nur dann frei, wenn PostMessage() ausfällt. Windows wird die DROPFILES für Sie freigeben, wenn PostMessage() erfolgreich ist.

Aber selbst dann gibt es keine Garantie, dass der Empfangsprozess WM_DROPFILES Nachrichten tatsächlich behandelt (und selbst wenn dies der Fall, könnte Ihr Handbuch WM_DROPFILES Nachricht von UIPI blockiert werden, es sei denn, der Empfänger ChangeWindowMessageFilter/Ex() auf sich selbst aufruft WM_DROPFILES und WM_COPYGLOBALDATA Nachrichten zu ermöglichen,). Der Empfänger könnte stattdessen IDataObject erwarten. Wenn der Empfänger überhaupt unterstützt Drag & Drop.

Verwandte Themen