鱼C论坛

 找回密码
 立即注册
查看: 1120|回复: 7

[已解决]接收拖拽到其它窗口的文件路径

[复制链接]
发表于 2022-2-24 10:53:11 | 显示全部楼层 |阅读模式
10鱼币

想做一个无窗口后台程序,可以获取指定窗口的拖拽事件,得到拖拽文件路径
(只要是获取拖拽其它窗口的文件,所以窗口组件的拖拽事件self.setAcceptDrops(True)是不适应的)

import win32gui, win32ui, win32con
hwnd = win32gui.FindWindow(None, "Test Dialogs")#获取窗口句柄
win32gui.DragAcceptFiles(hwnd, True) #定义一个窗口句柄接受拖拽

以下找到的示例无效
wnd = win32ui.CreateWindowFromHandle(hwnd)
wnd.HookMessage(self.test, win32con.WM_DROPFILES)


请教有可以实现的方法吗?

谢谢啦!
最佳答案
2022-2-24 10:53:12
本帖最后由 hrpzcf 于 2022-3-11 12:13 编辑

看你还没解决,我按照楼上大佬的代码修改了做成模块了,你自己看看吧

GouZi.zip (12.67 KB, 下载次数: 6)

下载附件,把里面三个文件解压至你项目里能import 到的地方,用法:
  1. import time

  2. from GouZi import *


  3. def test1():
  4.     # 实例化一个文件拖放事件钩子客户端
  5.     # 当然,你想直接调用dll也行,可导出的函数跟DragHookClient类里的函数同名
  6.     dh = DragHookClient()
  7.     print(f"启用钩子:{dh.HookDrag()}")  # 安装拖放事件钩子
  8.     print(f"钩子是否启用:{dh.IsHooked()}")  # 检查钩子是否已安装
  9.     count = 0
  10.     while count < 60:  # while True:
  11.         count += 1
  12.         if dh.HasNewDropFiles():  # 查询是否有新的拖放事件
  13.             print(dh.GetNewDropFiles())  # 获取新的拖放事件生成的路径列表
  14.         time.sleep(1)
  15.     dh.UnHookDrag()  # 程序结束不要忘记卸载钩子


  16. def test2():
  17.     with DragHookClient() as dh:
  18.         if dh.IsHooked():  # 检查钩子是否已安装
  19.             print("钩子已启用")
  20.         else:
  21.             print("钩子未启用")
  22.             return
  23.         count = 0
  24.         while count < 60:  # while True:
  25.             count += 1
  26.             if dh.HasNewDropFiles():  # 查询是否有新的拖放事件
  27.                 print(dh.GetNewDropFiles())  # 获取新的拖放事件生成的路径列表
  28.             time.sleep(1)


  29. if __name__ == "__main__":
  30.     # test1()
  31.     test2()
复制代码



GouZi.py
  1. import sys
  2. from ctypes import c_bool, c_wchar_p, windll
  3. from os import path

  4. __all__ = ["DragHookClient"]

  5. if sys.maxsize > 0xFFFFFFFF:
  6.     dllName = "GouZi_vc143_x64.dll"
  7. else:
  8.     dllName = "GouZi_vc143_x86.dll"
  9. rootPath = path.dirname(path.realpath(__file__))
  10. dllFullPath = path.join(rootPath, dllName)


  11. class DragHookClient:
  12.     """WIN全局文件拖放事件钩子客户端"""

  13.     def __init__(self):
  14.         self.__hook = windll.LoadLibrary(dllFullPath)
  15.         self.__hook.IsHooked.restype = c_bool
  16.         self.__hook.HasNewDropFiles.restype = c_bool
  17.         self.__hook.HookDrag.restype = c_bool
  18.         self.__hook.GetNewDropFiles.restype = c_wchar_p

  19.     def IsHooked(self) -> bool:
  20.         """检查是否已启用全局文件拖放事件钩子"""
  21.         return self.__hook.IsHooked()

  22.     def HasNewDropFiles(self) -> bool:
  23.         """检查是否有新的文件拖放事件"""
  24.         return self.__hook.HasNewDropFiles()

  25.     def UnHookDrag(self) -> None:
  26.         """停止全局文件拖放事件钩子"""
  27.         self.__hook.UnHookDrag()

  28.     def HookDrag(self) -> bool:
  29.         """启用全局文件拖放事件钩子"""
  30.         return self.__hook.HookDrag()

  31.     def GetNewDropFiles(self) -> list:
  32.         """以列表形式返回检测到的全局文件拖放事件的文件路径"""
  33.         string = self.__hook.GetNewDropFiles()
  34.         return [s for s in string.strip().split("\n") if s]

  35.     # def __del__(self) -> None:
  36.     #    self.__hook.UnHookDrag()

  37.     def __enter__(self) -> "DragHookClient":
  38.         self.__hook.HookDrag()
  39.         return self

  40.     def __exit__(self, excType, excValue, excTB) -> None:
  41.         self.__hook.UnHookDrag()
