2024年1月21日发(作者:)

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

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

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

系统托盘

程序切换

计时控件

查找窗口

系统热键

生成一个系统托盘程序

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

在C# windows Form程序中添加托盘

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

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

Taskbar = false;

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

程序切换

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

public void HideApp()

{

State = zed;

Hide();

}

public void ShowApp()

{

Show();

State = ;

}

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

protected override void OnClosing(CancelEventArgs e)

{

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

= true;

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

State = zed;

Hide();

}

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

private void menu_App_Exit(object sender, rgs e)

{

sterHotKey(Handle, 100);

//隐藏托盘

e = false;

();

}

添加右键菜单

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

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

private void menu_App_BeforePopup(object sender, rgs e)

{

if ( State == zed )

{

App_d = true;

App_d = false;

}

else

{

App_d = false;

App_d = true;

}

}

计时工具

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

m_Timer = new (); // explicit namespace (Timer also in

ing)

m_d += new ElapsedEventHandler(OnTimerKillPopup);

m_al = m_nInterval; // for instance 3000 milliseconds

m_d = true; // start timer

protected void OnTimerKillPopup(Object source, ElapsedEventArgs e)

{

m_d = false; // pause the timer

FindPopupToKill();

m_d = true;

}

本地win32窗体查找

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

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

一个可行的办法使用s列举出所有的运行的进程,然后sThreadCollection 来得到他们的.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 = cessesByName("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 s)

{

int threadId = ;

readProc callbackProc =

new readProc(MyEnumThreadWindowsProc);

readWindows(threadId, callbackProc, /*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

BUFFER sLimitedLengthWindowTitle;

dowText(hwnd, out sLimitedLengthWindowTitle, 256);

String sWindowTitle = ;

if (==0) return true;

// find this caption in the list of banned captions

foreach (ListViewItem item in )

{

if ( With() )

ssage(hwnd, _SYSCOMMAND,

_CLOSE,

); // try soft kill

}

return true;

}

public class NativeWIN32

{

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

[DllImport("", CharSet=)]

public static extern bool EnumThreadWindows(int threadId, EnumThreadProc pfnEnum,

IntPtr lParam);

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

[StructLayout(tial, CharSet=)]

public struct STRINGBUFFER

{

[MarshalAs(Str, SizeConst=256)]

public string szText;

}

[DllImport("", CharSet=)]

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

nMaxCount);

[DllImport("", CharSet=)]

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 hNext = ;

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

do

{

hNext = ndowEx(hParent,hNext,sClassNameFilter,);

// we've got a hwnd to play with

if ( !() )

{

// get window caption

BUFFER sLimitedLengthWindowTitle;

dowText(hNext, out sLimitedLengthWindowTitle, 256);

String sWindowTitle = ;

if (>0)

{

// find this caption in the list of banned captions

foreach (ListViewItem item in )

{

if ( With() )

ssage(hNext, _SYSCOMMAND,

_CLOSE,

); // try soft kill

}

}

}

}

while (!());

}

public class NativeWIN32

{

[DllImport("", CharSet=)]

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

ifiers modifiers = ;

if (m_ctrlhotkey)

modifiers |= l;

if (m_shifthotkey)

modifiers |= ;

if (m_althotkey)

modifiers |= ;

if (m_winhotkey)

modifiers |= s;

erHotKey(Handle, 100, modifiers,}

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

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

-- code snippet by James J Thompson --

在Form的load 中 : Ctrl+Shift+J

bool success = RegisterHotKey(Handle,

100,

l | ,

Keys.J);

在 form的closing中 :

UnregisterHotKey(Handle, 100);

如何处理热键 :

protected override void WndProc( ref Message m )

{

m_hotkey); //Keys.J);

const int WM_HOTKEY = 0x0312;

switch()

{

case WM_HOTKEY:

("Hotkey pressed");

ProcessHotkey();

break;

}

c(ref m );

}

public class NativeWIN32

{

[DllImport("", 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("", 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 = egroundWindow();

if (!())

{

BUFFER sWindowTitle;

dowText(hwnd, out sWindowTitle, 256);

if (>0)

AddWindowTitle( ); // add to the ListView (Form)

}

}