您的位置:首页 > 其它

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

2017-06-22 17:13 344 查看
前言: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;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: