2.2 检查是否已经有实例在运行
通过调用LSOpenURLsWithRole
函数,我们可以检查是否已经有一个实例在运行。如果有,则返回true
,否则返回false
。
use std:: os:: raw:: c_char;
extern crate libc ;
fn is_single_instance ( bundle_id: & str ) -> bool {
let mut psi: libc:: PROCESSENTRY32 = unsafe { std:: mem:: zeroed ( ) } ;
let snapshot = unsafe { libc:: CreateToolhelp32Snapshot ( TH32CS_SNAPPROCESS , 0 ) } ;
if snapshot == 0 {
return false ;
}
psi. dwSize = std:: mem:: size_of :: < libc:: PROCESSENTRY32 > ( ) as DWORD ;
while unsafe { Process32Next ( snapshot, & mut psi) } != 0 {
if let Some ( name) = unsafe { CStr :: from_ptr ( psi. szExeFile. as_ptr ( ) as * const c_char) } . to_str ( ) {
if name == bundle_id {
return true ;
}
}
}
unsafe { CloseHandle ( snapshot) } ;
false
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
3 Linux下的实现
在Linux平台下,可以通过检查进程名或使用套接字来实现单实例检查。这里我们将演示如何通过检查进程名来实现单实例检查。
3.1 获取进程列表
通过调用/proc
文件系统,我们可以获取当前运行的所有进程,并检查是否有相同的进程名。
use std:: fs;
use std:: path:: Path ;
fn get_process_list ( ) -> Vec < String > {
let mut processes = Vec :: new ( ) ;
for entry in fs:: read_dir ( "/proc" ) . unwrap ( ) {
let entry = entry. unwrap ( ) ;
let path = entry. path ( ) ;
if path. is_dir ( ) {
if let Some ( name) = path. file_name ( ) . and_then ( | n| n. to_str ( ) ) {
if name. chars ( ) . all ( char :: is_digit) {
processes. push ( name. to_string ( ) ) ;
}
}
}
}
processes
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
3.2 检查是否已经有实例在运行
通过遍历所有进程,并检查是否有相同的进程名来判断是否已经有实例在运行。
fn is_single_instance ( process_name: & str ) -> bool {
let processes = get_process_list ( ) ;
for pid in processes {
let exe_path = format! ( "/proc/{}/exe" , pid) ;
let exe_link = Path :: new ( & exe_path) ;
if exe_link. exists ( ) {
if let Some ( exe_path) = exe_link. canonicalize ( ) . ok ( ) {
if exe_path. file_name ( ) . and_then ( | n| n. to_str ( ) ) == Some ( process_name) {
return true ;
}
}
}
}
false
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
4 在Tauri应用中集成单实例检查
在Tauri应用的主函数中,我们可以根据不同的平台调用相应的单实例检查函数。
fn main ( ) {
#[cfg(target_os = "windows" )]
{
let instance_name = "MyTauriApp" ;
if ! is_single_instance ( instance_name) {
println! ( "An instance of {} is already running." , instance_name) ;
std:: process:: exit ( 1 ) ;
}
}
#[cfg(target_os = "macos" )]
{
let bundle_id = get_bundle_identifier ( ) ;
if is_single_instance ( & bundle_id) {
println! ( "An instance of {} is already running." , bundle_id) ;
std:: process:: exit ( 1 ) ;
}
}
#[cfg(target_os = "linux" )]
{
let process_name = "my_tauri_app" ;
if is_single_instance ( process_name) {
println! ( "An instance of {} is already running." , process_name) ;
std:: process:: exit ( 1 ) ;
}
}
tauri:: run ( ) ;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
三、使用Tauri官方提供的插件实现单例程序
1. 安装准备
首先,确保你安装的Rust版本符合条件,该插件要求你的Rust版本大于1.77.2
.
然后就是看你的应用平台是否支持该插件,官方给出以下表格
可以明显看到,只有桌面系统受支持,也就是你的应用只能是在windows
,linux
,macos
上,这个插件才会有用,否则插件是用不了的。
2. 自动安装(推荐)
使用你所选择的包管理器直接安装即可,例如pnpm
安装
pnpm tauri add single-instance
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
3. 手动安装
首先添加依赖
# src-tauri/Cargo.toml
[dependencies]
tauri-plugin-single-instance = "2.0.0"
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
然后在tauri启动的时候添加插件
pub fn run ( ) {
tauri:: Builder :: default ( )
. plugin ( tauri_plugin_single_instance:: init ( | app, args, cwd| { } ) )
. run ( tauri:: generate_context! ( ) )
. expect ( "error while running tauri application" ) ;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
然后运行一下项目就装好插件了
pnpm tauri dev
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
四、配置单例插件
如果你只是想要简单的实现单实例的话,就以上安装配置就已经能够达到这个效果了,如果你还想要在这个过程中实现其他功能,例如用户启动了另一个程序后提示程序已经启动了
,那么可以接着往下看。
1. init
函数
在配置安装插件时有一个init
函数可以注意一下,也就是
. plugin ( tauri_plugin_single_instance:: init ( | app, args, cwd| {
} ) )
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
插件的 init()
方法接收一个闭包,该闭包在新 App 实例启动时调用,但由插件关闭。 这个闭包有三个参数:
app
:应用程序的 AppHandle ,即应用的句柄,用来操作该程序。args
:用户初始化新实例时传递的参数列表,也就是新打开的程序的传入参数。cwd
:当前工作目录表示启动新应用程序实例的目录,也就是另一个程序在哪个目录打开的。
2. 新打开程序提示例子
注意,这部分逻辑你可以自己实现,这只是个官方给的例子。
use tauri:: { AppHandle , Manager } ;
pub fn run ( ) {
tauri:: Builder :: default ( )
. plugin ( tauri_plugin_single_instance:: init ( | app, args, cwd| {
let _ = show_window ( app) ;
} ) )
. run ( tauri:: generate_context! ( ) )
. expect ( "error while running tauri application" ) ;
}
fn show_window ( app: & AppHandle ) {
let windows = app. webview_windows ( ) ;
windows
. values ( )
. next ( )
. expect ( "Sorry, no window found" )
. set_focus ( )
. expect ( "Can't Bring Window to Focus" ) ;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/weixin_47754149/article/details/145709030","extend1":"pc","ab":"new"}">>
id="blogExtensionBox" style="width:400px;margin:auto;margin-top:12px" class="blog-extension-box"> class="blog_extension blog_extension_type2" id="blog_extension">
class="extension_official" data-report-click="{"spm":"1001.2101.3001.6471"}" data-report-view="{"spm":"1001.2101.3001.6471"}">
class="blog_extension_card_left">
class="blog_extension_card_cont">
共同探讨互联网知识
class="blog_extension_card_cont_r">
微信名片
评论记录:
回复评论: