Reduce the number of files in the TShellListView child stream

I am trying to create a descendant of TShellListView that accepts files dropped from Windows Explorer. I want to handle the drag and drop in the definition of my component without the need to implement it in any of the applications using the component (I found examples of accepting files deleted from Windows Explorer, but all at the application level / TForm).

I call DragAcceptFiles () in my constructor, and I have defined a message handler for WM_DROPFILES. However, when I use this component in a sample project and drag and drop a file from Windows Explorer:

  • I see the "not accepted" icon (w / slash circle), and not an indication that I can delete the file.

  • If I try to delete a file, I do not hear Beep ().

I assume that I am warning Windows incorrectly that my control would like to accept dragged files. Can anyone suggest that I am missing?

Here, my component code with uninteresting bits is deleted:

unit LJLShellListView; interface type TLJLShellListView = class(TShellListView) private procedure WMDropFiles(var Msg: TWMDropFiles); message WM_DROPFILES; published constructor Create(AOwner: TComponent); end; implementation uses ShellAPI; constructor TLJLShellListView.Create(AOwner: TComponent); begin inherited Create(AOwner); DragAcceptFiles(self.Handle, True); end; procedure TLJLShellListView.WMDropFiles(var Msg: TWMDropFiles); begin Beep(); // I never hear this. end; end. 
+7
source share
2 answers

To call DragAcceptFiles in the code in the question, a ShellListView window handle is required. When the code accesses the wincontrol handle, the VCL checks to see if this window is created or not, and if not, the VCL calls CreateHandle and continues to create the window and return its handle. At this point, the code in the question successfully registers the ShellListView window to drag and drop the file. But the problem is that control is not yet registered. When it is turned on, its own control will be destroyed, and then it will be recreated in the new parent and, of course, will receive another descriptor, an invalid registered state.

The control may be recreated for other reasons. For this reason, it is better to put our code in the overridden CreateWnd and DestroyWnd , whenever the handle changes or the window is destroyed, our code will work.

+8
source

As @SertacAkyuz said, the solution to your question is to override the CreateWnd() method to call DragAcceptFiles() instead in the constructor. I just want to mention that in Windows Vista and later, the User Privilege Function (UIPI) comes into effect, so if your application is running in elevated state in UAC, you also need to call ChangeWindowMessageFilter() to deliver WM_COPYGLOBALDATA ($ 0049) and WM_DROPFILES to your application from processes with lower privileges, such as Windows Explorer, or drag and drop will not work correctly.

WM_DROPFILES has not been recommended for a long time in favor of the newer IDropTarget interface, which is much more powerful and flexible. The new code should use IDropTarget instead of WM_DROPFILES . See MSDN for more details:

Transfer shell objects using drag-and-drop and clipboard

One of the flexible functions that IDropTarget offers is that WM_DROPFILES not able to use a single IDropTarget object to accept drag and drop not only on a specific HWND , but also on your app.exe, as well as use it in the Shell context menus and even allow other applications Transfer data directly to your application without using window messages or other IPC mechanisms.

+3
source

All Articles