当前位置:网站首页>微软是如何解决 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
边栏推荐
- Introduction to ACM [TSP problem]
- The way to conquer C language
- MySQL complex query uses temporary table / with as (similar to table variable)
- The space between the left and right of the movie ticket seats is empty and cannot be selected
- How to use C language to realize [guessing numbers game]
- Leangoo brain map - shared multi person collaborative mind mapping tool
- 第46届ICPC亚洲区域赛(昆明) B Blocks(容斥+子集和DP+期望DP)
- How to build an integrated industrial Internet plus hazardous safety production management platform?
- Source code and some understanding of employee management system based on polymorphism
- tf. keras. layers. Density function
猜你喜欢
![FileNotFoundError: [Errno 2] No such file or directory](/img/ea/0c3f2768d14c1f4bb42bd1309ab996.png)
FileNotFoundError: [Errno 2] No such file or directory

tf. keras. layers. Conv? D function

Leangoo brain map - shared multi person collaborative mind mapping tool

Linux Redis——Redis 数据库缓存服务

Plug in for vscode

Source code and some understanding of employee management system based on polymorphism

Airtrack cracking wireless network password (Dictionary running method)

Summary of interface automation interview questions for software testing

HLS / chisel practice CORDIC high performance computing complex square root

Q-Learning & Sarsa
随机推荐
Some problems encountered in setting Django pure interface, channel and MySQL on the pagoda panel
Les derniers noeuds K de la liste jz22
【Hcip】OSPF常用的6种LSA详解
Microservices (distributed architecture)
The difference between encodeuri and encodeuricomponent
Introduction to ACM [inclusion exclusion theorem]
Basic workflow of CPU
基于ele封装下拉菜单等组件
tf. keras. layers. Embedding function
Onenet connection process
It turns out that PID was born in the struggle between Lao wangtou and Lao sky
Configuring Apache Web services for servers such as Tianyi cloud
In redis cluster, the master node fails, and the IP changes after the master-slave switch. The client does not need to deal with it
tf. keras. layers. Conv? D function
AC380V drop 5v12v24v200ma, UHV non isolated chip IC scheme
Source code and some understanding of employee management system based on polymorphism
Regular object type conversion tool - Common DOM class
Résumé du gestionnaire de projet du système d'information Chapitre VI gestion des ressources humaines du projet
MySQL function syntax
Specific field information of MySQL export table (detailed operation of Navicat client)