复制代码


Hook.c
  1. #include <Windows.h>
  2. #include <strsafe.h>

  3. #define MAX_STRLEN 131072
  4. #define LOCKER TEXT("j5u7ld6va0b489sj1y3k28r1n3b1")
  5. #define IDRAGFILE INFINITE

  6. typedef struct {
  7.     INT len;
  8.     TCHAR str[MAX_STRLEN];
  9. } cp_t;

  10. #pragma data_seg("shared")
  11. static BOOL hasNewDrops = FALSE;
  12. static cp_t dropedFiles = { 0 };
  13. static HHOOK hHookHnd = NULL;
  14. #pragma data_seg()
  15. #pragma comment(linker, "/section:shared,rws")

  16. static HINSTANCE hLibInst;

  17. BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
  18.     switch (reason) {
  19.     case DLL_PROCESS_ATTACH:
  20.         hLibInst = instance;
  21.     }
  22.     return TRUE;
  23. }

  24. static void TargetWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
  25.     switch (message) {
  26.     case WM_DROPFILES: {
  27.         HDROP hDrop = (HDROP)wParam;
  28.         UINT reqSize = 0;
  29.         TCHAR buffer[MAX_PATH];
  30.         UINT count = DragQueryFile(hDrop, IDRAGFILE, NULL, 0);
  31.         HANDLE hMutex = CreateMutex(NULL, FALSE, LOCKER);
  32.         if (!hMutex) break;
  33.         WaitForSingleObject(hMutex, INFINITE);
  34.         if (!hasNewDrops) {
  35.             hasNewDrops = TRUE;
  36.             dropedFiles.len = 0;
  37.             dropedFiles.str[0] = 0;
  38.         }
  39.         for (UINT i = 0; i < count; ++i) {
  40.             reqSize = DragQueryFile(hDrop, i, NULL, 0);
  41.             if (reqSize >= MAX_PATH)
  42.                 continue;
  43.             if (dropedFiles.len + reqSize + 1 >= MAX_STRLEN)
  44.                 break;
  45.             DragQueryFile(hDrop, i, buffer, MAX_PATH);
  46.             StringCchCat(dropedFiles.str, MAX_STRLEN, buffer);
  47.             StringCchCat(dropedFiles.str, MAX_STRLEN, TEXT("\n"));
  48.             dropedFiles.len += (reqSize + 1);
  49.         }
  50.         dropedFiles.str[dropedFiles.len] = 0;
  51.         ReleaseMutex(hMutex);
  52.         break;
  53.     }
  54.     }
  55. }

  56. static LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) {
  57.     switch (nCode) {
  58.     case HC_ACTION: {
  59.         MSG *pMsg = (MSG *)lParam;
  60.         TargetWndProc(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam);
  61.         break;
  62.     }
  63.     }
  64.     return CallNextHookEx(hHookHnd, nCode, wParam, lParam);
  65. }

  66. __declspec(dllexport) void UnHookDrag(void) {
  67.     if (hHookHnd)
  68.         UnhookWindowsHookEx(hHookHnd);
  69.     hHookHnd = NULL;
  70. }

  71. __declspec(dllexport) BOOL HookDrag(void) {
  72.     if (hHookHnd) return TRUE;
  73.     hHookHnd = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, hLibInst, 0);
  74.     return hHookHnd != NULL;
  75. }

  76. __declspec(dllexport) BOOL IsHooked(void) {
  77.     return hHookHnd != NULL;
  78. }

  79. __declspec(dllexport) BOOL HasNewDropFiles(void) {
  80.     BOOL newDrops = FALSE;
  81.     if (!IsHooked()) return newDrops;
  82.     HANDLE hMutex = CreateMutex(NULL, FALSE, LOCKER);
  83.     if (!hMutex) return newDrops;
  84.     WaitForSingleObject(hMutex, INFINITE);
  85.     newDrops = hasNewDrops;
  86.     ReleaseMutex(hMutex);
  87.     return newDrops;
  88. }

  89. __declspec(dllexport) TCHAR *GetNewDropFiles(void) {
  90.     static TCHAR dropedTemp[MAX_STRLEN];
  91.     dropedTemp[0] = 0;
  92.     if (!IsHooked()) return dropedTemp;
  93.     HANDLE hMutex = CreateMutex(NULL, FALSE, LOCKER);
  94.     if (!hMutex) return dropedTemp;
  95.     WaitForSingleObject(hMutex, INFINITE);
  96.     hasNewDrops = FALSE;
  97.     if (dropedFiles.len > 0) {
  98.         StringCchCopy(dropedTemp, MAX_STRLEN, dropedFiles.str);
  99.         dropedFiles.len = 0;
  100.         dropedFiles.str[0] = 0;
  101.     }
  102.     ReleaseMutex(hMutex);
  103.     return dropedTemp;
  104. }
