Visual C#彈出窗口殺手 (窗口顯示隱藏)

彈出窗口殺手是一個可以自動關閉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)
{
// 用最小化來代替關閉操作d
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);
}


.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章