如何隐藏运行 winform 程序?

群里有个同学问了问题 如何隐藏运行 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孵化器

开发者精选资讯
 每日为您推荐开发精选资讯

长按二维码
关注 「开发者精选资讯」 公众号

好文章,我在看 ❤️ 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/308578.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[MyBatisPlus]常用注解_@TableName_@TableId_@TableField_@TableLogic通过全局配置配置主键生成策略

常用注解 TableName 设置实体类所对应的表名 如果全部表都有某个前缀,难道我们要通过一个一个加注解的方式来解决实体类对应表名问题吗&#xff1f; 我们可以通过配置文件来解决这个问题&#xff1a; TableId 将属性所对应的字段指定为主键 TableId的value属性 TableId的ty…

最小堆和最大堆的建立以及基本操作

前言&#xff1a; 堆的特性&#xff1a;用数组表示的完全二叉树。有序性&#xff1a;任一结点的关键字是其子树所有结点的最大值 (最小值) 堆的本质&#xff1a;就是一颗 完全二叉树 堆的数据存储&#xff1a; 用的是 数组 建堆时主要的操作&#xff1a;就是调整 对数组的元素…

字符串是单一字符的无序组合吗_Python学习笔记(八)组合数据类型

Python语言中最常用的组合数据类型有3大类&#xff0c; 分别是集合类型、序列类型和映射类型。集合类型是一个具体的数据类型名称&#xff0c;而序列类型和映射类型是一类数据类型的总称。集合类型是一个元素集合&#xff0c;元素之间无序&#xff0c;相同元素在 集合中唯一存在…

[MyBatisPlus]条件构造器wapper

wapper简介 QueryWrapper 组装查询条件 查询用户名包含a&#xff0c;年龄在20到30之间&#xff0c;邮箱信息不为null的用户信息 package com.xxxx.mybatisplus;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.xxxx.mybatisplus.mapper.Use…

推荐:适合小白入门的Asp.Net Core 开源学习手册

前言推荐一个入门级的.NET Core开源项目&#xff0c;非常适合新手入门学习.NET Core。开源地址:https://github.com/windsting/little-aspnetcore-book。手册在线下载地址&#xff1a;https://nbarbettini.gitbooks.io/little-asp-net-core-book/content/chapters/mvc-basics/c…

从当前元素继续寻找_云漫圈 | 寻找无序数组的第k大元素

戳蓝字“CSDN云计算”关注我们哦&#xff01;作者&#xff1a;小灰来源&#xff1a;程序员小灰本期封面作者&#xff1a;泰勒太乐————— 第二天 —————题目是什么意思呢&#xff1f;比如给定的无序数组如下&#xff1a;如果 k6&#xff0c;也就是要寻找第6大的元素&a…

DFS和BFS总结和代码演示(详解)

1&#xff1a;BFS 广度优先搜索类似于树的层次遍历过程。它需要借助一个队列来实现。如图2-1-1所示&#xff0c;要想遍历从v0到v6的每一个顶点&#xff0c;我们可以设v0为第一层&#xff0c;v1、v2、v3为第二层&#xff0c;v4、v5为第三层&#xff0c;v6为第四层&#xff0c;再…

Kestrel的ListenAnyIP和ListenLocalhost的区别

问题在上篇文章&#xff0c;把AAStore.ProductCatalog.Api部署到docker中运行&#xff0c;输入地址访问报错如下图&#xff0c;说明外部无法访问这个url。&#xff08;当然本地开发环境测试是可以访问的&#xff09;。后来修改此处options.ListenLocalhost(8081)的代码改成opti…

[MyBatisPlus]Plus分页插件的配置和使用

Plus分页插件的配置和使用 配置类 package com.xxxx.mybatisplus.config;import com.baomidou.mybatisplus.annotation.DbType; import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; import com.baomidou.mybatisplus.extension.plugins.inner.Pagin…

控制是否展示_现场展示板管理不在于看,而在于管!

点击上方"五株科技"&#xff0c;关注公众号&#xff0c;天天有精彩&#xff01;一位日本专家根据研究数据宣称&#xff0c;如果中国的中小企业有效实行车间展示板管理&#xff0c;最大能够提升生产效率30%以上。通常被管理者小视的车间展示板&#xff0c;在专家眼中却…