复制代码




@人造人


最佳答案

查看完整内容

看你还没解决,我按照楼上大佬的代码修改了做成模块了,你自己看看吧 下载附件,把里面三个文件解压至你项目里能import 到的地方,用法: GouZi.py Hook.c @人造人
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-2-24 10:53:12 | 显示全部楼层    本楼为最佳答案   
本帖最后由 hrpzcf 于 2022-3-11 12:13 编辑

看你还没解决,我按照楼上大佬的代码修改了做成模块了,你自己看看吧

GouZi.zip (12.67 KB, 下载次数: 6)

下载附件,把里面三个文件解压至你项目里能import 到的地方,用法:
  1. import time

  2. from GouZi import *


  3. def test1():
  4.     # 实例化一个文件拖放事件钩子客户端
  5.     # 当然,你想直接调用dll也行,可导出的函数跟DragHookClient类里的函数同名
  6.     dh = DragHookClient()
  7.     print(f"启用钩子:{dh.HookDrag()}")  # 安装拖放事件钩子
  8.     print(f"钩子是否启用:{dh.IsHooked()}")  # 检查钩子是否已安装
  9.     count = 0
  10.     while count < 60:  # while True:
  11.         count += 1
  12.         if dh.HasNewDropFiles():  # 查询是否有新的拖放事件
  13.             print(dh.GetNewDropFiles())  # 获取新的拖放事件生成的路径列表
  14.         time.sleep(1)
  15.     dh.UnHookDrag()  # 程序结束不要忘记卸载钩子


  16. def test2():
  17.     with DragHookClient() as dh:
  18.         if dh.IsHooked():  # 检查钩子是否已安装
  19.             print("钩子已启用")
  20.         else:
  21.             print("钩子未启用")
  22.             return
  23.         count = 0
  24.         while count < 60:  # while True:
  25.             count += 1
  26.             if dh.HasNewDropFiles():  # 查询是否有新的拖放事件
  27.                 print(dh.GetNewDropFiles())  # 获取新的拖放事件生成的路径列表
  28.             time.sleep(1)


  29. if __name__ == "__main__":
  30.     # test1()
  31.     test2()
复制代码



