Windows 模拟用户点击桌面图标(双击、右击)

前言:2014-04-22记录在hi baidu上,现移过来。

思路:1、获取指定图标的坐标;2、发送右击、双击操作;

第一步: 获取坐标

/*
* Purpose: 获取32位桌面图标坐标
* Arguments:
*           hDeskWnd => 桌面窗口句柄
*           pszName  => 图标名称
*           lpPoint  => 图标坐标
* Returns:
*           TRUE     => 获取成功
*           FALSE    => 获取失败
*/
BOOL WINAPI GetXY32( HWND hDeskWnd, char *pszName, LPPOINT lpPoint)
{
    BOOL bRet = FALSE;
    // 遍历外部进程所有图标
    DWORD dwThreadId = 0;
    GetWindowThreadProcessId( hDeskWnd, &dwThreadId );
    HANDLE hProcess = OpenProcess( PROCESS_VM_READ|PROCESS_VM_OPERATION|PROCESS_VM_WRITE, FALSE, dwThreadId );
    if( hProcess == NULL ) {
        printf( "OpenProcess Failed.\n" );
    }
    else {
        LVITEMA* plvItem = (LVITEMA*)VirtualAllocEx( hProcess, NULL, sizeof(LVITEMA), MEM_COMMIT, PAGE_READWRITE );
        char *pszText = (char*)VirtualAllocEx( hProcess, NULL, 512,MEM_COMMIT, PAGE_READWRITE);
        POINT *pItemPt= (POINT*)VirtualAllocEx( hProcess, NULL, sizeof(POINT), MEM_COMMIT, PAGE_READWRITE);
        POINT pt;
        if( !pItemPt || !plvItem || !pszText ) {
            printf( "AllocEx Failed.\n" );
        }
        else {
            LVITEMA lvItem;
            lvItem.mask         = LVIF_TEXT;
            lvItem.cchTextMax   = 512;
            lvItem.pszText      = pszText;
            char szItemBuf[512] = {0};
            int nMaxItem = ::SendMessage( hDeskWnd, LVM_GETITEMCOUNT, 0, 0 );
            for( int nItem = 0; nItem < nMaxItem; nItem++ ) {
                lvItem.iItem    = nItem;
                lvItem.iSubItem = 0;
                // 将设置好的结构插入目标进程
                WriteProcessMemory( hProcess, plvItem, &lvItem, sizeof(lvItem), NULL);
                // 发送LVM_GETITEM消息
                BOOL retValue = (BOOL)::SendMessage( hDeskWnd, LVM_GETITEMTEXTA, nItem, (LPARAM)plvItem );
                // 获取pszText
                ReadProcessMemory( hProcess, pszText, szItemBuf, 512,NULL );
                if( _stricmp( szItemBuf, pszName ) == 0 ) {
                    // Send LVM_GETITEMPOSITION Get position
                    ::SendMessage( hDeskWnd, LVM_GETITEMPOSITION, nItem, (LPARAM)pItemPt);
                    ReadProcessMemory( hProcess, pItemPt, &pt, sizeof(POINT), NULL );
                    memcpy_s( lpPoint, sizeof(POINT), &pt, sizeof(POINT) );
                    bRet=TRUE;
                    break;
                }
            }
            VirtualFreeEx( hProcess, plvItem, 0, MEM_RELEASE);
            VirtualFreeEx( hProcess, pszText, 0, MEM_RELEASE);
            VirtualFreeEx( hProcess, pItemPt, 0, MEM_RELEASE);
        }
        CloseHandle(hProcess);
    }
    return bRet;
}

继续……

