群里有个同学问了问题 如何隐藏运行 winform 程序?,提起了我的兴趣,玩玩呗?那就玩玩吧!

第一版

将一个 winform 程序隐藏执行,隐藏执行的方式有很多种,第一个 demo 就用最简单的方式,实现隐藏执行。

demo 执行时,不会显示任何窗体,但是过10秒,会弹出对话框证明程序在运行。

  1. 按照常规思路,在窗体初始化完成之后,调整窗体参数。

public partial class Form1 : Form
{public Form1(){InitializeComponent();//不要显示在任务栏this.ShowInTaskbar = false;//隐藏窗体this.Visible = false;//窗体宽度调整为0this.Width = 0;//窗体高度调整为0this.Height = 0;//窗体最左边设置成-10000,保证在屏幕外边this.Left = -10000;//窗体最顶部设置成-10000,保证在屏幕外边this.Top = -10000;}
}
  1. Form1_Load 方法里新启动一个线程,弹出对话框试试。

private void Form1_Load(object sender, EventArgs e)
{new Thread(new ThreadStart(() =>{Thread.Sleep(10 * 1000);MessageBox.Show("我在后台执行哟...");})).Start();
}

运行起来发现还是有显示,而且左边和顶边的位置没有设置成功。如图:

  1. 还有一个 opacity,窗体透明度的属性,设置成0。如下:

this.Opacity = 0;
  1. 现在就好了,看不见窗体,达到了隐藏的目的,简单粗暴,但是还凑合实用。

不足之处:窗体虽然是隐藏了,但只是调整了透明度(心里有点不爽,明明它是存在的,肉眼看不见而已)。

第二版

经过第一个 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 程序?相关推荐

  1. 运行winform程序提示:You must install .NET Desktop Runtime 6.0.1(x64)

    场景 需要将一个winform程序打包发送给客户运行.一开始是将debug下所有文件发送给客户,然后客户点击exe文件运行时提示没有安装.NET Desktop Runtime 6.0.1.然后又尝试 ...

  2. 不装.net Framework 也能运行WinForm程序,用飞信(转)

    本来想把用C#写的程序重写移植到win32平台的,但是感觉重写好累,而且不是很熟练,就想着能不能在未安装.net的机器上运行,有需就有求,嘎嘎,百度了一会,已经有各位老大们已经在讨论用飞信的虚拟机平台 ...

  3. C# 以管理员身份运行WinForm程序

    最近帮客户开发的WinForm客户端,部分在使用的过程中,会出现"系统文件找不到"的错误提示. 调试后,确定为程序在操作配置文件时,系统权限引起的错误,直接管理员权限运行就正常了. ...

  4. C# winform程序免安装.net framework在XP/win7/win10环境运行

    前文: 首先感谢群里的大神宇内流云 提供的anyexec for windows版本. 经过本人搭建虚拟机在xp环境 使用anyexec运行winfrom程序后,测试通过,如下是用的xp运行winfr ...

  5. 在VS.NET中使用clickonce技术开发Winform程序

    做为程序员,我们经常要面对的是对开发模式的选择,比如C/S模式和b/s模式.现在,很多人都似乎比较喜欢选择B/S模式进行web的开发,这其中的原因是很多的.但其中一点很重要的原因,那就是因为B/S开发 ...

  6. 脱离.Net Framework运行doNet程序的简单方法

    脱离.Net Framework运行doNet程序的简单方法(Console) 在.Net Framework下,你就算写一个小小的控制台程序,哪怕只有几K大小,我们必须要安装一个几十M的Framew ...

  7. 关于C#winform程序运行无异常,在生成安装文件安装后提示水晶报表加载失败,系统找不到指定的路径的解决方法...

    关于C#winform程序运行无异常,在生成安装文件安装后提示"水晶报表加载失败,系统找不到指定的路径"的解决方法 娘了个腿的!搞了好几天,百度都被我搜烂了,连发布相关内容的作者名 ...

  8. 在运行时切换 WinForm 程序的界面语言 System.ComponentModel.ComponentResourceManager .ApplyResources...

    Download the code for this article: WinForm-Multilanguages-2.rar (11 KB). 方法二: 下面介绍一种只需对现有代码做较小改动的方法 ...

  9. win10隐藏正在运行的程序怎么操作_win10怎么隐藏正在运行的软件

    win10隐藏正在运行的程序的方法: 1.按下"Win+TAB"组合键,在左上角点击"新建桌面"; 2.点击新建的"桌面2",我们将需要隐藏 ...

最新文章

  1. MongoDB基本使用
  2. 碎碎念 | 投资理财那些事
  3. java获取tomcat目录结构_tomcat目录结构简介_动力节点Java学院整理
  4. python为什么装不了pip_python自带pip用不了怎么办
  5. 32 块大小_详解Linux文件系统的完整结构--引导块、超级块、GDT等
  6. mysql 数据迁移_【AWS 功能】Mysql 数据库迁移至Amazon RDS方案
  7. epic打开一直闪_教你用意派Epub360做酷炫的快闪H5!(附快闪H5模板)
  8. Linux:JDK配置
  9. 控制网页frame vba_V8 bindings 设计isolate,context,world,frame之间的关系(翻译)
  10. 我成功通过PMP考试的经验与体会
  11. js操作浏览器cookie详解
  12. xy转经纬 经纬转xy 各种坐标系
  13. web前段 ps基础
  14. Linu系统 rpm软件包 管理
  15. Flutter AnimatedIcon 图标也可以动画
  16. 跨考计算机英语自我介绍,跨专业考研英语自我介绍
  17. Oracle - 优化器(Optimizer)- 01概念
  18. bootStrap-table之全选反选
  19. XML与JSON的生成与解析
  20. oracle 第一范式,数据库范式之第一范式

热门文章

  1. Linux环境下压缩与解压命令大全
  2. Appium同时运行多个设备
  3. getElementByClassName()不兼容的解决办法
  4. UScript中的Pow函数
  5. Asp.net 2.0 发送电子邮件
  6. 如何在Microsoft Word中插入签名
  7. facebook 邀请好友_如何在Facebook上与某人解除好友
  8. java 输入流关闭顺序_Java IO流中先关闭输出流还是先关闭输入流?为什么?
  9. 配置 mybatis的 log4j.properties
  10. 设置 Xcode 自动生成代码片段