如何隱藏運(yùn)行 winform 程序?
群里有個(gè)同學(xué)問了問題 如何隱藏運(yùn)行 winform 程序?,提起了我的興趣,玩玩唄?那就玩玩吧!
第一版
將一個(gè) winform 程序隱藏執(zhí)行,隱藏執(zhí)行的方式有很多種,第一個(gè) demo 就用最簡單的方式,實(shí)現(xiàn)隱藏執(zhí)行。
demo 執(zhí)行時(shí),不會顯示任何窗體,但是過10秒,會彈出對話框證明程序在運(yùn)行。
按照常規(guī)思路,在窗體初始化完成之后,調(diào)整窗體參數(shù)。
public?partial?class?Form1?:?Form
{
????public?Form1()
????{
????????InitializeComponent();
????????//不要顯示在任務(wù)欄
????????this.ShowInTaskbar?=?false;
????????//隱藏窗體
????????this.Visible?=?false;
????????//窗體寬度調(diào)整為0
????????this.Width?=?0;
????????//窗體高度調(diào)整為0
????????this.Height?=?0;
????????//窗體最左邊設(shè)置成-10000,保證在屏幕外邊
????????this.Left?=?-10000;
????????//窗體最頂部設(shè)置成-10000,保證在屏幕外邊
????????this.Top?=?-10000;
????}
}
在 Form1_Load方法里新啟動(dòng)一個(gè)線程,彈出對話框試試。
private?void?Form1_Load(object?sender,?EventArgs?e)
{
????new?Thread(new?ThreadStart(()?=>
????{
????????Thread.Sleep(10?*?1000);
????????MessageBox.Show("我在后臺執(zhí)行喲...");
????})).Start();
}
運(yùn)行起來發(fā)現(xiàn)還是有顯示,而且左邊和頂邊的位置沒有設(shè)置成功。如圖:

還有一個(gè) opacity,窗體透明度的屬性,設(shè)置成0。如下:
this.Opacity?=?0;
現(xiàn)在就好了,看不見窗體,達(dá)到了隱藏的目的,簡單粗暴,但是還湊合實(shí)用。
不足之處:窗體雖然是隱藏了,但只是調(diào)整了透明度(心里有點(diǎn)不爽,明明它是存在的,肉眼看不見而已)。
第二版
經(jīng)過第一個(gè) demo,我們簡單的實(shí)現(xiàn)了一個(gè)隱藏運(yùn)行的應(yīng)用程序,那么還有什么方式能隱藏執(zhí)行呢?
細(xì)心的同學(xué)發(fā)現(xiàn),這里在 Program.cs 文件 Main 方法中運(yùn)行了一個(gè) new Form1(),那么有什么辦法能不執(zhí)行這一句,應(yīng)用程序還能運(yùn)行呢?
我們把這一句注釋掉,看到 Application 類提供了一個(gè) Run 方法,不帶任何參數(shù)。我們試著刪掉沒用的 Form1 這個(gè)窗體,把代碼改成下面這樣執(zhí)行一下試試。
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new?Form1());
Application.Run();
prefect!程序照常可以運(yùn)行,任務(wù)管理器中可以看到 HiddenApp2.exe 這個(gè)進(jìn)程,也不用費(fèi)心隱藏窗體,何樂不為?
PS: 某些想法不良的同學(xué),可能想到了隱藏起來干點(diǎn)壞事,記住:法網(wǎng)恢恢、疏而不漏!
再來改造一下,讓他實(shí)現(xiàn)上面的功能,10秒后彈出一個(gè)對話框,證明程序確實(shí)在運(yùn)行。
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//Application.Run(new?Form1());
new?Thread(new?ThreadStart(()?=>
{
????Thread.Sleep(10?*?1000);
????MessageBox.Show("我在后臺執(zhí)行喲...");
})).Start();
Application.Run();
代碼很簡單,就是啟動(dòng)一個(gè)線程延遲10秒后彈窗,有的同學(xué)可能要問了,為啥 new Thread 不放在 Application.Run() 方法之后?因?yàn)?Application.Run() 會使應(yīng)用程序主進(jìn)程阻塞執(zhí)行,所以后面的代碼不會執(zhí)行。
擴(kuò)展
這一節(jié)里,我們使用第二步里使用的方法來干一點(diǎn)壞事(PS:我喜歡),做一個(gè) 剪切板尾巴 。
最終效果:他會在你復(fù)制的文本后面綴上設(shè)置好的文字,然后放進(jìn)剪切板。
迅雷的監(jiān)視剪切板,就是監(jiān)視了剪切板中是否有 Html 格式的文本,從中間解析 URL,實(shí)現(xiàn)下載。
winform 使用 Clipboard 這個(gè)密封類實(shí)現(xiàn)剪切板的一些基本用法,來看下定義:
namespace?System.Windows.Forms
{
????public?sealed?class?Clipboard
????{
????????public?static?void?Clear();
????????public?static?bool?ContainsAudio();
????????public?static?bool?ContainsData(string?format);
????????public?static?bool?ContainsFileDropList();
????????public?static?bool?ContainsImage();
????????public?static?bool?ContainsText(TextDataFormat?format);
????????public?static?bool?ContainsText();
????????public?static?Stream?GetAudioStream();
????????public?static?object?GetData(string?format);
????????public?static?IDataObject?GetDataObject();
????????public?static?StringCollection?GetFileDropList();
????????public?static?Image?GetImage();
????????public?static?string?GetText();
????????public?static?string?GetText(TextDataFormat?format);
????????public?static?void?SetAudio(Stream?audioStream);
????????public?static?void?SetAudio(byte[]?audioBytes);
????????public?static?void?SetData(string?format,?object?data);
????????public?static?void?SetDataObject(object?data);
????????public?static?void?SetDataObject(object?data,?bool?copy,?int?retryTimes,?int?retryDelay);
????????public?static?void?SetDataObject(object?data,?bool?copy);
????????public?static?void?SetFileDropList(StringCollection?filePaths);
????????public?static?void?SetImage(Image?image);
????????public?static?void?SetText(string?text);
????????public?static?void?SetText(string?text,?TextDataFormat?format);
????}
}
這一節(jié)主要是使用 public static string GetText(); 這個(gè)方法,來盜取用戶剪切的內(nèi)容,并在其后邊追加一個(gè)尾巴來惡搞一下。
原理:使用后臺線程,定時(shí)的把剪切板內(nèi)容復(fù)制下來,然后追加一些文字,再寫回剪切板。廢話不多說,直接上核心代碼:
var?text?=?Clipboard.GetText();
//不要問我為啥不用?String.IsNullOrEmpty(),因?yàn)槲矣玫?.Net?Framework?3.5
if?(text?!=?null?&&?text.Length?>?0)
{
????if?(!text.EndsWith(TAIL))
????{
????????Clipboard.SetText(text?+?TAIL);
????????Debug.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd?HH:mm:ss")}]?successful?catch?text【{text}】changed?to【{Clipboard.GetText()}】");
????}
}
代碼很短,但是很惡搞。
有趣的問題,看下面的代碼:
private?static?void?MemoryBomb()
{
????Clipboard.SetDataObject(new?MemoryStream(new?byte[1024000000?*?2L]));
????var?data?=?Clipboard.GetDataObject()?.GetData(typeof(MemoryStream));
????var?thread?=?new?Thread(new?ThreadStart(()?=>
????{
????????Thread.Sleep(3000);
????????//1
????????data?=?null;
????????GC.Collect();
????????Clipboard.SetDataObject(new?MemoryStream(new?byte[0]));
????????data?=?Clipboard.GetDataObject()?.GetData(typeof(MemoryStream));
????????//2
????????data?=?null;
????????GC.Collect();
????}));
????thread.SetApartmentState(ApartmentState.STA);
????thread.Start();
}
看到剪切板 Clipboard.SetDataObject 方法可以接受一個(gè) object 參數(shù),我好奇的弄了一個(gè)很大的 byte[] 放了進(jìn)去,結(jié)果發(fā)現(xiàn)在 GetData() 方法調(diào)用后內(nèi)存劇增(完全算得上內(nèi)存炸彈),大小是2倍的 byte[] 大小字節(jié),我又重啟一個(gè)線程來,再次調(diào)用 SetDataObject() 方法設(shè)置剪切板內(nèi)容,發(fā)現(xiàn)內(nèi)存不會釋放。
加了第一個(gè) GC.Collect(); 之后,內(nèi)存會降一半,我猜想 data 變量被釋放,但是剪切板內(nèi)容沒釋放,2倍大小的字節(jié)應(yīng)該是 data 變量占用 2G,剪切板占用 2G。如圖:


緊接著執(zhí)行完畢這段代碼之后:
data?=?null;
GC.Collect();
Clipboard.SetDataObject(new?MemoryStream(new?byte[0]));
data?=?Clipboard.GetDataObject()?.GetData(typeof(MemoryStream));
有趣的是占用的2G內(nèi)存,不會釋放。為什么上面的 GetData 會使內(nèi)存劇增,而這一句不會使內(nèi)存變小呢?如圖:

緊接著執(zhí)行第二個(gè) GC.Collect(); 執(zhí)行之后,內(nèi)存會被回收,但是還是比最初的大了一些,沒有完全釋放。如圖:

奇思妙想:可以用
Clipboard申請一些內(nèi)存,然后在內(nèi)存中執(zhí)行一些代碼,會不會對系統(tǒng)造成威脅?有能力的大牛可以嘗試一下。
完整代碼:
using?System;
using?System.Collections.Generic;
using?System.Diagnostics;
using?System.IO;
using?System.Linq;
using?System.Threading;
using?System.Windows.Forms;
namespace?HiddenApp3
{
????static?class?Program
????{
????????///?
????????///?應(yīng)用程序的主入口點(diǎn)。
????????///?
????????[STAThread]
????????static?void?Main()
????????{
????????????Application.EnableVisualStyles();
????????????Application.SetCompatibleTextRenderingDefault(false);
????????????//MemoryBomb();
????????????RunClipboardTail();
????????????Application.Run();
????????}
????????private?static?void?MemoryBomb()
????????{
????????????Clipboard.SetDataObject(new?MemoryStream(new?byte[1024000000?*?2L]));
????????????var?data?=?Clipboard.GetDataObject()?.GetData(typeof(MemoryStream));
????????????var?thread?=?new?Thread(new?ThreadStart(()?=>
????????????{
????????????????Thread.Sleep(3000);
????????????????//1
????????????????data?=?null;
????????????????GC.Collect();
????????????????Clipboard.SetDataObject(new?MemoryStream(new?byte[1]));
????????????????data?=?Clipboard.GetDataObject()?.GetData(typeof(MemoryStream));
????????????????//2
????????????????data?=?null;
????????????????GC.Collect();
????????????}));
????????????thread.SetApartmentState(ApartmentState.STA);
????????????thread.Start();
????????}
????????private?const?string?TAIL?=?"你需要關(guān)注《開發(fā)者精選資訊》公眾號";
????????private?static?void?RunClipboardTail()
????????{
????????????var?thread?=?new?Thread(new?ThreadStart(()?=>
????????????{
????????????????while?(true)
????????????????{
????????????????????try
????????????????????{
????????????????????????var?text?=?Clipboard.GetText();
????????????????????????if?(text?!=?null?&&?text.Length?>?0)
????????????????????????{
????????????????????????????if?(!text.EndsWith(TAIL))
????????????????????????????{
????????????????????????????????Clipboard.SetText(text?+?TAIL);
????????????????????????????????Debug.WriteLine($"[{DateTime.Now.ToString("yyyy-MM-dd?HH:mm:ss")}]?successful?catch?text【{text}】changed?to【{Clipboard.GetText()}】");
????????????????????????????}
????????????????????????}
????????????????????}
????????????????????catch?{?}
????????????????????Thread.Sleep(10000);
????????????????}
????????????}))
????????????{
????????????????IsBackground?=?true
????????????};
????????????thread.SetApartmentState(ApartmentState.STA);
????????????thread.Start();
????????}
????}
}
github:
https://github.com/mrhuo/HiddenAppDemo
推薦閱讀:
開發(fā)者精選資訊
?每日為您推薦開發(fā)精選資訊
長按二維碼
關(guān)注 「開發(fā)者精選資訊」 公眾號
好文章,我在看 ???