GouZi.py
  1. import sys
  2. from ctypes import c_bool, c_wchar_p, windll
  3. from os import path

  4. __all__ = ["DragHookClient"]

  5. if sys.maxsize > 0xFFFFFFFF:
  6.     dllName = "GouZi_vc143_x64.dll"
  7. else:
  8.     dllName = "GouZi_vc143_x86.dll"
  9. rootPath = path.dirname(path.realpath(__file__))
  10. dllFullPath = path.join(rootPath, dllName)


  11. class DragHookClient:
  12.     """WIN全局文件拖放事件钩子客户端"""

  13.     def __init__(self):
  14.         self.__hook = windll.LoadLibrary(dllFullPath)
  15.         self.__hook.IsHooked.restype = c_bool
  16.         self.__hook.HasNewDropFiles.restype = c_bool
  17.         self.__hook.HookDrag.restype = c_bool
  18.         self.__hook.GetNewDropFiles.restype = c_wchar_p

  19.     def IsHooked(self) -> bool:
  20.         """检查是否已启用全局文件拖放事件钩子"""
  21.         return self.__hook.IsHooked()

  22.     def HasNewDropFiles(self) -> bool:
  23.         """检查是否有新的文件拖放事件"""
  24.         return self.__hook.HasNewDropFiles()

  25.     def UnHookDrag(self) -> None:
  26.         """停止全局文件拖放事件钩子"""
  27.         self.__hook.UnHookDrag()

  28.     def HookDrag(self) -> bool:
  29.         """启用全局文件拖放事件钩子"""
  30.         return self.__hook.HookDrag()

  31.     def GetNewDropFiles(self) -> list:
  32.         """以列表形式返回检测到的全局文件拖放事件的文件路径"""
  33.         string = self.__hook.GetNewDropFiles()
  34.         return [s for s in string.strip().split("\n") if s]

  35.     # def __del__(self) -> None:
  36.     #    self.__hook.UnHookDrag()

  37.     def __enter__(self) -> "DragHookClient":
  38.         self.__hook.HookDrag()
  39.         return self

  40.     def __exit__(self, excType, excValue, excTB) -> None:
  41.         self.__hook.UnHookDrag()
复制代码


Hook.c
  1. #include <Windows.h>
  2. #include <strsafe.h>

  3. #define MAX_STRLEN 131072
  4. #define LOCKER TEXT("j5u7ld6va0b489sj1y3k28r1n3b1")
  5. #define IDRAGFILE INFINITE

  6. typedef struct {
  7.     INT len;
  8.     TCHAR str[MAX_STRLEN];
  9. } cp_t;

  10. #pragma data_seg("shared")
  11. static BOOL hasNewDrops = FALSE;
  12. static cp_t dropedFiles = { 0 };
  13. static HHOOK hHookHnd = NULL;
  14. #pragma data_seg()
  15. #pragma comment(linker, "/section:shared,rws")

  16. static HINSTANCE hLibInst;

  17. BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
  18.     switch (reason) {
  19.     case DLL_PROCESS_ATTACH:
  20.         hLibInst = instance;
  21.     }
  22.     return TRUE;
  23. }

  24. static void TargetWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
  25.     switch (message) {
  26.     case WM_DROPFILES: {
  27.         HDROP hDrop = (HDROP)wParam;
  28.         UINT reqSize = 0;
  29.         TCHAR buffer[MAX_PATH];
  30.         UINT count = DragQueryFile(hDrop, IDRAGFILE, NULL, 0);
  31.         HANDLE hMutex = CreateMutex(NULL, FALSE, LOCKER);
  32.         if (!hMutex) break;
  33.         WaitForSingleObject(hMutex, INFINITE);
  34.         if (!hasNewDrops) {
  35.             hasNewDrops = TRUE;
  36.             dropedFiles.len = 0;
  37.             dropedFiles.str[0] = 0;
  38.         }
  39.         for (UINT i = 0; i < count; ++i) {
  40.             reqSize = DragQueryFile(hDrop, i, NULL, 0);
  41.             if (reqSize >= MAX_PATH)
  42.                 continue;
  43.             if (dropedFiles.len + reqSize + 1 >= MAX_STRLEN)
  44.                 break;
  45.             DragQueryFile(hDrop, i, buffer, MAX_PATH);
  46.             StringCchCat(dropedFiles.str, MAX_STRLEN, buffer);
  47.             StringCchCat(dropedFiles.str, MAX_STRLEN, TEXT("\n"));
  48.             dropedFiles.len += (reqSize + 1);
  49.         }
  50.         dropedFiles.str[dropedFiles.len] = 0;
  51.         ReleaseMutex(hMutex);
  52.         break;
  53.     }
  54.     }
  55. }

  56. static LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) {
  57.     switch (nCode) {
  58.     case HC_ACTION: {
  59.         MSG *pMsg = (MSG *)lParam;
  60.         TargetWndProc(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam);
  61.         break;
  62.     }
  63.     }
  64.     return CallNextHookEx(hHookHnd, nCode, wParam, lParam);
  65. }

  66. __declspec(dllexport) void UnHookDrag(void) {
  67.     if (hHookHnd)
  68.         UnhookWindowsHookEx(hHookHnd);
  69.     hHookHnd = NULL;
  70. }

  71. __declspec(dllexport) BOOL HookDrag(void) {
  72.     if (hHookHnd) return TRUE;
  73.     hHookHnd = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, hLibInst, 0);
  74.     return hHookHnd != NULL;
  75. }

  76. __declspec(dllexport) BOOL IsHooked(void) {
  77.     return hHookHnd != NULL;
  78. }

  79. __declspec(dllexport) BOOL HasNewDropFiles(void) {
  80.     BOOL newDrops = FALSE;
  81.     if (!IsHooked()) return newDrops;
  82.     HANDLE hMutex = CreateMutex(NULL, FALSE, LOCKER);
  83.     if (!hMutex) return newDrops;
  84.     WaitForSingleObject(hMutex, INFINITE);
  85.     newDrops = hasNewDrops;
  86.     ReleaseMutex(hMutex);
  87.     return newDrops;
  88. }

  89. __declspec(dllexport) TCHAR *GetNewDropFiles(void) {
  90.     static TCHAR dropedTemp[MAX_STRLEN];
  91.     dropedTemp[0] = 0;
  92.     if (!IsHooked()) return dropedTemp;
  93.     HANDLE hMutex = CreateMutex(NULL, FALSE, LOCKER);
  94.     if (!hMutex) return dropedTemp;
  95.     WaitForSingleObject(hMutex, INFINITE);
  96.     hasNewDrops = FALSE;
  97.     if (dropedFiles.len > 0) {
  98.         StringCchCopy(dropedTemp, MAX_STRLEN, dropedFiles.str);
  99.         dropedFiles.len = 0;
  100.         dropedFiles.str[0] = 0;
  101.     }
  102.     ReleaseMutex(hMutex);
  103.     return dropedTemp;
  104. }
