如何隐藏运行 winform 程序?
群里有個同學問了問題 如何隱藏運行 winform 程序?,提起了我的興趣,玩玩唄?那就玩玩吧!
第一版
將一個 winform 程序隱藏執行,隱藏執行的方式有很多種,第一個 demo 就用最簡單的方式,實現隱藏執行。
demo 執行時,不會顯示任何窗體,但是過10秒,會彈出對話框證明程序在運行。
按照常規思路,在窗體初始化完成之后,調整窗體參數。
在 Form1_Load 方法里新啟動一個線程,彈出對話框試試。
運行起來發現還是有顯示,而且左邊和頂邊的位置沒有設置成功。如圖:
還有一個 opacity,窗體透明度的屬性,設置成0。如下:
現在就好了,看不見窗體,達到了隱藏的目的,簡單粗暴,但是還湊合實用。
不足之處:窗體雖然是隱藏了,但只是調整了透明度(心里有點不爽,明明它是存在的,肉眼看不見而已)。
第二版
經過第一個 demo,我們簡單的實現了一個隱藏運行的應用程序,那么還有什么方式能隱藏執行呢?
細心的同學發現,這里在 Program.cs 文件 Main 方法中運行了一個 new Form1(),那么有什么辦法能不執行這一句,應用程序還能運行呢?
我們把這一句注釋掉,看到 Application 類提供了一個 Run 方法,不帶任何參數。我們試著刪掉沒用的 Form1 這個窗體,把代碼改成下面這樣執行一下試試。
Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); //Application.Run(new?Form1()); Application.Run();prefect!程序照常可以運行,任務管理器中可以看到 HiddenApp2.exe 這個進程,也不用費心隱藏窗體,何樂不為?
PS: 某些想法不良的同學,可能想到了隱藏起來干點壞事,記住:法網恢恢、疏而不漏!
再來改造一下,讓他實現上面的功能,10秒后彈出一個對話框,證明程序確實在運行。
Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); //Application.Run(new?Form1()); new?Thread(new?ThreadStart(()?=> {Thread.Sleep(10?*?1000);MessageBox.Show("我在后臺執行喲..."); })).Start(); Application.Run();代碼很簡單,就是啟動一個線程延遲10秒后彈窗,有的同學可能要問了,為啥 new Thread 不放在 Application.Run() 方法之后?因為 Application.Run() 會使應用程序主進程阻塞執行,所以后面的代碼不會執行。
擴展
這一節里,我們使用第二步里使用的方法來干一點壞事(PS:我喜歡),做一個 剪切板尾巴 。
最終效果:他會在你復制的文本后面綴上設置好的文字,然后放進剪切板。
迅雷的監視剪切板,就是監視了剪切板中是否有 Html 格式的文本,從中間解析 URL,實現下載。
winform 使用 Clipboard 這個密封類實現剪切板的一些基本用法,來看下定義:
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);} }這一節主要是使用 public static string GetText(); 這個方法,來盜取用戶剪切的內容,并在其后邊追加一個尾巴來惡搞一下。
原理:使用后臺線程,定時的把剪切板內容復制下來,然后追加一些文字,再寫回剪切板。廢話不多說,直接上核心代碼:
var?text?=?Clipboard.GetText(); //不要問我為啥不用?String.IsNullOrEmpty(),因為我用的?.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);//1data?=?null;GC.Collect();Clipboard.SetDataObject(new?MemoryStream(new?byte[0]));data?=?Clipboard.GetDataObject()?.GetData(typeof(MemoryStream));//2data?=?null;GC.Collect();}));thread.SetApartmentState(ApartmentState.STA);thread.Start(); }看到剪切板 Clipboard.SetDataObject 方法可以接受一個 object 參數,我好奇的弄了一個很大的 byte[] 放了進去,結果發現在 GetData() 方法調用后內存劇增(完全算得上內存炸彈),大小是2倍的 byte[] 大小字節,我又重啟一個線程來,再次調用 SetDataObject() 方法設置剪切板內容,發現內存不會釋放。
加了第一個 GC.Collect(); 之后,內存會降一半,我猜想 data 變量被釋放,但是剪切板內容沒釋放,2倍大小的字節應該是 data 變量占用 2G,剪切板占用 2G。如圖:
剛啟動GC.Collect();緊接著執行完畢這段代碼之后:
data?=?null; GC.Collect(); Clipboard.SetDataObject(new?MemoryStream(new?byte[0])); data?=?Clipboard.GetDataObject()?.GetData(typeof(MemoryStream));有趣的是占用的2G內存,不會釋放。為什么上面的 GetData 會使內存劇增,而這一句不會使內存變小呢?如圖:
2G緊接著執行第二個 GC.Collect(); 執行之后,內存會被回收,但是還是比最初的大了一些,沒有完全釋放。如圖:
奇思妙想:可以用 Clipboard 申請一些內存,然后在內存中執行一些代碼,會不會對系統造成威脅?有能力的大牛可以嘗試一下。
完整代碼:
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{///?<summary>///?應用程序的主入口點。///?</summary>[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);//1data?=?null;GC.Collect();Clipboard.SetDataObject(new?MemoryStream(new?byte[1]));data?=?Clipboard.GetDataObject()?.GetData(typeof(MemoryStream));//2data?=?null;GC.Collect();}));thread.SetApartmentState(ApartmentState.STA);thread.Start();}private?const?string?TAIL?=?"你需要關注《開發者精選資訊》公眾號";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
推薦閱讀:
基于GitBook框架搭建技術文檔平臺
百度最牛x的5個開源項目,第一個全票通過進入Apache孵化器
開發者精選資訊
?每日為您推薦開發精選資訊
長按二維碼
關注 「開發者精選資訊」 公眾號
好文章,我在看 ???
總結
以上是生活随笔為你收集整理的如何隐藏运行 winform 程序?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 程序员修神之路--晦涩难懂的CAP,是否
- 下一篇: Kestrel的ListenAnyIP和