用代码移动桌面图标(贪吃蛇)

时间:2024-04-17 16:39:32

效果图

实例.gif

前言

记得上高二的时候,闲来无事,上b站搜电脑病毒的视频看(不要问我为什么会搜这个),看到一个很有意思的"病毒",其实也不算病毒,它会控制桌面图标形成一个人形,并跳舞,跳完之后电脑就蓝屏了.之后下定决心也要整一个,埋头研究了两个星期吧,写了一个贪吃蛇,此贪吃蛇非彼贪吃蛇,它当然是控制的桌面图标来玩啦,还写了个网络版的,通过手机去控制.

贪吃蛇效果

本文章只介绍如何移动图标,不介绍贪吃蛇实现(源码太多),可以评价私信要源码

实例.gif

实现思路

说到这,真的很后悔以前没第一个学c语言,反而学了vb,现在被其他语言搞得没有精力去学了,并没有说vb不好,它也很强大,只是它封装了很多,让很多人接触底层得知识更少了,比如窗体,归根到底,所有窗体都是用CreateWindow 函数来创建,但是学了vb,谁会傻到在用CreateWindow来创建窗口呢?

好了,说原理吧.
首先要了解什么是句柄,通俗得讲它就是一个整数,具体它标识窗口、位图、画笔等对象,并且是不变得整数,就像身份证一样,当人出生后,必定会有一个18位的身份证号,并且是不变得,通过它,可以知道某人得姓名,地址,年龄等信息,句柄也是如此.

上面所说的CreateWindow,当它成功创建一个窗口后,它的返回值就是一个句柄,你拿到这个句柄后,你就可以对它做你想做的事了,比如用SetWindowText 给它设置一个标题.

明白了句柄,现在就要拿到桌面的句柄,对它进行控制,用spy++可以分析一下它

image.png

这里有一点不一样,在windows7中,它的父窗口类名是Program Manage,但是在windows10中,它的类名是WorkerW,并且有多个WorkerW.下图是windows 7中

image.png

但是这不影响我们.从中可以看到,桌面就是一个ListView,我们只要拿到它的句柄,就可以对他进行控制.

获取桌面句柄

需要用到api:
FindWindow:根据窗口的类名和窗口名称匹配指定的窗口,并且返回这个窗口的句柄
FindWindowEx:根据所在的父窗口中查找类名和窗口名称匹配的窗口,并且返回这个窗口的句柄

查找桌面句柄如下.
注:在win7下可就不这么写了,

Private Function getDesktopHwnd() As Long
Dim hwndWorkerW As Long, hwndShelldll As Long, hwndDesktop As Long

Do While (hwndDesktop = 0)
    hwndWorkerW = FindWindowEx(0, hwndWorkerW, "WorkerW", vbNullString)
        If (hwndWorkerW <> 0) Then
            hwndShelldll = FindWindowEx(hwndWorkerW, 0, "SHELLDLL_DefView", vbNullString)
   
            hwndDesktop = FindWindowEx(hwndShelldll, 0, "SysListView32", vbNullString)
        End If
Loop
getDesktopHwnd = hwndDesktop
End Function

移动图标

知道了桌面的句柄,然后就是移动图标了
既然桌面就是一个ListView,那么只需要给ListView发送一个LVM_SETITEMPOSITION消息来设置item的位置.
如果你对windows机制不太了解的话,可能不明白为何要这样做,简单说一下,windows是根据消息来驱动程序运行的,例如,单击鼠标、改变窗口尺寸、按下键盘上的一个键都会使Windows发送一个消息给应用程序,应用程序会在一个叫窗口过程函数的地方处理消息,windows定义了大量的消息,列入:WM_CLOSE,对这个窗口发送WM_CLOSE,如果应用程序不做特殊处理的话,窗口就会关闭,

如果对ListView操作的话,就需要发送以LVM开头的消息,WM开头的是窗口消息,还有对列表框的消息LB_xxx

发送消息可以用SendMessage函数或PostMessage,区别在于使用PostMessage是立即返回,SendMessage需要等待应用程序处理完之后返回,在这里我们也不需要等待程序返回,所以用PostMessage.

看一下PostMeeage的定义

image.png
参数hwnd:消息接收的窗口句柄
参数msg:具体消息
参数wparam和lparam:其他特定于消息的信息。

在看一下LVM_SETITEMPOSITION消息的定义

image.png

也就是说,使用PostMeeage投递LVM_SETITEMPOSITION消息的时候,参数wparam是某个图标的索引,lparam是位置.
但是如何用一个整数标识一个坐标呢,在c中可以用MAKELPARAM来获取,vb中可没有这样的方法,那就自己写一个

Public Function MAKELPARAM(ByVal l As Integer, ByVal h As Integer) As Long
Dim ll As String
Dim lh As String
Dim r As String
ll = Format(Hex(l), "@@@@")
lh = Format(Hex(h), "@@@@")
Dim result As Long

result = CLng("&h" & Replace(lh & ll, " ", "0"))
 MAKELPARAM = result
 
End Function

全部代码

Private Const LVM_FIRST As Long = &H1000

Private Declare Function GetDesktopWindow Lib "user32.dll" () As Long

Private Const LVM_SETITEMPOSITION32 As Long = (LVM_FIRST + 49)
Private Declare Function PostMessage Lib "user32.dll" Alias "PostMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

Private Declare Function EnumWindows Lib "user32.dll" (ByVal lpEnumFunc As Long, ByVal lParam As Long) As Long

Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long

Private Const LVM_SETITEMPOSITION As Long = (LVM_FIRST + 15)

Private Type POINTAPI
    x As Long
    y As Long
End Type

Dim curPoint As POINTAPI

Dim listViewhwnd As Long

Public Function MAKELPARAM(ByVal l As Integer, ByVal h As Integer) As Long
Dim ll As String
Dim lh As String
Dim r As String
ll = Format(Hex(l), "@@@@")
lh = Format(Hex(h), "@@@@")
Dim result As Long

result = CLng("&h" & Replace(lh & ll, " ", "0"))
 MAKELPARAM = result
 
End Function


Private Function getDesktopHwnd() As Long
Dim hwndWorkerW As Long, hwndShelldll As Long, hwndDesktop As Long

Do While (hwndDesktop = 0)
    hwndWorkerW = FindWindowEx(0, hwndWorkerW, "WorkerW", vbNullString)
        If (hwndWorkerW <> 0) Then
            hwndShelldll = FindWindowEx(hwndWorkerW, 0, "SHELLDLL_DefView", vbNullString)
   
            hwndDesktop = FindWindowEx(hwndShelldll, 0, "SysListView32", vbNullString)
        End If
Loop
getDesktopHwnd = hwndDesktop
End Function
Private Sub Form_Load()
listViewhwnd = getDesktopHwnd()

End Sub

Private Sub Timer1_Timer()
curPoint.x = curPoint.x + 10

PostMessage listViewhwnd, LVM_SETITEMPOSITION, 10, MAKELPARAM(curPoint.x, 110)
End Sub

注:右击桌面--->查看---->自动排列图标 、将图标和网格对齐 需要取消勾选