复制代码




@人造人


评分

参与人数 2荣誉 +6 鱼币 +6 贡献 +3 收起 理由
heverst + 1 + 1 感谢楼主无私奉献!
人造人 + 5 + 5 + 3 无条件支持楼主!

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-3-1 02:36:11 | 显示全部楼层
本帖最后由 人造人 于 2022-3-1 02:43 编辑

现学现卖,耗时4天,^_^
就我所知,目前拖放文件有两种完全不同的方法
一种是通过消息机制,使用 WM_DROPFILES 消息
另一种是通过 com 接口,使用 IDropSource IDataObject IDropTarget 这3个接口
第一种我弄懂了,写了一个C代码
第二种我找不到能用的资料,这方面的资料太少了
而且现在大部分软件已经不使用消息机制了,使用的是 com 接口
下面的代码是C语言版本的,核心原理就是一个全局钩子,在python中我还不知道怎么用全局钩子
如果你使用第一种方法的话,这方面的资料很多,你完全可以参考这个代码,把这个代码修改成python版本的
实在不行,你可以 python + c 呀,全局钩子的部分在 C 中做,就是在 python 中调用一下,这完全没有问题
对于第二种方法,我真的没办法了,这方面的资料真的太少了,^_^

drag.c
  1. #include <windows.h>
  2. #include <wchar.h>
  3. #include <strsafe.h>

  4. #define BUFF_SIZE 4096

  5. static TCHAR video_buff[BUFF_SIZE] = TEXT("hello world!");

  6. static LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
  7.     switch(message) {
  8.         case WM_CREATE: {
  9.             DragAcceptFiles(hwnd, TRUE);
  10.             return 0;
  11.         }
  12.         case WM_DROPFILES: {
  13.             HDROP hdrop = (HDROP)wParam;
  14.             POINT point; DragQueryPoint(hdrop, &point);
  15.             StringCchPrintf(video_buff, BUFF_SIZE, TEXT("point: (%ld, %ld)"), point.x, point.y);
  16.             UINT count = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
  17.             TCHAR filename[MAX_PATH];
  18.             filename[0] = TEXT('\n');
  19.             for(UINT i = 0; i < count; ++i) {
  20.                 DragQueryFile(hdrop, i, filename + 1, MAX_PATH - 1);
  21.                 StringCchCat(video_buff, BUFF_SIZE, filename);
  22.             }
  23.             DragFinish(hdrop);
  24.             RECT rect;
  25.             GetClientRect(hwnd, &rect);
  26.             InvalidateRect(hwnd, &rect, TRUE);
  27.             return 0;
  28.         }
  29.         case WM_PAINT: {
  30.             PAINTSTRUCT ps;
  31.             HDC hdc = BeginPaint(hwnd, &ps);
  32.             RECT rect; GetClientRect(hwnd, &rect);
  33.             DrawText(hdc, video_buff, -1, &rect, DT_LEFT);
  34.             EndPaint(hwnd, &ps);
  35.             return 0;
  36.         }
  37.         case WM_DESTROY: {
  38.             DragAcceptFiles(hwnd, FALSE);
  39.             PostQuitMessage(0);
  40.             return 0;
  41.         }
  42.     }
  43.     return DefWindowProc(hwnd, message, wParam, lParam);
  44. }

  45. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {
  46.     const TCHAR szAppName[] = TEXT("MyWindows");
  47.     WNDCLASS wndclass = {0};
  48.     wndclass.style = CS_HREDRAW | CS_VREDRAW;
  49.     wndclass.lpfnWndProc = MainWndProc;
  50.     wndclass.cbClsExtra = 0;
  51.     wndclass.cbWndExtra = 0;
  52.     wndclass.hInstance = hInstance;
  53.     wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  54.     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  55.     wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  56.     wndclass.lpszMenuName = NULL;
  57.     wndclass.lpszClassName = szAppName;
  58.     if(!RegisterClass(&wndclass)) {
  59.         MessageBox(NULL, TEXT("这个程序需要在 Windows NT 才能执行!"), szAppName, MB_ICONERROR);
  60.         return 0;
  61.     }
  62.     HWND hwnd = CreateWindow(szAppName, TEXT("鱼C工作室"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
  63.             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
  64.     ShowWindow(hwnd, iCmdShow);
  65.     UpdateWindow(hwnd);
  66.     MSG msg;
  67.     while(GetMessage(&msg, NULL, 0, 0)) {
  68.         TranslateMessage(&msg);
  69.         DispatchMessage(&msg);
  70.     }
  71.     return msg.wParam;
  72. }
复制代码


common.h
  1. #ifndef _COMMON_H_
  2. #define _COMMON_H_

  3. #include <windows.h>

  4. typedef struct {
  5.     POINT point;
  6.     UINT count;
  7.     TCHAR path[0][MAX_PATH];
  8. } shared_t;

  9. #define SHARED_STRUCT_SIZE(n) (sizeof(shared_t) + n * sizeof(TCHAR [MAX_PATH]))

  10. #endif
复制代码


hook.c
  1. #include "common.h"

  2. static HHOOK hhook;
  3. static HINSTANCE hinstLib;
  4. static HWND hwndCaller __attribute((section(TEXT("shared")), shared));

  5. static void TargetWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
  6.     switch(message) {
  7.         case WM_DROPFILES: {
  8.             HDROP hdrop = (HDROP)wParam;
  9.             UINT count = DragQueryFile(hdrop, 0xffffffff, NULL, 0);
  10.             UINT block_size = SHARED_STRUCT_SIZE(count);
  11.             shared_t *shared = malloc(block_size);
  12.             DragQueryPoint(hdrop, &shared->point);
  13.             shared->count = count;
  14.             for(UINT i = 0; i < shared->count; ++i) {
  15.                 DragQueryFile(hdrop, i, shared->path[i], MAX_PATH);
  16.             }
  17.             COPYDATASTRUCT cds = {0, block_size, shared};
  18.             HANDLE hMutex = CreateMutex(NULL, FALSE, TEXT("mutex_hook_dll"));
  19.             WaitForSingleObject(hMutex, INFINITE);
  20.             if(hwndCaller) SendMessage(hwndCaller, WM_COPYDATA, (WPARAM)hwnd, (LPARAM)&cds);
  21.             ReleaseMutex(hMutex);
  22.             free(shared);
  23.             break;
  24.         }
  25.     }
  26. }

  27. static LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) {
  28.     switch(nCode) {
  29.         case HC_ACTION: {
  30.             MSG *pMsg = (MSG *)lParam;
  31.             TargetWndProc(pMsg->hwnd, pMsg->message, pMsg->wParam, pMsg->lParam);
  32.             break;
  33.         }
  34.     }
  35.     return CallNextHookEx(hhook, nCode, wParam, lParam);
  36. }

  37. void InstallHook(HWND hwnd) {
  38.     HANDLE hMutex = CreateMutex(NULL, FALSE, TEXT("mutex_hook_dll"));
  39.     WaitForSingleObject(hMutex, INFINITE);
  40.     hwndCaller = hwnd;
  41.     ReleaseMutex(hMutex);
  42.     hhook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, hinstLib, 0);
  43. }

  44. void UninstallHook(void) {
  45.     HANDLE hMutex = CreateMutex(NULL, FALSE, TEXT("mutex_hook_dll"));
  46.     WaitForSingleObject(hMutex, INFINITE);
  47.     hwndCaller = NULL;
  48.     ReleaseMutex(hMutex);
  49.     UnhookWindowsHookEx(hhook);
  50.     hhook = NULL;
  51. }

  52. BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) {
  53.     switch(reason) {
  54.     case DLL_PROCESS_ATTACH:
  55.         hinstLib = instance;
  56.         break;
  57.     }
  58.     return TRUE;
  59. }
