C++ 用C+发送WM#u dropfile+;和WinAPI到第三方应用程序
因此,我一直在拼命地尝试自动化拖放功能,并将我对解决方案的搜索范围缩小到了相当精细的代码块:C++ 用C+发送WM#u dropfile+;和WinAPI到第三方应用程序,c++,winapi,drag-and-drop,automation,windows-messages,C++,Winapi,Drag And Drop,Automation,Windows Messages,因此,我一直在拼命地尝试自动化拖放功能,并将我对解决方案的搜索范围缩小到了相当精细的代码块: // DragAndDrop.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <Windows.h> #include <Shlobj.h> #include <tchar.h> int main(int argc, char*
// DragAndDrop.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Windows.h>
#include <Shlobj.h>
#include <tchar.h>
int main(int argc, char* argv[]) {
for (int i = 0; i <= WM_DROPFILES; i++)
{
ChangeWindowMessageFilter (i, MSGFLT_ADD);
}
if (HWND hwnd = FindWindow ("OpusApp", NULL)) {
//HGLOBAL hGlobal = GlobalAlloc (GMEM_FIXED,
//sizeof ("d:\\DragMe.txt") + 2);
//char *strFile = (char*) GlobalLock
//(hGlobal);
//strcpy (strFile, "d:\\DragMe.txt");
//strFile [strlen ("d:\\DragMe.txt") +
//1] = NULL;
char filename[] = "d:\\DragMe.txt";
POINT point;
point.x = 480;
point.y = 480;
HGLOBAL hMem = GlobalAlloc(GHND, sizeof(DROPFILES) + strlen(filename)+2);
DROPFILES *dfiles = (DROPFILES*) GlobalLock(hMem);
if (!dfiles)
{
GlobalFree(hMem);
return NULL;
}
dfiles->pFiles = sizeof(DROPFILES);
dfiles->pt = point;
dfiles->fNC = TRUE;
dfiles->fWide = FALSE;
memcpy(&dfiles[1], filename, strlen(filename));
GlobalUnlock(hMem);
printf ("Sending Message...\n");
if (!PostMessage(hwnd, WM_DROPFILES, (WPARAM)hMem, 0)) {
printf("Error Posting Message!");
GlobalFree(hMem);
}
}
int temp = 0;
scanf("&d", temp);
return 0;
}
//DragAndDrop.cpp:定义控制台应用程序的入口点。
//
#包括“stdafx.h”
#包括
#包括
#包括
int main(int argc,char*argv[]){
for(int i=0;i pFiles=sizeof(DROPFILES);
dfiles->pt=点;
dfiles->fNC=TRUE;
dfiles->fWide=FALSE;
memcpy(&d文件[1],文件名,strlen(文件名));
GlobalUnlock(hMem);
printf(“发送消息…\n”);
if(!PostMessage(hwnd,WM_DROPFILES,(WPARAM)hMem,0)){
printf(“发布错误消息!”);
全球自由度(hMem);
}
}
内部温度=0;
scanf(“&d”,温度);
返回0;
}
…我为我的代码中的任何不好的词道歉…它们只是为了调试目的。无论如何,上面的内容非常简单,它可以与Microsoft Word、Excel和记事本一起使用…但是对于许多应用程序来说,它根本不起作用(Spy++甚至不记录WM_DROPFILES消息在这些情况下,系统范围内的,这很奇怪…).我甚至尝试过为有问题的应用程序将代码编译为x64或x86,但没有改变
我觉得我可能错误地使用了FindWindow(我使用了与AutoIT捆绑的窗口信息工具来获取窗口类,因为我发现Spy++非常混乱)。无论如何,我设置了一个悬赏,因为我真的需要弄清楚这一点
我需要使用的应用程序名为Dartfish,它是Windows 7上的32位应用程序…我需要将视频文件列表发送到其界面的特定区域(特定窗格),我正在尝试使用上述代码执行此操作
有什么帮助吗?我非常感谢!!
ChangeWindowMessageFilter/Ex()
不授予您将指定消息发送给其他进程的权利。它授予其他进程(特别是较低完整性进程)将该消息发送给您的权利。因此,请摆脱它,这对您没有好处
下一步,尝试发送Unicode文件名,并将dfiles->fWide
设置为TRUE,然后查看是否有区别。某些应用程序不处理Ansi数据。Windows是基于Unicode的操作系统。用于了解给定HWND是否需要Ansi或Unicode窗口消息
最后,一些应用程序根本不实现
WM\u DROPFILES
(它们不调用dragaacceptfiles()
或启用WS\u EX\u ACCEPTFILES
)。在现代Windows版本中,处理拖放操作的首选方法是实现该界面,并使用将其与HWND关联。没有API可检索HWND的IDropTarget
,但可以手动执行:
(改编自本次讨论:)
如果HWND具有
IDropTarget
,则可以使用IDataObject
包装DROPFILES
数据,并将其传递给IDropTarget::Drop()
方法。如果Drop()
接受数据,不要发布WM\u DROPFILES
消息。但是,诀窍是IDropTarget*
指针由GetProp()返回
与拥有HWND的进程相关,因此您必须将其封送到您的进程中,或者将代码注入HWND的进程中,以便实际使用接口指针。我使用了与您的代码几乎相同的代码,并在许多应用程序中取得了很好的效果。我认为您的问题在于您找到的窗口FindWindow()是一个顶级窗口,它可能不是在目标应用中启用拖放的窗口。某些应用仅启用选定的子窗口进行拖放。问题当然是找到该窗口。我还没有找到任何简单的解决方案。您可以递归枚举顶部窗口的所有子窗口使用EnumChildWindows()并尝试识别正确的窗口(即,按类、ID、窗口样式或其他参数),但这很糟糕。我使用SpyXX,但这也不是一个很好的解决方案。祝你好运。你的目标窗口是否有WS_EX_ACCEPTFILES样式?看,这就是问题所在……它是第三方、封闭源代码的应用程序。我不知道。因此完全有可能我选错了树,应用程序甚至可能没有WM_DROPFILES的事件处理程序?或者所有windows应用程序都处理此消息吗默认情况下?要检测WS_EX_ACCEPTFILES样式,您可以将GetWindowLong与GWL_EXSTYLE参数一起使用。
WS_EX_ACCEPTFILES
只是一种快捷方式,以避免调用DragAcceptFiles()
。但不,默认情况下,所有应用程序都不会处理WM DROPFILES
放弃它。单个应用程序必须处理WM_DROPFILES
来决定如何使用拖动的文件名。好的,谢谢你清理这些文件名。请参阅下文;我一直在研究你的解决方案。检索IDropTarget
的代码看起来无法跨进程工作(至少,检索到的值没有意义)。如果目标应用程序注册了drop target(如上所述),您可以使用它。如果您阅读了我链接到的讨论,则通过分析DoDragDrop()的内部工作来确定IDropTarget
检索代码
,它与IDropTarget
一起跨流程边界工作。其他在线来源,包括和,确认了这一点。在您的第一个链接中,建议使用此方法的评论者也说(在后面的评论中)您需要在相同的地址空间中运行。我知道DoDragDrop
可以跨进程运行;我还知道它使用在每个进程中运行的OLE代码。最后,如何可能每个注册的IDropTarget
指针在每个进程的地址空间中都有效?Remy,您的答案与建议一致我还有一个相关的问题,我有一个“半生不熟的”
IDropTarget* GetRegisteredDropTargetFromWnd (HWND hWnd)
{
IUnknown *pBuffer = (IUnknown *) GetProp (hWnd, TEXT("OleDropTargetInterface"));
if (pBuffer != NULL)
{
IDropTarget *pRetVal = NULL;
if (SUCCEEDED(pBuffer->QueryInterface(IID_IDropTarget, (void **) &pRetVal)))
return pRetVal;
}
return NULL;
}