VC模拟文件拖拽

来源:互联网 发布:mysql #什么意思 编辑:程序博客网 时间:2024/04/30 18:02

1 引言

用到海康的一个视频播放器VSPlayer,不支持命令行参数,设置为默认播放器的话打开视频文件时只是启动了播放器而不会播放文件。因此每次都要先打开播放器然后选择文件,而且一旦打开新的文件播放器窗口都会再次回到屏幕中央,很不方便。但是该播放器支持文件拖拽到窗口播放,因此考虑自己写一个程序接受视频文件(设为海康视频默认程序)然后模拟文件拖拽到VSPlayer窗口并将窗口移动到之前的位置。

2 原理

模拟文件拖拽基本原理是向目标窗口发送WM_DROPFILES消息,同时提供文件拖拽相关参数(DROPFILES结构体和文件名),因此需要在目标进程的虚拟地址空间中申请内存存放拖拽相关参数。用到的主要结构体或函数如下

  1. DROPFILES结构体,定义了CF_HDROP剪贴板的格式,后面跟着一个双null-terminated的文件名列表(可能有多个文件,中间用'\0'间隔,最后双null-terminated)

    typedef struct _DROPFILES {  DWORD pFiles;         // 结构体后紧跟的文件名的偏移量,等于结构体的大小  POINT pt;             // 拖拽点坐标  BOOL  fNC;            // 指示pt的坐标类型,FALSE:客户区坐标,TRUE:非客户区点的屏幕坐标  BOOL  fWide;          // 文件字符集,FALSE:ANSI,TRUE:Unicode} DROPFILES, *LPDROPFILES;
  2. 进程内存操作

    函数 说明 VirtualAllocEx 在指定进程的虚拟地址空间申请内存区域,msdn WriteProcessMemory 向指定进程的内存区域写数据,msdn VirtualFreeEx 释放VirtualAllocEx申请的内存区域,msdn

3 实现

为了调试时方便就用了控制台程序,因此每次打开时会闪现一个控制台窗口,不想弹窗的话可以改为Win32实现。完整代码如下(最终使用时偶尔会出现只打开播放器不播放视频的情况,感觉像是模拟拖拽有一定的概率失败,不知是程序的问题还是播放器的问题,Win10下测试)

#include <stdio.h>#include <windows.h>#include <shlobj.h>#include <tlhelp32.h>// 由进程名获取进程ID(需要头文件tlhelp32.h)// 失败返回0DWORD GetProcessIDFromName(LPCSTR szName){    DWORD id = 0;       // 进程ID    PROCESSENTRY32 pe;  // 进程信息    pe.dwSize = sizeof(PROCESSENTRY32);    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); // 获取系统进程列表    if(Process32First(hSnapshot, &pe))      // 返回系统中第一个进程的信息    {        do        {            if(0 == _stricmp(pe.szExeFile, szName)) // 不区分大小写比较            {                id = pe.th32ProcessID;                break;            }        }while(Process32Next(hSnapshot, &pe));      // 下一个进程    }    CloseHandle(hSnapshot);     // 删除快照    return id;}int main(int argc, char* argv[]){    int nWaitExitMs = 1000; // 输出信息显示时长    // 检查参数    if (argc < 2)    {        printf("缺少文件名参数,程序退出\n");        Sleep(nWaitExitMs);        return 0;    }    printf("%s\n", argv[1]);    // 输出文件名    // VSPlayer已打开则记录窗口位置并关闭    HWND hWnd = FindWindow(NULL, "VSPlayer");    RECT rect;    rect.left = -1;    if (hWnd)    {        GetWindowRect(hWnd, &rect);         // 记录窗口位置        DWORD pid = GetProcessIDFromName("VSPlayer.exe");;        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);        if (hProcess)        {            TerminateProcess(hProcess, 0);      // 终止进程            CloseHandle(hProcess);        }    }    // 打开VSPlayer, 获取窗口句柄    STARTUPINFO si;    PROCESS_INFORMATION pi;    memset(&si, 0, sizeof(si));    si.cb = sizeof(si);    memset(&pi, 0, sizeof(pi));    printf("正在打开VSPlayer……\n");    CreateProcess(NULL, "VSPlayer.exe", NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);    // 打开VSPlayer    hWnd = FindWindow(NULL, "VSPlayer");    int tCnt = 0;    while(hWnd == NULL && tCnt < 1000)          // 等待打开完成或超时    {        Sleep(1);        hWnd = FindWindow(NULL, "VSPlayer");        tCnt++;    }    if (NULL == hWnd)    {        printf("打开VSPlayer失败,程序退出\n");        Sleep(nWaitExitMs);        return 0;    }    // 填充DROPFILES    int bufferSize = sizeof(DROPFILES)+strlen(argv[1])+2;    char* pBuffer = new char[bufferSize];    memset(pBuffer, 0, bufferSize);    DROPFILES* pDrop = (DROPFILES*)pBuffer;    pDrop->pFiles = sizeof(DROPFILES);    pDrop->fWide = FALSE;    pDrop->fNC = FALSE;    pDrop->pt.x = 10;    pDrop->pt.y = 10;    sprintf_s(pBuffer+sizeof(DROPFILES), strlen(argv[1])+2, argv[1]);    // 获取特定权限的进程句柄    HANDLE hProcess = OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_WRITE, FALSE, pi.dwProcessId);    if (NULL == hProcess)    {        delete [] pBuffer;        CloseHandle(pi.hThread);        CloseHandle(pi.hProcess);        printf("获取进程句柄失败,程序退出\n");        Sleep(nWaitExitMs);        return 0;    }    // 申请进程虚拟内存    char* pMem = (char*)VirtualAllocEx(hProcess, NULL, bufferSize, MEM_COMMIT, PAGE_READWRITE);    if (NULL == pMem)    {        delete [] pBuffer;        CloseHandle(hProcess);        CloseHandle(pi.hThread);        CloseHandle(pi.hProcess);        printf("申请进程虚拟内存失败,程序退出\n");        Sleep(nWaitExitMs);        return 0;    }    // 写进程内存    if(WriteProcessMemory(hProcess, pMem, pBuffer, bufferSize, NULL))    {        SendMessage(hWnd, WM_DROPFILES, (WPARAM)pMem, 0);       // 发送WM_DROPFILES消息        Sleep(200);    }    else    {        printf("写进程内存失败,程序退出\n");        Sleep(nWaitExitMs);    }    // 移动窗口到之前位置    if (rect.left > 0)    {        SetWindowPos(hWnd, NULL, rect.left, rect.top, 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE);    }    // 释放    delete [] pBuffer;    VirtualFreeEx(hProcess, pMem, 0, MEM_RELEASE);    CloseHandle(hProcess);    CloseHandle(pi.hThread);    CloseHandle(pi.hProcess);    return 0;}

本文原文链接 http://blog.csdn.net/yanglx2022/article/details/48322237

0 0
原创粉丝点击