复制代码


main.c
  1. #include "common.h"
  2. #include <wchar.h>
  3. #include <strsafe.h>

  4. #define BUFF_SIZE 4096

  5. static TCHAR video_buff[BUFF_SIZE] = TEXT("hello world!");
  6. static HINSTANCE hinstLib;

  7. static LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
  8.     switch(message) {
  9.         case WM_CREATE: {
  10.             hinstLib = LoadLibrary(TEXT("hook.dll"));
  11.             void (*InstallHook)(HWND hwnd) = (void *)GetProcAddress(hinstLib, TEXT("InstallHook"));
  12.             InstallHook(hwnd);
  13.             return 0;
  14.         }
  15.         case WM_PAINT: {
  16.             PAINTSTRUCT ps;
  17.             HDC hdc = BeginPaint(hwnd, &ps);
  18.             RECT rect; GetClientRect(hwnd, &rect);
  19.             DrawText(hdc, video_buff, -1, &rect, DT_LEFT);
  20.             EndPaint(hwnd, &ps);
  21.             return 0;
  22.         }
  23.         case WM_COPYDATA: {
  24.             COPYDATASTRUCT *pcds = (COPYDATASTRUCT *)lParam;
  25.             shared_t *shared = (shared_t *)pcds->lpData;
  26.             StringCchPrintf(video_buff, BUFF_SIZE, TEXT("hwnd: %p\npoint: (%ld, %ld)"), wParam, shared->point.x, shared->point.y);
  27.             for(UINT i = 0; i < shared->count; ++i) {
  28.                 StringCchCat(video_buff, BUFF_SIZE, TEXT("\n"));
  29.                 StringCchCat(video_buff, BUFF_SIZE, shared->path[i]);
  30.             }
  31.             RECT rect;
  32.             GetClientRect(hwnd, &rect);
  33.             InvalidateRect(hwnd, &rect, TRUE);
  34.             return 0;
  35.         }
  36.         case WM_DESTROY: {
  37.             void (*UninstallHook)(void) = (void *)GetProcAddress(hinstLib, TEXT("UninstallHook"));
  38.             UninstallHook();
  39.             FreeLibrary(hinstLib);
  40.             PostQuitMessage(0);
  41.             return 0;
  42.         }
  43.     }
  44.     return DefWindowProc(hwnd, message, wParam, lParam);
  45. }

  46. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {
  47.     const TCHAR szAppName[] = TEXT("MyWindows");
  48.     WNDCLASS wndclass = {0};
  49.     wndclass.style = CS_HREDRAW | CS_VREDRAW;
  50.     wndclass.lpfnWndProc = MainWndProc;
  51.     wndclass.cbClsExtra = 0;
  52.     wndclass.cbWndExtra = 0;
  53.     wndclass.hInstance = hInstance;
  54.     wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  55.     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  56.     wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  57.     wndclass.lpszMenuName = NULL;
  58.     wndclass.lpszClassName = szAppName;
  59.     if(!RegisterClass(&wndclass)) {
  60.         MessageBox(NULL, TEXT("这个程序需要在 Windows NT 才能执行!"), szAppName, MB_ICONERROR);
  61.         return 0;
  62.     }
  63.     HWND hwnd= CreateWindow(szAppName, TEXT("鱼C工作室"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT,
  64.             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
  65.     ShowWindow(hwnd, iCmdShow);
  66.     UpdateWindow(hwnd);
  67.     MSG msg;
  68.     while(GetMessage(&msg, NULL, 0, 0)) {
  69.         TranslateMessage(&msg);
  70.         DispatchMessage(&msg);
  71.     }
  72.     return msg.wParam;
  73. }
复制代码


1.gif

评分

参与人数 3荣誉 +11 鱼币 +11 贡献 +6 收起 理由
heverst + 1 + 1 感谢您的回复!
Stubborn + 5 + 5 + 3 感谢楼主无私奉献!
hrpzcf + 5 + 5 + 3 鱼C有你更精彩^_^

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2022-3-5 17:15:29 | 显示全部楼层
人造人 发表于 2022-3-1 02:36
现学现卖,耗时4天,^_^
就我所知,目前拖放文件有两种完全不同的方法
一种是通过消息机制,使用 WM_DROP ...

首先感谢你的回复及给出的建议,因为是想在python里做出最终效果

也不会C改PY,只能暂时用其它方式做测试,还不知道能不能行
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-3-6 14:07:15 | 显示全部楼层
新手报道
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-3-9 17:56:18 | 显示全部楼层
人造人 发表于 2022-3-1 02:36
现学现卖,耗时4天,^_^
就我所知,目前拖放文件有两种完全不同的方法
一种是通过消息机制,使用 WM_DROP ...

请问大佬,hook.c里开头的
  1. static HWND hwndCaller __attribute((section(TEXT("shared")), shared));
复制代码
是什么意思,起什么作用?搜索都搜不到这样的用法

疑问来源:
1. 我用msys2里的GCC编译器编译你的代码,需要把上面那句TEXT("shared")改成"shared"才能正常编译,也可以达到你演示的效果。
2. 当我改用VS创建工程后,VC好像不支持__attribute(xxx),我试着只保留了
  1. static HWND hwndCaller;
复制代码
,各种调试后发现hook安装正常但是往drag.c创建的窗口拖放文件时,main.c创建的窗口收不到WM_COPYDATA消息(给case WM_COPYDATA分支下加了MessageBox发现没被触发)。一顿查后好像发现HWND不支持跨模块传递??
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-3-9 18:13:50 | 显示全部楼层
hrpzcf 发表于 2022-3-9 17:56
请问大佬,hook.c里开头的是什么意思,起什么作用?搜索都搜不到这样的用法

疑问来源:

https://www.baidu.com/baidu?tn=m ... 0%E6%8D%AE%E6%AE%B5

这是gcc的写法,用来共享数据段
全局钩子会把dll加载到其他进程地址空间,不共享数据段的话,其他进程不知道应该把拦截下来的数据发送到哪里
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2022-3-9 18:41:07 | 显示全部楼层
人造人 发表于 2022-3-9 18:13
https://www.baidu.com/baidu?tn=monline_7_dg&ie=utf-8&wd=dll%E5%85%B1%E4%BA%AB%E6%95%B0%E6%8D%AE%E6 ...

感谢大佬,VC下改成
  1. #pragma data_seg("shared")
  2. static HWND hwndCaller = NULL;
  3. #pragma data_seg()
  4. #pragma comment(linker,"/section:shared,rws")
复制代码
成功。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-22 09:17

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表