[英]The Win32 API procedure of drag-and-dropping a file from my app to another app
In short, trying to do what the following two lines of C# code do without using System.Windows.Forms
, because it is .NET Core and not a WinForms project. 简而言之,请尝试不使用
System.Windows.Forms
而执行以下两行C#代码,因为它是.NET Core,而不是WinForms项目。
var data = new System.Windows.Forms.DataObject(
System.Windows.Forms.DataFormats.FileDrop, new string[] { @"C:\test.txt"});
dummyControl.DoDragDrop(data, System.Windows.Forms.DragDropEffects.Copy);
But it does not work. 但这行不通。 What have I done wrong?
我做错了什么? My procedure was,
我的程序是
SetCapture
to capture the event. SetCapture
捕获事件。 IDropSource
's QueryContinueDrag
keep returning S_OK
until the mouse button is up, and then DRAGDROP_S_DROP
. IDropSource
的QueryContinueDrag
一直返回S_OK
直到鼠标按钮向上,然后DRAGDROP_S_DROP
。 My "DataObject" implementing IDataObject
has EnumFormatEtc
. 我实现
IDataObject
“ DataObject”具有EnumFormatEtc
。 In which I return only one FORMATETC
. 我只返回一个
FORMATETC
。
new FORMATETC() { cfFormat = CF_HDROP, ptd = IntPtr.Zero, dwAspect = DVASPECT.DVASPECT_ICON, lindex = -1, tymed = TYMED.TYMED_FILE }
In QueryGetData
, if the format
's tymed
is TYMED_FILE
, return S_OK
meaning I am dragging a file. 在
QueryGetData
,如果format
的tymed
为TYMED_FILE
,则返回S_OK
表示我正在拖动文件。 Otherwise return DV_E_TYMED
meaning I don't have that type of data. 否则返回
DV_E_TYMED
表示我没有该类型的数据。
In GetData
, if the format
's tymed
is TYMED_FILE
, I set a file like this 在
GetData
,如果format
的tymed
是TYMED_FILE
,则我将这样设置一个文件
medium = new STGMEDIUM(); medium.tymed = TYMED.TYMED_FILE; medium.unionmember = Marshal.StringToHGlobalUni(@"C:\\test.txt"); medium.pUnkForRelease = IntPtr.Zero;
I tried to drag-and-drop to Notepad. 我试图将其拖放到记事本中。 Problems are,
问题是
DoDragDrop
is not called on the mouse down event, mouse is captured and mouse up event is received. DoDragDrop
时,将捕获鼠标并接收鼠标按下事件。 But when DoDragDrop
is called, QueryContinueDrag
is endlessly called and I don't get the mouse up event, even after I released the mouse. DoDragDrop
时,会无休止地调用QueryContinueDrag
,即使释放了鼠标,我也没有发生鼠标向上事件。 I tried to call DoDragDrop
in another thread, but that did not work. DoDragDrop
,但这没有用。 QueryGetData(TYMED_HGLOBAL)
or QueryGetData(TYMED_HGLOBAL, TYMED_ISTREAM, TYMED_GDI, TYMED_MFPICT, TYMED_ENHMF)
, but not for TYMED_FILE
. QueryGetData(TYMED_HGLOBAL)
或QueryGetData(TYMED_HGLOBAL, TYMED_ISTREAM, TYMED_GDI, TYMED_MFPICT, TYMED_ENHMF)
,但没有TYMED_FILE
。 Why isn't Notepad requesting that? The drag and drop seems unnecessarily complex, but for now, I am only interested in dragging a file, so I did not want to implement parts other than that. 拖放似乎不必要地复杂,但是目前,我仅对拖动文件感兴趣,因此我不想实现除此以外的其他部分。 What in the above procedure or assumptions are wrong?
上述程序或假设中有哪些错误?
When DoDragDrop is not called on the mouse down event, mouse is captured and mouse up event is received.
当在鼠标按下事件上未调用DoDragDrop时,将捕获鼠标并接收鼠标按下事件。 But when DoDragDrop is called, QueryContinueDrag is endlessly called and I don't get the mouse up event, even after I released the mouse.
但是,当调用DoDragDrop时,会无休止地调用QueryContinueDrag,即使释放了鼠标,我也没有发生鼠标向上事件。
You don't get a mouse up event because DoDragDrop()
blocks your UI message loop until the drag operation is completed. 您不会发生鼠标上
DoDragDrop()
事件,因为DoDragDrop()
阻塞UI消息循环,直到完成拖动操作为止。 So you need to use the input flags given to your QueryContinueDrag()
implementation to decide whether to continue dragging, perform the drop, or abort the operation. 因此,您需要使用提供给
QueryContinueDrag()
实现的输入标志来确定是继续拖动,执行放置还是中止操作。
If you start the drag on a left mouse down, return S_OK
if the grfKeyState
parameter includes the MK_LBUTTON
flag, and return DRAGDROP_S_DROP
if the MK_LBUTTON
flag is cleared. 如果你开始在鼠标左键拖动下,返回
S_OK
如果grfKeyState
参数包括MK_LBUTTON
标志,并返回DRAGDROP_S_DROP
如果MK_LBUTTON
标志被清除。 Return DRAGDROP_S_CANCEL
if the fEscapePressed
parameter is true. 如果
fEscapePressed
参数为true,则返回DRAGDROP_S_CANCEL
。 This is documented on MSDN: 这记录在MSDN上:
IDropSource::QueryContinueDrag method IDropSource :: QueryContinueDrag方法
Parameters
参数
fEscapePressed
Indicates whether the Esc key has been pressed since the previous call to
QueryContinueDrag
or toDoDragDrop
if this is the first call toQueryContinueDrag
.指示自上次调用
QueryContinueDrag
或DoDragDrop
如果这是对QueryContinueDrag
的第一次调用)以来,是否已按下Esc键 。 ATRUE
value indicates the end user has pressed the escape key;TRUE
值表示最终用户已按下退出键; aFALSE
value indicates it has not been pressed.FALSE
值表示尚未按下。
grfKeyState
The current state of the keyboard modifier keys on the keyboard.
键盘上键盘修饰键的当前状态。 Possible values can be a combination of any of the flags MK_CONTROL, MK_SHIFT, MK_ALT, MK_BUTTON, MK_LBUTTON , MK_MBUTTON, and MK_RBUTTON.
可能的值可以是标志MK_CONTROL,MK_SHIFT,MK_ALT,MK_BUTTON, MK_LBUTTON ,MK_MBUTTON和MK_RBUTTON中任何一个的组合。
Return Value
返回值
This method can return the following values.
此方法可以返回以下值。
S_OK
S_OK
The drag operation should continue.拖动操作应继续。 This result occurs if no errors are detected, the mouse button starting the drag-and-drop operation has not been released , and the Esc key has not been detected.
如果未检测到任何错误, 尚未释放开始拖放操作的鼠标按钮 ,也未检测到Esc键,则会出现此结果。
DRAGDROP_S_DROP
DRAGDROP_S_DROP
The drop operation should occur completing the drag operation.放置操作应完成拖动操作。 This result occurs if
grfKeyState
indicates that the key that started the drag-and-drop operation has been released.如果
grfKeyState
指示开始拖放操作的键已释放,则会出现此结果。DRAGDROP_S_CANCEL
DRAGDROP_S_CANCEL
The drag operation should be canceled with no drop operation occurring.拖动操作应被取消,而不会发生拖放操作。 This result occurs if
fEscapePressed
is TRUE, indicating the Esc key has been pressed.如果
fEscapePressed
为TRUE(表示已按下Esc键),则会出现此结果。Remarks
备注
The
DoDragDrop
function callsQueryContinueDrag
whenever it detects a change in the keyboard or mouse button state during a drag-and-drop operation.每当
DoDragDrop
函数在拖放操作期间检测到键盘或鼠标按钮状态发生变化时,就会调用QueryContinueDrag
。QueryContinueDrag
must determine whether the drag-and-drop operation should be continued, canceled, or completed based on the contents of the parametersgrfKeyState
andfEscapePressed
.QueryContinueDrag
必须基于参数grfKeyState
和fEscapePressed
的内容来确定拖放操作是应该继续,取消还是完成。
I get callbacks like QueryGetData(TYMED_HGLOBAL) or QueryGetData(TYMED_HGLOBAL, TYMED_ISTREAM, TYMED_GDI, TYMED_MFPICT, TYMED_ENHMF), but not for TYMED_FILE.
我收到了类似QueryGetData(TYMED_HGLOBAL)或QueryGetData(TYMED_HGLOBAL,TYMED_ISTREAM,TYMED_GDI,TYMED_MFPICT,TYMED_ENHMF)的回调,但没有TYMED_FILE的回调。 Why isn't Notepad requesting that?
为什么记事本不要求?
You can't use TYMED_FILE
for CF_HDROP
, you must use TYMED_HGLOBAL
. 您不能将
TYMED_FILE
用于CF_HDROP
,而必须使用TYMED_HGLOBAL
。 And the content of the allocated HGLOBAL
must be a DROPFILES
struct followed by a double-null-terminated list of file paths. 并且已分配的
HGLOBAL
的内容必须是DROPFILES
结构,后跟一个双空终止的文件路径列表。 This is documented on MSDN: 这记录在MSDN上:
Shell Clipboard Formats Shell剪贴板格式
CF_HDROP
CF_HDROP
This clipboard format is used when transferring the locations of a group of existing files.
传输一组现有文件的位置时使用此剪贴板格式。 Unlike the other Shell formats, it is predefined, so there is no need to call
RegisterClipboardFormat
.与其他Shell格式不同,它是预定义的,因此无需调用
RegisterClipboardFormat
。 The data consists of anSTGMEDIUM
structure that contains a global memory object.数据由包含全局存储对象的
STGMEDIUM
结构组成。 The structure'shGlobal
member points to aDROPFILES
structure as itshGlobal
member.该结构的
hGlobal
成员指向DROPFILES
结构作为其hGlobal
成员。The
pFiles
member of theDROPFILES
structure contains an offset to a double null-terminated character array that contains the file names.DROPFILES
结构的pFiles
成员包含一个双零终止字符数组的偏移量,该字符数组包含文件名。 If you are extracting aCF_HDROP
format from a data object, you can useDragQueryFile
to extract individual file names from the global memory object.如果要从数据对象中提取
CF_HDROP
格式,则可以使用DragQueryFile
从全局内存对象中提取单个文件名。 If you are creating aCF_HDROP
format to place in a data object, you will need to construct the file name array.如果要创建
CF_HDROP
格式以放置在数据对象中,则需要构造文件名数组。The file name array consists of a series of strings, each containing one file's fully qualified path, including the terminating NULL character.
文件名数组由一系列字符串组成,每个字符串包含一个文件的标准路径,包括终止NULL字符。 An additional null character is appended to the final string to terminate the array.
在最终字符串后附加一个空字符以终止数组。 For example, if the files
c:\\temp1.txt
andc:\\temp2.txt
are being transferred, the character array looks like this:例如,如果正在传输文件
c:\\temp1.txt
和c:\\temp2.txt
,则字符数组如下所示:
c:\\temp1.txt'\\0'c:\\temp2.txt'\\0''\\0'
Note
注意
In this example,'\\0'
is used to represent the null character, not the literal characters that should be included.在此示例中,
'\\0'
用于表示空字符,而不是应包括的文字字符。If the object was copied to the clipboard as part of a drag-and-drop operation, the
pt
member of theDROPFILES
structure contains the coordinates of the point where the object was dropped.如果作为拖放操作的一部分将对象复制到剪贴板,则
DROPFILES
结构的pt
成员将包含放置对象的点的坐标。 You can useDragQueryPoint
to extract the cursor coordinates.您可以使用
DragQueryPoint
提取光标坐标。If this format is present in a data object, an OLE drag loop simulates
WM_DROPFILES
functionality with non-OLE drop targets.如果数据对象中存在此格式,则OLE拖动循环会使用非OLE放置目标来模拟
WM_DROPFILES
功能。 This is important if your application is the source of a drag-and-drop operation on a Windows 3.1 system.如果您的应用程序是Windows 3.1系统上的拖放操作的来源,则这一点很重要。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.