问题
I'm using windows API to create an application with a window only, so everything inside this window is drawn using Direct2D.
Now I want to drop some files in specific parts of my window's client area, and I'm handling the message WM_DROPFILES
. No problem here, when the files are dropped in those specific areas, I can treat them correctly and everything is working properly. BTW, my window is DragAcceptFiles(hWnd, true)
, it always accepts drag/drops.
I want the mouse cursor to be different depending on the area of the window the mouse is in. In the areas that I don't treat the drop, I want the cursor to be the invalid icon, and for the areas of the window that I do handle the drops, I want the correct drop icon.
The first thing I noticed is that no message is generated when files are being dragged into the window, and for this reason I added a mouse hook (WH_MOUSE_LL
using SetWindowsHookEx
). When the hook is processed, I only look at the WM_MOUSEMOVE
message, so I can change the cursor according to the area the mouse is in.
The problem is that the SetCursor
does nothing, if my windows is configured to accept drag files, the cursor is always the drag/drop cursor, no matter how many times I call SetCursor
.
It seems impossible to change the cursor this way, but is there any other way of doing what I'm trying to achieve?
回答1:
You need to write a class in your code that implements the IDropTarget interface, then create an instance of that class and pass it to RegisterDragDrop() to associate it with your window. Do not use DragAcceptFiles()
anymore.
Whenever the user drags anything (not just files) over your window, your IDropTarget::DragEnter()
and IDropTarget::DragOver()
, IDropTarget::DragLeave()
methods will be called accordingly, giving you the current coordinates of the drag and information about the data being dragged (so you can filter out any data you don't want to accept). If you choose to accept the data, and the user actually drops the data onto your window, your IDropTarget::Drop()
method will be called.
As the drop target, it is not your responsibility to change the cursor. It is the responsibility of the drop source instead to handle that as needed. In your IDropTarget::DragEnter()
and IDropTarget::DragOver()
implementations, all you need to do is set the pdwEffect
output parameter to an appropriate DROPEFFECT value. That value gets passed back to the drop source, which then displays visual feedback to the user (like changing the cursor) in its IDropSource::GiveFeedback()
implementation.
It is possible for your IDropTarget
to be invoked without user interaction (ie, programmably from another apps, and not just for drag&drop operations). That is why the drop source, not the drop target, decides whether or not to display UI updates to the user, since only the drop source knows why it is invoking your IDropTarget
in the first place. The drop target does not know (or care) why it is being invoked, only that it is being given some data and asked whether it will accept or reject that data, nothing more.
Refer to MSDN for more details:
OLE and Data Transfer
Transferring Shell Objects with Drag-and-Drop and the Clipboard
来源:https://stackoverflow.com/questions/18856514/setcursor-while-dragging-files-into-a-window