龙芯完成.NET移植稳步推进生态建设

不久前&#xff0c;龙芯团队完成了.Net Core 3.1在龙芯上的移植。早在1年前&#xff0c;一位网友就告知&#xff0c;希望.Net能够移植到龙芯平台&#xff0c;因为一些政务应用场景有这方面的需求。只不过了一年&#xff0c;这就问题就被龙芯团队解决了。龙芯团队之所以移植.Net…

[MyBatisPlus]乐观锁和悲观锁

乐观锁和悲观锁 场景 一件商品&#xff0c;成本价是80元&#xff0c;售价是100元。老板先是通知小李&#xff0c;说你去把商品价格增加50元。小李正在玩游戏&#xff0c;耽搁了一个小时。正好一个小时后&#xff0c;老板觉得商品价格增加到150元&#xff0c;价格太高&#xf…

7月30日 举办专注于微服务的.NET Conf Focus

2020 年 7 月 30 日, 由.NET基金会和微软 将举办一个在线和为期一天的活动&#xff0c;包括 微软 .NET 团队的演讲者以及社区的演讲者。本次在线大会 专注.NET框架构建微服务&#xff0c;演讲者分享构建和部署云原生应用程序的最佳实践、模式、提示和技巧。有关更多信息和随时了…

7-8 哈利·波特的考试 (25 分)(详解+思路分析)真香啊

一&#xff1a;题目&#xff1a; 哈利波特要考试了&#xff0c;他需要你的帮助。这门课学的是用魔咒将一种动物变成另一种动物的本事。例如将猫变成老鼠的魔咒是haha&#xff0c;将老鼠变成鱼的魔咒是hehe等等。反方向变化的魔咒就是简单地将原来的魔咒倒过来念&#xff0c;例…

ABPHelper.CLI及其依赖项简单介绍

图片gif无法查看&#xff0c;请查看原文至博客园查看详情。目录目录ABPHelper.CLIScriban通过Microsoft.Extensions.FileProviders.Embedded获取嵌入资源通过静态方法获取文件内容使用Microsoft.Extensions.FileProviders.Physical获取文件内容Microsoft.CodeAnalysis.CSharpHu…

[RabbitMQ]整合SpringBoot

整合SpringBoot 创建项目 引入依赖 <dependencies><!--RabbitMQ 依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId></dependency><dependency><…

mysql 固定符号分列显示_MySql中指定符号分割并分行展示

1.涉及到的函数三个&#xff1a;1.1 REPLACE(value,str1,str2)用法规则&#xff1a;使用str2替换掉value中的所有的str1;SELECT REPLACE(我来了,来,走)执行结果如下&#xff1a;1.2 LENGTH(str)用法规则&#xff1a;获取字符串的长度&#xff0c;使用 uft8(UNICODE 的一种变长字…

C++中 Map的了解与基本用法(代码演示+自我总结+map中一对多的用法)

C中 map的了解与基本用法&#xff08;代码演示&#xff09; 一&#xff1a;map的基本认识 Map是STL的一个关联容器&#xff0c;它提供一对一&#xff08;其中第一个可以称为关键字&#xff0c;每个关键字只能在map中出现一次&#xff0c;第二个可能称为该关键字的值&#xff…

[Redis6]跳跃表(跳表)

跳跃表(跳表) 简介 有序集合在生活中比较常见&#xff0c;例如根据成绩对学生排名&#xff0c;根据得分对玩家排名等。对于有序集合的底层实现&#xff0c;可以用数组、平衡树、链表等。数组不便元素的插入、删除&#xff1b;平衡树或红黑树虽然效率高但结构复杂&#xff1b;…

ASP.NET Core中的响应压缩

介绍响应压缩技术是目前Web开发领域中比较常用的技术&#xff0c;在带宽资源受限的情况下&#xff0c;使用压缩技术是提升带宽负载的首选方案。我们熟悉的Web服务器&#xff0c;比如IIS、Tomcat、Nginx、Apache等都可以使用压缩技术&#xff0c;常用的压缩类型包括Brotli、Gzip…