6.案例 - 恶搞程序

这一篇再加一个函数 然后把前面说到的SetWindowPos和GetWindowRect函数做一个练习 写一个恶搞程序出来玩玩 那是一个什么样子的程序呢?

QQ的抖动窗口 应该都见过吧?这一篇就来做一个这个东西 不过不是自己的窗体抖动 而是程序运行的时候 用户点击哪个窗口 哪个窗口就抖动 然后一直抖个不停、、抖动的原理应该都知道吧?就是窗口的位置在原来位置的基础上 左上右下 的转一圈 所以需要用到SetWindowPos 不过在设置窗口的位置之前你总得知道窗口原来的位置吧?不能随便的一个坐标让一个窗口转一圈啊 所以需要用到GetWindowRect去获取目标窗口的位置 然后在这个位置的基础上转一圈

现在的问题就是目标窗口到底是哪个?刚才说了 用户点哪个窗口哪个窗口就是目标窗口?那么怎么知道用户点了那个窗口?而通常情况下 用户点击哪个窗口 被点击的窗口就会变成当前桌面的前台窗口(也就是此时如果你按键键盘 会来接收按键信息的那个窗口) 那么要怎么样才能知道是那个窗口?用GetForegroundWindow函数就可以了:

数功能:
    获取一个前台窗口的句柄(窗口与用户当前的工作)。
    该系统分配给其他线程比它的前台窗口的线程创建一个稍微更高的优先级
函数原型:
    HWND GetForegroundWindow(void);
参数:无 
返回值:
    返回值是一个前台窗口的句柄。在某些情况下,如一个窗口失去激活时,前台窗口可以是NULL。
其它资料
头文件:winuser.h
库文件:user32.lib;
    Unicode:在 Windows NT上实现为 Unicode和 ANSI两种版本。

函数没有参数 调用函数返回一个窗口句柄 这个窗口就是当前桌面的前台窗口有了这三个函数 就可以干事情了、、然后来看看怎么设计

放一个按钮到窗体上 然后点击按钮的时候 开始执行程序 然后程序的执行过程是【获取前台窗体 - 然后转一圈 - 继续获取窗体 - 继续转...】然后程序就一直这样、、为了人性化 还是定个时吧  程序运行30秒后就停下来 不然中招的人要抓狂的

首先把要用到的函数声明出来 (我个人的习惯是 喜欢单独来一个类放这些东西):

internal class Win32
{
    [DllImport("user32.dll")]
    public static extern IntPtr GetForegroundWindow();
    [DllImport("user32.dll")]
    public static extern bool GetWindowRect(IntPtr hWnd, ref RECT rect);
    [DllImport("user32.dll")]
    public static extern bool SetWindowPos(
        IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint uFlags);

    public const uint SWP_NOSIZE = 0x01;
    public const uint SWP_NOZORDER = 0x04;

    public struct RECT
    {
        public int Left;
        public int Top;
        public int Right;
        public int Bottom;
    }
}
这三个函数有了 剩下的就是自己捣鼓的过程了 先来说所抖动的过程 刚才已经说了就是转一圈来着、、那么把这个过程单独写一个方法来着 方法接收一个句柄参数 然后将该句柄的窗口转一圈:
private void ShakeWindow(IntPtr hWnd) {//执行一次差不多80多毫秒
    Win32.RECT rect = new Win32.RECT();
    if (!Win32.GetWindowRect(hWnd, ref rect)) return;
    Point[] pts = new Point[]{//要转圈的位置
        new Point( rect.Left - 5, rect.Top),        //左
        new Point( rect.Left - 5, rect.Top - 5),    //左上
        new Point( rect.Left, rect.Top -5),         //上
        new Point( rect.Left + 5, rect.Top - 5),    //右上
        new Point( rect.Left + 5, rect.Top),        //右
        new Point( rect.Left + 5, rect.Top + 5),    //右下
        new Point( rect.Left, rect.Top + 5),        //下
        new Point( rect.Left - 5, rect.Top + 5),    //左下
    };
    for (int i = 0, len = pts.Length - 1; i < len; i++) {
        Win32.SetWindowPos(
            hWnd, IntPtr.Zero, pts[i].X, pts[i].Y, 0, 0,
            Win32.SWP_NOSIZE | Win32.SWP_NOZORDER);
        System.Threading.Thread.Sleep(10);//转一下停顿一下
    }
    Win32.SetWindowPos(//要做一个有素质的流氓 最后把位置搞回去
        hWnd, IntPtr.Zero, rect.Left, rect.Top, 0, 0,
        Win32.SWP_NOSIZE | Win32.SWP_NOZORDER);
}
然后就是不停的调用这个方法 然后传个句柄进来就是了 而这个句柄就是通过GetForegroundWindow函数获取的 这里方便点 用一个Timer来不停的获取句柄 然后抖动 但是只让Timer运行30秒就是了 不然一直运行会哭的、、全部代码如下:
public partial class Form2 : Form
{
    public Form2() {
        InitializeComponent();
        timer1.Interval = 100;//不要太小还要考虑ShakeWindow的执行时间
    }

