• 弹出广告杀手


    Visual C#弹出窗口杀手

    2002-11-19· ···ASPCool.com

    1 2  下一页

      弹出窗口杀手是一个可以自动关闭IE弹出窗口的程序,它工作在系统的托盘中,按照一定的间隔来检测IE窗口,然后关闭弹出窗体。最后,还提供了用热键来杀掉弹出窗口的功能。

      虽然已经有类似的用C++写的程序,但是本文讲述的是用C#来实现这些功能,并且本文所讲的方案在查找窗口上的方法要比更快一些。

      这是一个崭新的话题,在Internet上我们还可以看到许多类似的程序。但是我也还是要借这个机会来讲述一些下面的技术在C#中如何实现:

      系统托盘

      程序切换

      计时控件

      查找窗口

      系统热键

      生成一个系统托盘程序

      首先,产生一个新的C# Windows Form程序, 将NotifyIcon控件从工具箱中拖到窗体中,如下图所示:

      C# windows Form程序中添加托盘

      为了保证系统托盘的图标和应用程序的图标一致,我们用一个共同的图标文件a.ico来设置系统托盘的图标和应用程序的图标。

      为了使程序不显示在工具栏上,我们可以设置窗体的visible属性为false. 这个可以在窗体属性窗口中直接实现。

      this.ShowInTaskbar = false;

      到目前为止,系统托盘已基本好了,但是我们还没有设置右键菜单,也没有使程序显示和隐藏的功能。

      程序切换

      首先,程序的主窗体可以根据不同的状态来选择显示或者是隐藏,除此之外,我们可以用WindowState设置窗体的状态:

    public void HideApp()

    {

    this.WindowState = FormWindowState.Minimized;

    Hide();

    }

    public void ShowApp()

    {

    Show();

    this.WindowState = FormWindowState.Normal;

    }

      一个非常有趣的功能是让用户关闭窗体的时候程序并不是退出,为了实现这个功能,我们必须要重写窗体的OnClosing事件。

    protected override void OnClosing(CancelEventArgs e)

    {

    // 用最小化来代替关闭操作

    e.Cancel = true;

    // 最小化,并且隐藏窗体

    this.WindowState = FormWindowState.Minimized;

    Hide();

    }

    当然,我们必须要提供一个必须的退出方法.这个可以在托盘的右键菜单的exit中实现,

    private void menu_App_Exit(object sender, System.EventArgs e)

    {

    NativeWIN32.UnregisterHotKey(Handle, 100);

    //隐藏托盘

    notifyIcon1.Visible = false;

    Application.Exit();

    }

      添加右键菜单

      添加一个右键菜单和添加托盘基本一样,从工具箱中添加context menu就可以.右键菜单在你鼠标右键按下的时候是会自动弹出的。

      当设置好右键菜单以后,我们必要要根据不同的情况来启用或停用右键菜单,这个可以通过在菜单的BeforePopup设置。Enabled属性来实现。

    private void menu_App_BeforePopup(object sender, System.EventArgs e)

    {

    if ( this.WindowState == FormWindowState.Minimized )

    {

    App_Show.Enabled = true;

    App_Hide.Enabled = false;

    }

    else

    {

    App_Show.Enabled = false;

    App_Hide.Enabled = true;

    }

    }

     计时工具

      .Net Framework的 Timer能和系统的Win32 timer实现一样的功能。我们要做的就是设置一个timer,然后合理的设置属性。

    m_Timer = new System.Timers.Timer(); // explicit namespace (Timer also in System.Threading)

    m_Timer.Elapsed += new ElapsedEventHandler(OnTimerKillPopup);

    m_Timer.Interval = m_nInterval; // for instance 3000 milliseconds

    m_Timer.Enabled = true; // start timer

    protected void OnTimerKillPopup(Object source, ElapsedEventArgs e)

    {

    m_Timer.Enabled = false; // pause the timer

    FindPopupToKill();

    m_Timer.Enabled = true;

    }

      本地win32窗体查找

      本程序的实现原理是这样,先检查所有的IE窗口标题,然后于已经有的列表来比较,如果有相同的,我们就关闭这个窗口。

      按照上面的方法,我们每n妙使用KillPopup()来检查。比较遗憾的是我们无法使用安全代码来完成所有的工作。我们可以使用 System.Diagnostics.Proces来检查所有的IE进程,然后得到主窗体。但是每一个IE进程可以打开好几个窗口,虽然每一个窗体都于一个进程相关,但是还没有办法来使每一个窗体于进程对应起来。

      一个可行的办法使用System.Diagnostics.Process列举出所有的运行的进程,然后System.Diagnostics.ProcessThreadCollection 来得到他们的.Threads属性,为了得到thread Id,我们使用Win32 API EnumThreadWindows(DWORD threadId,WNDENUMPROC lpfn,LPARAM lParam) 来实现,这是一个回调(call back)函数,他可以列举出于进程相关的窗体。当我们得到了窗体的句柄以后,我们可以使用另一个API函数 GetWindowText(HWND hwnd,/*out*/LPTSTR lpString,int nMaxCount)来得到窗体的标题,然后根据已经有的窗体,调用API函数SendMessage(HWND hWnd,int msg,int wParam,int lParam)来关闭窗口。下面使演示代码

    Process[] myProcesses = Process.GetProcessesByName("IEXPLORE");

    foreach(Process myProcess in myProcesses)

    {

    FindPopupToKill(myProcess);

    }

    protected void FindPopupToKill(Process p)

    {

    // traverse all threads and enum all windows attached to the thread

    foreach (ProcessThread t in p.Threads)

    {

    int threadId = t.Id;

    NativeWIN32.EnumThreadProc callbackProc =

    new NativeWIN32.EnumThreadProc(MyEnumThreadWindowsProc);

    NativeWIN32.EnumThreadWindows(threadId, callbackProc, IntPtr.Zero /*lParam*/);

    }

    }

    // callback used to enumerate Windows attached to one of the threads

    bool MyEnumThreadWindowsProc(IntPtr hwnd, IntPtr lParam)

    {

    public const int WM_SYSCOMMAND = 0x0112;

    public const int SC_CLOSE = 0xF060;

    // get window caption

    NativeWIN32.STRINGBUFFER sLimitedLengthWindowTitle;

    NativeWIN32.GetWindowText(hwnd, out sLimitedLengthWindowTitle, 256);

    String sWindowTitle = sLimitedLengthWindowTitle.szText;

    if (sWindowTitle.Length==0) return true;

    // find this caption in the list of banned captions

    foreach (ListViewItem item in listView1.Items)

    {

    if ( sWindowTitle.StartsWith(item.Text) )

    NativeWIN32.SendMessage(hwnd, NativeWIN32.WM_SYSCOMMAND,

    NativeWIN32.SC_CLOSE,

    IntPtr.Zero); // try soft kill

    }

    return true;

    }

    public class NativeWIN32

    {

    public delegate bool EnumThreadProc(IntPtr hwnd, IntPtr lParam);

    [DllImport("user32.dll", CharSet=CharSet.Auto)]

    public static extern bool EnumThreadWindows(int threadId, EnumThreadProc pfnEnum, IntPtr lParam);

    // used for an output LPCTSTR parameter on a method call

    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]

    public struct STRINGBUFFER

    {

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)]

    public string szText;

    }

    [DllImport("user32.dll", CharSet=CharSet.Auto)]

    public static extern int GetWindowText(IntPtr hWnd, out STRINGBUFFER ClassName, int nMaxCount);

    [DllImport("user32.dll", CharSet=CharSet.Auto)]

    public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, int lParam);

    }

      上面的方法在性能上是不错的,因为他过滤了其他非IE的窗口.但是我们可以用一个更简单的方法来实现,就是调用API FindWindowEx(HWND hWndParent, HWND hWndNext, /*in*/LPCTSTR szClassName, /*in*/LPCTSTR szWindowTitle)方法.比较有用的是这句,我们可以使用registered window class name来找到IE窗口(IEFrame是所有打开的IE的标识).

    protected void FindPopupToKill()

    {

    IntPtr hParent = IntPtr.Zero;

    IntPtr hNext = IntPtr.Zero;

    String sClassNameFilter = "IEFrame"; // 所有IE窗口的类

    do

    {

    hNext = NativeWIN32.FindWindowEx(hParent,hNext,sClassNameFilter,IntPtr.Zero);

    // we've got a hwnd to play with

    if ( !hNext.Equals(IntPtr.Zero) )

    {

    // get window caption

    NativeWIN32.STRINGBUFFER sLimitedLengthWindowTitle;

    NativeWIN32.GetWindowText(hNext, out sLimitedLengthWindowTitle, 256);

    String sWindowTitle = sLimitedLengthWindowTitle.szText;

    if (sWindowTitle.Length>0)

    {

    // find this caption in the list of banned captions

    foreach (ListViewItem item in listView1.Items)

    {

    if ( sWindowTitle.StartsWith(item.Text) )

    NativeWIN32.SendMessage(hNext, NativeWIN32.WM_SYSCOMMAND,

    NativeWIN32.SC_CLOSE,

    IntPtr.Zero); // try soft kill

    }

    }

    }

    }

    while (!hNext.Equals(IntPtr.Zero));

    }

    public class NativeWIN32

    {

    [DllImport("user32.dll", CharSet=CharSet.Auto)]

    public static extern IntPtr FindWindowEx(IntPtr parent /*HWND*/,

    IntPtr next /*HWND*/,

    string sClassName,

    IntPtr sWindowTitle);

    }

       代码下载:

      演示程序:

        注册系统热键

      系统热键用在像弹出窗口杀手这种应用程序非常有用, Ctrl+Shift+J是缺省热键。

      说道实现,我们继续用RegisterHotkey(HWND hWnd, int id, UINT fsModifiers, UINT vkey)。完成,代码如下:

    public void SetHotKey(Keys c, bool bCtrl, bool bShift, bool bAlt, bool bWindows)

    {

    m_hotkey = c;

    m_ctrlhotkey = bCtrl;

    m_shifthotkey = bShift;

    m_althotkey = bAlt;

    m_winhotkey = bWindows;

    // update hotkey

    NativeWIN32.KeyModifiers modifiers = NativeWIN32.KeyModifiers.None;

    if (m_ctrlhotkey)

    modifiers |= NativeWIN32.KeyModifiers.Control;

    if (m_shifthotkey)

    modifiers |= NativeWIN32.KeyModifiers.Shift;

    if (m_althotkey)

    modifiers |= NativeWIN32.KeyModifiers.Alt;

    if (m_winhotkey)

    modifiers |= NativeWIN32.KeyModifiers.Windows;

    NativeWIN32.RegisterHotKey(Handle, 100, modifiers, m_hotkey); //Keys.J);

    }

    一般的,注册热键要一下几步

    /* ------- using HOTKEYs in a C# application -------

    -- code snippet by James J Thompson --

    在Form的load 中 : Ctrl+Shift+J

    bool success = RegisterHotKey(Handle,

    100,

    KeyModifiers.Control | KeyModifiers.Shift,

    Keys.J);

      在 form的closing中 :

      UnregisterHotKey(Handle, 100);

      如何处理热键 :

    protected override void WndProc( ref Message m )

    {

    const int WM_HOTKEY = 0x0312;

    switch(m.Msg)

    {

    case WM_HOTKEY:

    MessageBox.Show("Hotkey pressed");

    ProcessHotkey();

    break;

    }

    base.WndProc(ref m );

    }

    public class NativeWIN32

    {

    [DllImport("user32.dll", SetLastError=true)]

    public static extern bool RegisterHotKey( IntPtr hWnd, // handle to window

    int id, // hot key identifier

    KeyModifiers fsModifiers, // key-modifier options

    Keys vk // virtual-key code

    );

    [DllImport("user32.dll", SetLastError=true)]

    public static extern bool UnregisterHotKey( IntPtr hWnd, // handle to window

    int id // hot key identifier

    );

    [Flags()]

    public enum KeyModifiers

    {

    None = 0,

    Alt = 1,

    Control = 2,

    Shift = 4,

    Windows = 8

    }

    }

    ------- using HOTKEYs in a C# application ------- */

      当我们按下热键以后,流程是这样:首先用HWND GetForegroundWindow()来得到窗体,然后要抓出窗体的标题, GetWindowText(HWND hwnd, /*out*/LPTSTR lpString, int nMaxCount). 具体如下:

    protected void ProcessHotkey()

    {

    IntPtr hwnd = NativeWIN32.GetForegroundWindow();

    if (!hwnd.Equals(IntPtr.Zero))

    {

    NativeWIN32.STRINGBUFFER sWindowTitle;

    NativeWIN32.GetWindowText(hwnd, out sWindowTitle, 256);

    if (sWindowTitle.szText.Length>0)

    AddWindowTitle( sWindowTitle.szText ); // add to the ListView (Form)

    }

    }

  • 相关阅读:
    Dede CMS如何在文章中增加“附件下载”操作说明
    仿站模仿的三个网站
    PHP面相对象中的重载与重写
    面向对象思想
    最常用的正则表达式
    PHP第二阶段学习 一、php的基本语法
    PHP isset()与empty()的使用区别详解
    mysql索引总结----mysql 索引类型以及创建
    MySQL实现当前数据表的所有时间都增加或减少指定的时间间隔
    T-SQL语句以及几个数据库引擎
  • 原文地址:https://www.cnblogs.com/jhabb/p/1881461.html
Copyright © 2020-2023  润新知