将文件从我的应用程序拖放到另一个应用程序的Win32 API过程 [英] The Win32 API procedure of drag-and-dropping a file from my app to another app
问题描述
简而言之,请尝试执行以下两行C#代码而不使用System.Windows.Forms
,因为它是.NET Core,而不是WinForms项目.
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.
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,
- 将鼠标放在UI控件上时,请调用
SetCapture
捕获事件. -
IDropSource
的QueryContinueDrag
会一直返回S_OK
,直到鼠标按钮向上,然后再返回DRAGDROP_S_DROP
. -
实现
IDataObject
的我的"DataObject"具有EnumFormatEtc
.我只返回一个FORMATETC
.
- When mouse is down on a UI control, call
SetCapture
to capture the event. - The
IDropSource
'sQueryContinueDrag
keep returningS_OK
until the mouse button is up, and thenDRAGDROP_S_DROP
. My "DataObject" implementing
IDataObject
hasEnumFormatEtc
. In which I return only oneFORMATETC
.
new FORMATETC()
{
cfFormat = CF_HDROP,
ptd = IntPtr.Zero,
dwAspect = DVASPECT.DVASPECT_ICON,
lindex = -1,
tymed = TYMED.TYMED_FILE
}
-
在
QueryGetData
中,如果format
的tymed
是TYMED_FILE
,则返回S_OK
表示我正在拖动文件.否则,返回DV_E_TYMED
表示我没有该类型的数据.
In
QueryGetData
, if theformat
'stymed
isTYMED_FILE
, returnS_OK
meaning I am dragging a file. Otherwise returnDV_E_TYMED
meaning I don't have that type of data.
在GetData
中,如果format
的tymed
是TYMED_FILE
,我会设置一个这样的文件
In GetData
, if the format
's tymed
is TYMED_FILE
, I set a file like this
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
时,将捕获鼠标并接收鼠标按下事件.但是,当调用DoDragDrop
时,会无休止地调用QueryContinueDrag
,即使释放了鼠标,我也没有鼠标向上的事件.我试图在另一个线程中调用DoDragDrop
,但这没用. - 我收到类似
QueryGetData(TYMED_HGLOBAL)
或QueryGetData(TYMED_HGLOBAL, TYMED_ISTREAM, TYMED_GDI, TYMED_MFPICT, TYMED_ENHMF)
的回调,但没有获得TYMED_FILE
的回调.为什么记事本不要求?
- When
DoDragDrop
is not called on the mouse down event, mouse is captured and mouse up event is received. But whenDoDragDrop
is called,QueryContinueDrag
is endlessly called and I don't get the mouse up event, even after I released the mouse. I tried to callDoDragDrop
in another thread, but that did not work. - I get callbacks like
QueryGetData(TYMED_HGLOBAL)
orQueryGetData(TYMED_HGLOBAL, TYMED_ISTREAM, TYMED_GDI, TYMED_MFPICT, TYMED_ENHMF)
, but not forTYMED_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?
推荐答案
在鼠标按下事件中未调用DoDragDrop时,将捕获鼠标并接收鼠标按下事件.但是当调用DoDragDrop时,QueryContinueDrag被无休止地调用,即使释放了鼠标,我也没有鼠标上移事件.
When DoDragDrop is not called on the mouse down event, mouse is captured and mouse up event is received. 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()
会阻塞UI消息循环,直到完成拖动操作为止.因此,您需要使用为QueryContinueDrag()
实现提供的输入标志来决定是继续拖动,执行放置还是中止操作.
You don't get a mouse up event because DoDragDrop()
blocks your UI message loop until the drag operation is completed. 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.
如果在鼠标左键上开始拖动,则如果grfKeyState
参数包含MK_LBUTTON
标志,则返回S_OK
;如果清除MK_LBUTTON
标志,则返回DRAGDROP_S_DROP
.如果fEscapePressed
参数为true,则返回DRAGDROP_S_CANCEL
.在MSDN上有记录:
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. Return DRAGDROP_S_CANCEL
if the fEscapePressed
parameter is true. This is documented on MSDN:
IDropSource :: QueryContinueDrag方法
参数
fEscapePressed
表示自上次调用QueryContinueDrag
或DoDragDrop
(如果这是第一次调用QueryContinueDrag
)以来,是否已按Esc键. TRUE
值表示最终用户按下了退出键; FALSE
值表示尚未按下.
Indicates whether the Esc key has been pressed since the previous call to QueryContinueDrag
or to DoDragDrop
if this is the first call to QueryContinueDrag
. A TRUE
value indicates the end user has pressed the escape key; a FALSE
value indicates it has not been pressed.
grfKeyState
键盘上键盘修饰键的当前状态.可能的值可以是以下任意标志的组合:MK_CONTROL,MK_SHIFT,MK_ALT,MK_BUTTON, MK_LBUTTON , MK_MBUTTON和MK_RBUTTON.
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.
返回值
此方法可以返回以下值.
This method can return the following values.
S_OK
拖动操作应继续.如果未检测到错误,开始拖放操作的鼠标按钮未释放,并且未检测到Esc键,则会发生此结果.
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.
DRAGDROP_S_DROP
放置操作应完成拖动操作. 如果grfKeyState
指示已释放开始拖放操作的键,则会出现此结果.
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.
DRAGDROP_S_CANCEL
拖动操作应被取消,而不会发生拖放操作. 如果fEscapePressed
为TRUE(表示已按下Esc键),则会出现此结果.
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.
备注
DoDragDrop
函数在拖放操作期间检测到键盘或鼠标按钮状态的变化时会调用QueryContinueDrag
. QueryContinueDrag
必须根据参数grfKeyState
和fEscapePressed
的内容来确定是否应继续,取消或完成拖放操作.
The DoDragDrop
function calls QueryContinueDrag
whenever it detects a change in the keyboard or mouse button state during a drag-and-drop operation. QueryContinueDrag
must determine whether the drag-and-drop operation should be continued, canceled, or completed based on the contents of the parameters grfKeyState
and fEscapePressed
.
我收到了类似QueryGetData(TYMED_HGLOBAL)或QueryGetData(TYMED_HGLOBAL,TYMED_ISTREAM,TYMED_GDI,TYMED_MFPICT,TYMED_ENHMF)的回调,但没有TYMED_FILE的回调.为什么记事本不要求?
I get callbacks like QueryGetData(TYMED_HGLOBAL) or QueryGetData(TYMED_HGLOBAL, TYMED_ISTREAM, TYMED_GDI, TYMED_MFPICT, TYMED_ENHMF), but not for TYMED_FILE. Why isn't Notepad requesting that?
不能将TYMED_FILE
用于CF_HDROP
,必须使用TYMED_HGLOBAL
.并且分配的HGLOBAL
的内容必须为
You can't use TYMED_FILE
for CF_HDROP
, you must use TYMED_HGLOBAL
. And the content of the allocated HGLOBAL
must be a DROPFILES
struct followed by a double-null-terminated list of file paths. This is documented on MSDN:
CF_HDROP
CF_HDROP
在传输一组现有文件的位置时使用此剪贴板格式.与其他Shell格式不同,它是预定义的,因此无需调用RegisterClipboardFormat
. 数据由包含全局内存对象的STGMEDIUM
结构组成.该结构的hGlobal
成员指向DROPFILES
结构作为其hGlobal
成员.
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
. The data consists of an STGMEDIUM
structure that contains a global memory object. The structure's hGlobal
member points to a DROPFILES
structure as its hGlobal
member.
DROPFILES
结构的pFiles
成员包含一个双零终止字符数组的偏移量,该字符数组包含文件名.如果要从数据中提取CF_HDROP
格式对象,您可以使用DragQueryFile
从全局内存对象中提取单个文件名. 如果要创建CF_HDROP
格式以放置在数据对象中,则需要构造文件名数组.
The pFiles
member of the DROPFILES
structure contains an offset to a double null-terminated character array that contains the file names. If you are extracting a CF_HDROP
format from a data object, you can use DragQueryFile
to extract individual file names from the global memory object. If you are creating a CF_HDROP
format to place in a data object, you will need to construct the file name array.
文件名数组由一系列字符串组成,每个字符串包含一个文件的标准路径,包括终止NULL字符.最后一个字符串后面会附加一个空字符以终止数组.例如,如果要传输文件c:\temp1.txt
和c:\temp2.txt
,则字符数组如下所示:
The file name array consists of a series of strings, each containing one file's fully qualified path, including the terminating NULL character. An additional null character is appended to the final string to terminate the array. For example, if the files c:\temp1.txt
and c:\temp2.txt
are being transferred, the character array looks like this:
c:\temp1.txt'\0'c:\temp2.txt'\0''\0'
注意
在此示例中,'\0'
用于表示空字符,而不是应包括的文字字符.
Note
In this example, '\0'
is used to represent the null character, not the literal characters that should be included.
如果通过拖放操作将对象复制到剪贴板,则DROPFILES
结构的pt
成员将包含放置对象的点的坐标.您可以使用DragQueryPoint
提取光标坐标.
If the object was copied to the clipboard as part of a drag-and-drop operation, the pt
member of the DROPFILES
structure contains the coordinates of the point where the object was dropped. You can use DragQueryPoint
to extract the cursor coordinates.
如果数据对象中存在此格式,则OLE拖动循环将使用非OLE放置目标模拟WM_DROPFILES
功能.如果您的应用程序是Windows 3.1系统上的拖放操作的源头,则这一点很重要.
If this format is present in a data object, an OLE drag loop simulates WM_DROPFILES
functionality with non-OLE drop targets. This is important if your application is the source of a drag-and-drop operation on a Windows 3.1 system.
这篇关于将文件从我的应用程序拖放到另一个应用程序的Win32 API过程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!