将文件从我的应用程序拖放到另一个应用程序的 Win32 API 过程
The Win32 API procedure of drag-and-dropping a file from my app to another app
简而言之,尝试在不使用 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);
但它不起作用。我做错了什么?我的程序是,
- 当鼠标在 UI 控件上时,调用
SetCapture
来捕获事件。
-
IDropSource
的 QueryContinueDrag
保持 returning S_OK
直到鼠标按钮弹起,然后 DRAGDROP_S_DROP
.
我的 "DataObject" 实施 IDataObject
有 EnumFormatEtc
。其中我return只有一个FORMATETC
.
new FORMATETC()
{
cfFormat = CF_HDROP,
ptd = IntPtr.Zero,
dwAspect = DVASPECT.DVASPECT_ICON,
lindex = -1,
tymed = TYMED.TYMED_FILE
}
在QueryGetData
中,如果format
的tymed
是TYMED_FILE
,returnS_OK
意思是我我正在拖一个文件。否则 return DV_E_TYMED
意味着我没有那种类型的数据。
在GetData
中,如果format
的tymed
是TYMED_FILE
,我设置一个这样的文件
medium = new STGMEDIUM();
medium.tymed = TYMED.TYMED_FILE;
medium.unionmember = Marshal.StringToHGlobalUni(@"C:\test.txt");
medium.pUnkForRelease = IntPtr.Zero;
我试图拖放到记事本。问题是,
- 当
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 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()
实施的输入标志来决定是继续拖动、执行放置还是中止操作。
如果您开始拖动鼠标左键,return S_OK
如果 grfKeyState
参数包含 MK_LBUTTON
标志,并且 return DRAGDROP_S_DROP
如果 MK_LBUTTON
标志被清除。 Return DRAGDROP_S_CANCEL
如果 fEscapePressed
参数为真。这记录在 MSDN 上:
IDropSource::QueryContinueDrag method
Parameters
fEscapePressed
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
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.
Return Value
This method can return the following values.
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
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
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.
Remarks
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
.
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?
CF_HDROP
不能使用TYMED_FILE
,必须使用TYMED_HGLOBAL
。分配的 HGLOBAL
的内容必须是一个 DROPFILES
结构,后跟一个以双空结尾的文件路径列表。这记录在 MSDN 上:
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
. 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.
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.
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'[=50=]'c:\temp2.txt'[=50=]''[=50=]'
Note
In this example, '[=51=]'
is used to represent the null character, not the literal characters that should be included.
如果对象作为拖放操作的一部分被复制到剪贴板,DROPFILES
结构的 pt
成员包含对象被放置点的坐标.您可以使用 DragQueryPoint
提取光标坐标。
如果此格式存在于数据对象中,则 OLE 拖动循环会模拟具有非 OLE 放置目标的 WM_DROPFILES
功能。如果您的应用程序是 Windows 3.1 系统上拖放操作的来源,这一点很重要。
简而言之,尝试在不使用 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);
但它不起作用。我做错了什么?我的程序是,
- 当鼠标在 UI 控件上时,调用
SetCapture
来捕获事件。 -
IDropSource
的QueryContinueDrag
保持 returningS_OK
直到鼠标按钮弹起,然后DRAGDROP_S_DROP
. 我的 "DataObject" 实施
IDataObject
有EnumFormatEtc
。其中我return只有一个FORMATETC
.new FORMATETC() { cfFormat = CF_HDROP, ptd = IntPtr.Zero, dwAspect = DVASPECT.DVASPECT_ICON, lindex = -1, tymed = TYMED.TYMED_FILE }
在
QueryGetData
中,如果format
的tymed
是TYMED_FILE
,returnS_OK
意思是我我正在拖一个文件。否则 returnDV_E_TYMED
意味着我没有那种类型的数据。在
GetData
中,如果format
的tymed
是TYMED_FILE
,我设置一个这样的文件medium = new STGMEDIUM(); medium.tymed = TYMED.TYMED_FILE; medium.unionmember = Marshal.StringToHGlobalUni(@"C:\test.txt"); medium.pUnkForRelease = IntPtr.Zero;
我试图拖放到记事本。问题是,
- 当
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 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()
实施的输入标志来决定是继续拖动、执行放置还是中止操作。
如果您开始拖动鼠标左键,return S_OK
如果 grfKeyState
参数包含 MK_LBUTTON
标志,并且 return DRAGDROP_S_DROP
如果 MK_LBUTTON
标志被清除。 Return DRAGDROP_S_CANCEL
如果 fEscapePressed
参数为真。这记录在 MSDN 上:
IDropSource::QueryContinueDrag method
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
. ATRUE
value indicates the end user has pressed the escape key; aFALSE
value indicates it has not been pressed.
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.
Return Value
This method can return the following values.
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
The drop operation should occur completing the drag operation. This result occurs ifgrfKeyState
indicates that the key that started the drag-and-drop operation has been released.DRAGDROP_S_CANCEL
The drag operation should be canceled with no drop operation occurring. This result occurs iffEscapePressed
is TRUE, indicating the Esc key has been pressed.Remarks
The
DoDragDrop
function callsQueryContinueDrag
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 parametersgrfKeyState
andfEscapePressed
.
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?
CF_HDROP
不能使用TYMED_FILE
,必须使用TYMED_HGLOBAL
。分配的 HGLOBAL
的内容必须是一个 DROPFILES
结构,后跟一个以双空结尾的文件路径列表。这记录在 MSDN 上:
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
. The data consists of anSTGMEDIUM
structure that contains a global memory object. The structure'shGlobal
member points to aDROPFILES
structure as itshGlobal
member.The
pFiles
member of theDROPFILES
structure contains an offset to a double null-terminated character array that contains the file names. If you are extracting aCF_HDROP
format from a data object, you can useDragQueryFile
to extract individual file names from the global memory object. If you are creating aCF_HDROP
format to place in a data object, you will need to construct the file name array.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
andc:\temp2.txt
are being transferred, the character array looks like this:
c:\temp1.txt'[=50=]'c:\temp2.txt'[=50=]''[=50=]'
Note
In this example,'[=51=]'
is used to represent the null character, not the literal characters that should be included.如果对象作为拖放操作的一部分被复制到剪贴板,
DROPFILES
结构的pt
成员包含对象被放置点的坐标.您可以使用DragQueryPoint
提取光标坐标。如果此格式存在于数据对象中,则 OLE 拖动循环会模拟具有非 OLE 放置目标的
WM_DROPFILES
功能。如果您的应用程序是 Windows 3.1 系统上拖放操作的来源,这一点很重要。