    private int m_nKeep;
    private DateTime m_dtStart;

    private void button1_Click(object sender, EventArgs e) {
        m_nKeep = 1000 * 30;        //保持30秒就是了
        m_dtStart = DateTime.Now;   //开始计时
        timer1.Enabled = true;
        button1.Enabled = false;
    }

    private void timer1_Tick(object sender, EventArgs e) {
        if (DateTime.Now.Subtract(m_dtStart).TotalMilliseconds > m_nKeep) {
            timer1.Enabled = false;
            button1.Enabled = true;
            return;
        }
        IntPtr hWnd = Win32.GetForegroundWindow();
        ShakeWindow(hWnd);//获取句柄 然后转圈
    }

    private void ShakeWindow(IntPtr hWnd) {//执行一次差不多80多毫秒
        Win32.RECT rect = new Win32.RECT();
        if (!Win32.GetWindowRect(hWnd, ref rect)) return;
        Point[] pts = new Point[]{
            new Point( rect.Left - 5, rect.Top),        //左
            new Point( rect.Left - 5, rect.Top - 5),    //左上
            new Point( rect.Left, rect.Top -5),         //上
            new Point( rect.Left + 5, rect.Top - 5),    //右上
            new Point( rect.Left + 5, rect.Top),        //右
            new Point( rect.Left + 5, rect.Top + 5),    //右下
            new Point( rect.Left, rect.Top + 5),        //下
            new Point( rect.Left - 5, rect.Top + 5),    //左下
        };
        for (int i = 0, len = pts.Length - 1; i < len; i++) {
            Win32.SetWindowPos(
                hWnd, IntPtr.Zero, pts[i].X, pts[i].Y, 0, 0,
                Win32.SWP_NOSIZE | Win32.SWP_NOZORDER);
            System.Threading.Thread.Sleep(10);//转一下停顿一下
        }
        Win32.SetWindowPos(//要做一个有素质的流氓 最后把位置搞回去
            hWnd, IntPtr.Zero, rect.Left, rect.Top, 0, 0,
            Win32.SWP_NOSIZE | Win32.SWP_NOZORDER);
    }
}
程序执行的时候 估计你会觉得有点卡 因为在不停的执行ShakeWindow方法 而这个方法执行一次差不多要阻塞80多毫秒 然后休息差不多20毫秒 又会被Timer调用 不过没关系 反正你也不怎么感觉得到的 因为你要去拖动你的窗口的时候你的窗口在不停的转圈、、

然后其他就没啥可说的了、、、


添加时间:2014-05-12 18:51:22 编辑时间:2014-05-12 19:38:52 阅读:1850 
C#Windows编程 C#Win32
还没有人留言 要不你来抢一个沙发?
  • 编写评论

      我觉得区分大小写是一个码农的基本素质
[访问统计] 今天:73 总数:262794 提示:未成年人 请在大人陪同下浏览本站内容 还有:世界上最帅的码农 -> 石头 RSS:http://st233.com/rss Powered by -> Crystal_lz