/*
* Purpose: 获取桌面图标坐标,在此处获取桌面窗口句柄,区分32位跟64位,以及Windows7和WindowsXP
* Arguments:
*           pszName  => 图标名称
*           lpPoint  => 图标坐标
* Returns:
*           TRUE     => 获取成功
*           FALSE    => 获取失败
*/
BOOL WINAPI GetDesktop( char *pszName, LPPOINT lpPoint )
{
    // 桌面上SysListView32的窗口句柄
    HWND hDeskWnd=NULL;
    // find windows7
    HWND hWnd= ::FindWindow( L"WorkerW", NULL );
    while( hWnd ) { 
        HWND hShellView = ::FindWindowEx( hWnd, NULL, L"SHELLDLL_DefView", NULL );
        if( hShellView ){ 
            hDeskWnd=::FindWindowEx( hShellView, NULL, L"SysListView32", NULL);
            break;
        } 
        hWnd = ::GetWindow( hWnd, GW_HWNDNEXT );
    } 
    // 在XP下找
    if( !hDeskWnd ) { 
        hWnd = ::FindWindow( L"ProgMan" , L"Program Manager" );
        if( hWnd ) { 
            hWnd = ::FindWindowEx( hWnd, NULL, L"SHELLDLL_DefView", NULL);
            hDeskWnd = ::FindWindowEx( hWnd, NULL, L"SysListView32", NULL);
        }
    } 
    if( !hDeskWnd ){
        printf( "Find Desktop Failed.\n" );
        return FALSE;
    } 
    BOOL bRet = FALSE;
    if( Is64BitOS() ) { 
        bRet = GetXY64( hDeskWnd, pszName, lpPoint );
    }
    else { 
        bRet = GetXY32( hDeskWnd, pszName, lpPoint );
    } 
    return bRet;
}

到此,获取到桌面的指定图标坐标,下一步开始模拟点击

第二步:双击、右击

  • 双击
    用python来模拟双击
################################################################################
# class FakeUserClicked: 模拟用户点击桌面指定坐标
# 传入参数:pos = [X,Y]
################################################################################
class FakeUserClicked:
    """docstring for FakeUserClicked"""
    def __init__(self, pos):
        self.posXY = pos

    # 模拟点击
    def FakeClicked(self):
        # 移动箭头到指定坐标
        autopy.mouse.move(self.posXY[0], self.posXY[1])
        autopy.mouse.click()
        time.sleep(0.03)
        autopy.mouse.click()
        return True

# 获取的坐标为原始坐标,也就是起点坐标
posXY[0] += 10
# 需要计算图标的高度,这里默认为30
posXY[1] += 30

print posXY[0],posXY[1]

# step2: 模拟执行
fakeClick = FakeUserClicked(posXY)
fakeClick.FakeClicked()
  • 右击
    右击操作主要是通过COM Shell32实现
/*
 * path ==> 指定程序目录
 * file_name ==> 程序名称
 * item_name ==> 菜单项
 * InvokeItemInPopupMenu("d:\\mydesktop", "PCHunter64.exe", "&load into pe editor");
 */
int InvokeItemInPopupMenu(const char * path, const char * file_name, const char * item_name)
{
    CoInitialize(NULL);
    Shell32::IShellDispatchPtr ptrShell;
    ptrShell.CreateInstance(__uuidof(Shell32::Shell));
    _variant_t var((short)Shell32::ssfRECENT);

    Shell32::FolderPtr ptrFolder = ptrShell->NameSpace(path);
    Shell32::FolderItemPtr ptrItem = ptrFolder->ParseName(file_name);  
    Shell32::FolderItemVerbsPtr t_verbs = ptrItem->Verbs();

    for (long i = 0; i < t_verbs->Count; ++i) {
        Shell32::FolderItemVerbPtr t_verb = t_verbs->Item(i);
        cout << t_verb->Name << endl;
        if (!_stricmp(t_verb->Name, item_name)) {
            t_verb->DoIt();
            Sleep(100);
        }
    }
    ptrItem.Release();
    ptrFolder.Release();
    ptrShell.Release();
    CoUninitialize();
    return 0;
}

需要注意的是,64位系统和32位系统获取坐标方法一样,只是ITEM结构不一样:

// 64位系统下ITEM结构
typedef struct tagLVITEM64A
{
    UINT mask;
    int iItem;
    int iSubItem;
    UINT state;
    UINT stateMask;
    INT64 pszText;
    int cchTextMax;
    int iImage;
    LPARAM lParam;
#if (_WIN32_IE >= 0x0300)
    int iIndent;
#endif
#if (_WIN32_WINNT >= 0x501)
    int iGroupId;
    UINT cColumns; // tile view columns
    PUINT puColumns;
#endif
} LVITEM64A, *LPLVITEM64A;

你可能感兴趣的:(技术小白)