为什么会出现无法拖放
条件:你的Windows版本>=NT6.0,你以普通用户的身份运行了Windows外壳程序(Windows资源管理器),又以管理员身份运行了test.exe,test.exe是一个包含了拖放对象的Windows窗体程序
发生的问题:不能够把任何东西从资源管理器拖放到test.exe
原因:你没有将UAC彻底关闭
原理:低权限的进程是无法向高权限的进程发送任何高于 WM_USER 的消息,而低于 WM_USER 的消息一部分也会因为安全原因被禁止。
我应该如何解决这个问题
从用户的角度,有两种方式(不建议从用户的角度这么做,因为在Win10下会发生一些花里胡哨的BUG,Win8.x下会禁止你使用metro应用)
1 停用这个机制(修改注册表)脚本:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINESOFTWAREMicrosoftWindowsCurrentVersionPoliciesSystem]
"ConsentPromptBehaviorAdmin"=dword:00000000
"EnableLUA"=dword:00000000
"PromptOnSecureDesktop"=dword:00000000
2 以管理员身份运行资源管理器(和上一个方法差不多)
从开发者的角度(推荐,不会发生过多的BUG),我们可以通过API来解决:ChangeWindowMessageFilter(Ex)
建议带上Ex,因为ChangeWindowMessageFilter面向的是整个进程,ChangeWindowMessageFilterEx是只对窗口进行应用
在C/C++中的用法:(在哪个头文件自己看MSDN)
ChangeWindowMessageFilter(WM_DROPFILES, MSGFLT_ADD);
ChangeWindowMessageFilter(WM_COPYDATA, MSGFLT_ADD);
ChangeWindowMessageFilter(WM_COPYGLOBALDATA , MSGFLT_ADD);
引用阿毛的文章某一部分:其中 WM_COPYGLOBALDATA 在 winodws.h 中并没有相应的定义,也可以直接用它的数值 0×0049 来代替。至于为啥要这么做,并没有很明确的官方文档说明,不过也可以猜出个大概:WM_COPYDATA 和 WM_COPYGLOBALDATA 是用于 explorer.exe 和当前进程进行进程通信的消息。
易语言下处理这个问题
DLL命令表:
.版本 2
.DLL命令 SetWindowLong, 整数型, "user32.dll", "SetWindowLongA"
.参数 hWnd, 整数型
.参数 nIndex, 整数型
.参数 dwNewLong, 整数型
.DLL命令 CallWindowProc, 整数型, "user32.dll", "CallWindowProcA"
.参数 lpPrevWndFunc, 整数型
.参数 hWnd, 整数型
.参数 Msg, 整数型
.参数 wParam, 整数型
.参数 lParam, 整数型
.DLL命令 GetVersion, 整数型, "kernel32.dll", "GetVersion"
.DLL命令 ChangeWindowMessageFilter, 逻辑型, "user32.dll", "ChangeWindowMessageFilter"
.参数 message, 整数型
.参数 dwFlag, 整数型
.DLL命令 DragAcceptFiles, , "shell32.dll", "DragAcceptFiles"
.参数 hWnd, 整数型
.参数 fAccept, 逻辑型
.DLL命令 DragQueryPoint, 逻辑型, "shell32.dll", "DragQueryPoint"
.参数 hDrop, 整数型
.参数 lppt, POINT, 传址
.DLL命令 DragQueryFile, 整数型, "shell32.dll", "DragQueryFileA"
.参数 hDrop, 整数型
.参数 iFile, 整数型
.参数 lpszFile, 文本型, 传址
.参数 cch, 整数型
.DLL命令 DragFinish, , "shell32.dll", "DragFinish"
.参数 hDrop, 整数型
声明一个变量:
.版本 2
.程序集变量 lpPrevWndFunc, 整数型
在窗口创建完毕之后,加上代码:
.版本 2
lpPrevWndFunc = SetWindowLong (取窗口句柄 (), -4, 到整数 (&WndProc)) ' 更换消息处理程序
DragAcceptFiles (取窗口句柄 (), 真) ' 允许窗口拖放
ChangeWindowMessageFilter (#WM_COPYGLOBALDATA, #MSGFLT_ADD)
ChangeWindowMessageFilter (#WM_DROPFILES, #MSGFLT_ADD)
更换消息处理程序的时候哪个子程序在这里:
.版本 2
.子程序 WndProc, 整数型
.参数 hWnd, 整数型
.参数 Msg, 整数型
.参数 wParam, 整数型
.参数 lParam, 整数型
.局部变量 Point, POINT
.局部变量 FileNumber, 整数型
.局部变量 FileName, 文本型
.局部变量 FileNameLength, 整数型
.局部变量 i, 整数型
.如果真 (Msg = #WM_DROPFILES)
' DragQueryPoint (wParam, Point) ' 取文件放入窗口时的坐标
FileNumber = DragQueryFile (wParam, 4294967295, “”, 0) ' 取拖放文件数量
.变量循环首 (0, FileNumber - 1, 1, i)
FileNameLength = DragQueryFile (wParam, i, “”, 0) ' 取拖放文件名长度
.如果真 (FileNameLength ≠ 0)
FileName = 取空白文本 (FileNameLength)
DragQueryFile (wParam, i, FileName, FileNameLength + 1) ' 取拖放文件名
信息框 (FileName, 0, )
.如果真结束
.变量循环尾 ()
DragFinish (wParam) ' 拖放完毕
.如果真结束
返回 (CallWindowProc (lpPrevWndFunc, hWnd, Msg, wParam, lParam))
这个封装好了的回调函数的功能是弹出一个信息框,里面显示你拖放的文件(自己改)
发表回复