当前位置:网站首页>微软是如何解决 PC 端程序多开问题的——内部实现
微软是如何解决 PC 端程序多开问题的——内部实现
2022-04-23 03:02:00 【dotNET跨平台】
前言
上次,我们通过《引用 Microsoft.VisualBasic 解决程序多开的问题》。
虽然它非常简单,但是仅适用于 WinForm 应用程序,而且还需要引用不常用的Microsoft.VisualBasic类库。
因此,我们决定深挖一下,看看具体是如何实现的。
原理
通过查看WindowsFormsApplicationBase的Run方法实现(代码有删减):
Public Sub Run(commandLine As String())
If Not IsSingleInstance Then
DoApplicationModel()
Else
' This is a Single-Instance application
Dim pipeServer As NamedPipeServerStream = Nothing
If TryCreatePipeServer(ApplicationInstanceID, pipeServer) Then
' --- This is the first instance of a single-instance application to run.
Using pipeServer
WaitForClientConnectionsAsync(pipeServer, AddressOf OnStartupNextInstanceMarshallingAdaptor, cancellationToken:=tokenSource.Token)
DoApplicationModel()
End Using
Else
Dim awaitable = SendSecondInstanceArgsAsync(ApplicationInstanceID, commandLine, cancellationToken:=tokenSource.Token).ConfigureAwait(False)
awaitable.GetAwaiter().GetResult()
End If
End If 'Single-Instance application
End Sub
可以分析出整个流程如下:
创建一个
NamedPipeServerStream实例如果创建成功,则用
WaitForClientConnectionsAsync等待第 2 个应用实例进行连接如果创建失败,则用
SendSecondInstanceArgsAsync向第 1 个应用实例发送数据
NamedPipeServerStream
使用NamedPipeServerStream类可以创建命名管道。
命名管道在管道服务器和一个或多个管道客户端之间提供进程间通信。命名管道可以是单向的,也可以是双向的。它们支持基于消息的通信,并允许多个客户端使用相同的管道名称同时连接到服务器进程。
详细使用说明,请参阅官方文档《使用命名管道进行网络进程间通信》[1]
实现
下面我们用控制台程序进行演示:
const string pipeName = "MyIO";
const PipeOptions NamedPipeOptions = PipeOptions.Asynchronous | PipeOptions.CurrentUserOnly;
static async Task Main(string[] args)
{
try
{
using (var pipeServer = new NamedPipeServerStream(
pipeName: pipeName,
direction: PipeDirection.In,
maxNumberOfServerInstances: 1,
transmissionMode: PipeTransmissionMode.Byte,
options: NamedPipeOptions))
{
WaitForClientConnectionsAsync(pipeServer,str => Console.WriteLine(str));
Console.WriteLine($"start server {args[0]}");
Console.ReadKey();
}
}
catch
{
await SendSecondInstanceArgsAsync(()=> $"call from {args[0]}").ConfigureAwait(false);
}
}
需要注意的是,WaitForClientConnectionsAsync不能加await,否则后续代码不能执行。
WaitForClientConnectionsAsync
实现代码如下:
private static async Task WaitForClientConnectionsAsync(NamedPipeServerStream pipeServer, Action<string> callback)
{
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
while (true)
{
await pipeServer.WaitForConnectionAsync(cancellationTokenSource.Token).ConfigureAwait(false);
try
{
const int bufferLength = 1024;
var buffer = new byte[bufferLength];
using (var stream = new MemoryStream())
{
while (true)
{
var bytesRead = await pipeServer.ReadAsync(buffer.AsMemory(0, bufferLength), cancellationTokenSource.Token).ConfigureAwait(false);
if (bytesRead == 0)
{
break;
}
stream.Write(buffer, 0, bytesRead);
}
stream.Seek(0, SeekOrigin.Begin);
callback(Encoding.UTF8.GetString(stream.ToArray()));
}
}
finally
{
pipeServer.Disconnect();
}
}
}
循环等待客户端连接
读取客户端发送的数据,转换成字符串
调用
callback处理字符串,这里是str => Console.WriteLine(str)断开客户端连接
SendSecondInstanceArgsAsync
实现代码如下:
private static async Task SendSecondInstanceArgsAsync(Func<string> func)
{
using (var pipeClient = new NamedPipeClientStream(
serverName: ".",
pipeName: pipeName,
direction: PipeDirection.Out,
options: NamedPipeOptions))
{
CancellationTokenSource cancellationTokenSource2 = new CancellationTokenSource();
cancellationTokenSource2.CancelAfter(2500);
await pipeClient.ConnectAsync(cancellationTokenSource2.Token).ConfigureAwait(false);
await pipeClient.WriteAsync(Encoding.UTF8.GetBytes(func()), cancellationTokenSource2.Token).ConfigureAwait(false);
}
}
创建客户端连接本地管道服务
向服务端发送
func产生的数据,,这里是()=> $"call from {args[0]}"
Demo
创建多开脚本:
start " " "ConsoleApp1.exe" firstInstance
start " " "ConsoleApp1.exe" secondInstance
start " " "ConsoleApp1.exe" thirdInstance
执行后,我们发现程序只能打开一次。
并且收到了其它多开应用发过来的数据:

结论
使用NamedPipeServerStream相对互斥锁Mutex的实现要复杂。
但是由于可以进行通讯,因此可以做到更灵活的控制。
比如,应用定时启动自己的另一个实例去下载更新,下载完成后通知当前应用提示用户是否更新。
想了解更多内容,请关注我的个人公众号”My IO“
参考资料
[1]
《使用命名管道进行网络进程间通信》: https://docs.microsoft.com/zh-cn/dotnet/standard/io/how-to-use-named-pipes-for-network-interprocess-communication?WT.mc_id=DT-MVP-38491
版权声明
本文为[dotNET跨平台]所创,转载请带上原文链接,感谢
https://blog.csdn.net/sd7o95o/article/details/124310722
边栏推荐
- Kubernetes study notes
- Slave should be able to synchronize with the master in tests/integration/replication-psync.tcl
- Windows MySQL 8 zip installation
- Traversal of l2-006 tree (middle and later order determination binary tree & sequence traversal)
- Classification and regression tree of machine learning
- Er and eer models
- 【工欲善其事必先利其器】论文编辑及文献管理(Endnote,Latex,JabRef ,overleaf)资源下载及使用指南
- Leangoo brain map - shared multi person collaborative mind mapping tool
- Solve the problem that PowerShell mining occupies 100% of cpu7 in win7
- Kubernetes - Introduction to actual combat
猜你喜欢

tf. keras. layers. Embedding function

Leangoo brain map - shared multi person collaborative mind mapping tool

Xamarin效果第二十二篇之录音效果

Cloud computing learning 1 - openstack cloud computing installation and deployment steps with pictures and texts (Xiandian 2.2)

Depth deterministic strategy gradient (ddpg)

Actual combat of industrial defect detection project (IV) -- ceramic defect detection based on hrnet

樹莓派開發筆記(十二):入手研華ADVANTECH工控樹莓派UNO-220套件(一):介紹和運行系統

How can enterprises with major hazard installations ensure the completion of the digital construction task of double prevention mechanism by the end of the year

Linux Redis ——Redis HA Sentinel 集群搭建详解 & Redis主从部署

Configuring Apache Web services for servers such as Tianyi cloud
随机推荐
ROP Emporium x86_ 64 7 ~ 8 questions
Android 高阶面试必问:全局业务和项目的架构设计与重构
Résumé du gestionnaire de projet du système d'information Chapitre VI gestion des ressources humaines du projet
Introduction to ACM [inclusion exclusion theorem]
Classification of technology selection (2022)
Kubernetes study notes
基于多态的职工管理系统源码与一些理解
Xamarin效果第二十二篇之录音效果
Jz76 delete duplicate nodes in linked list
Cloud computing learning 1 - openstack cloud computing installation and deployment steps with pictures and texts (Xiandian 2.2)
Error installing Mongo service 'mongodb server' on win10 failed to start
Planning code ROS migration POMDP prediction planning (I)
Encapsulate components such as pull-down menu based on ele
JZ22 鏈錶中倒數最後k個結點
Airtrack cracking wireless network password (Dictionary running method)
MySQL complex query uses temporary table / with as (similar to table variable)
Chapter IV project cost management of information system project manager summary
OCR recognition PDF file
Summary of software test interview questions
Introduction to ACM [TSP problem]