找回密码
 注册
搜索
热搜: 超星 读书 找书
查看: 87|回复: 6

[【其它】] 有什么方法能让能多开的程序变成单开?

[复制链接]
发表于 2024-4-1 17:44:01 | 显示全部楼层 |阅读模式
例如记事本程序是可以多开的。还有一些程序在设置里可以设置成单开或多开。
现在一个可以多开的程序,设置里没有设置成单开的选项,例如记事本程序。
有什么方法能让这个程序暂时变成单开的?
例如点一个文本,这时再点另一个文本,之前的文本窗口转变成后来点的文本窗口。
windows图片和传真查看器就是单开的,符合上述要求。

评分

1

查看全部评分

回复

使用道具 举报

发表于 2024-4-1 17:46:46 | 显示全部楼层
为什么要单开,多开不好吗
回复

使用道具 举报

 楼主| 发表于 2024-4-1 18:05:23 | 显示全部楼层
1994 发表于 2024-4-1 17:46
为什么要单开,多开不好吗

我是让它暂时单开。有时多开反而不好用。
搜了一下,都是用编程的方法,有没有简单的方法。

回复

使用道具 举报

发表于 2024-4-1 22:11:27 来自手机 | 显示全部楼层
坐等大佬出手
回复

使用道具 举报

发表于 2024-4-3 16:51:20 | 显示全部楼层
轉帖
https://blog.csdn.net/HorseRoll/article/details/80365797
https://blog.csdn.net/liuyinghui ... 1-blog-80365797.235^v43^pc_blog_bottom_relevance_base4&spm=1001.2101.3001.4242.1&utm_relevant_index=3

有些时候,我们要求一个程序在系统中只能启动一个实例。比如,Windows自带的播放软件Windows Medea Player在Windows里就只能启动一个实例。原因很简单,如果同时启动几个实例,却播放不同的文件,那么声音和图像就会引起混乱。在设计模式中,就有一个SINGLETON模式,该模式就是让类只有一个实例。(关于SINGLETON模式,可以看我那篇 《重读《设计模式》之学习笔记(三)--SINGLETON模式的疑惑 》)。
    对于程序而言,我们只有在程序启动的时候去检测某个设置,如果程序没有启动,就把设置更新为程序已经启动,然后正常启动程序;如果程序已经启动,那么就终止程序的启动。在程序退出的时候把设置恢复为程序没有启动。按照上面的思路,我们很容易就能想出下面的两种方法:
    一,文件法
    在硬盘上创建一个文件,在文件里设置一个值,根据这个值来判断程序是否已经启动。
    二,注册表法
    在注册表中创建一个键,根据该键的键值来决定是否要启动程序。
    但是,上面的两种方法,都有I/O操作。我觉得这不是最好的方法。下面就介绍两种不用I/O操作的方法。思路跟上面是一样的,在进程启动的时候去检测某个设置是否继续启动进程。由于要判断同一个程序是否已经启动一个实例,也就是说会有两个进程去访问同一个设置,所以该设置应该是可以夸进程访问的,比如上面两种方法中的文件和注册表。我们在用VC进行开发时,还可以用文件映射和互斥量。下面是详细的说明:
    VC在创建工程的时候,会自动创建一个App的类。比如,你的工程名是StarLee,那么这个App类的类名就是CStarLeeApp。在进程启动和退出的时候会分别调用该类的两个方法:InitInstance()和ExitInstance()。所以,我们的代码都是添加在这两个方法里面的。
    三,文件映射法
    首先,给App类加上一个成员变量:
HANDLE m_hFileMapping;
    然后,在App类的InitInstance()方法的最前面加上下面的代码:

m_hFileMapping  =  CreateFileMapping(NULL, NULL, PAGE_READONLY,  0 ,  13 ,  " StarLee " );

//  检测是否已经创建FileMapping
//  如果已经创建,就终止进程的启动
if  ((m_hFileMapping  !=  NULL)  &&  (GetLastError()  ==  ERROR_ALREADY_EXISTS))
{
    CloseHandle(m_hFileMapping);
   
    MessageBox(NULL,  " 该进程已经启动 " ,  " 错误 " , MB_OK);

     return  FALSE;
}
    最后,在App类的ExitInstance()方法里加上下面的代码:

if  (m_hFileMapping  !=  NULL)
    CloseHandle(m_hFileMapping);
    四,互斥量法
    首先,给App类加上一个成员变量:

HANDLE m_hMutex;
    然后,在App类的InitInstance()方法的最前面加上下面的代码:

m_hMutex  =  CreateMutex(NULL, TRUE,  " StarLee " );

//  检测是否已经创建Mutex
//  如果已经创建,就终止进程的启动
if  ((m_hMutex  !=  NULL)  &&  (GetLastError()  ==  ERROR_ALREADY_EXISTS))
{
    ReleaseMutex(m_hMutex);

    MessageBox(NULL,  " 该进程已经启动 " ,  " 错误 " , MB_OK);

     return  FALSE;
}
    最后,在App类的ExitInstance()方法里加上下面的代码:

if  (m_hMutex  !=  NULL)
{
    ReleaseMutex(m_hMutex);
    CloseHandle(m_hMutex);
}
    上面两种方法的思路和代码添加的步骤都是一样的,当然效果也一样,选择任何一种方法都能达到让进程只启动一个实例的目的。

五,共享变量法
    首先,在App类的cpp文件开头加上下面的代码:

#pragma  data_seg("StarLee")  //  自己定义的数据段
     char  nInstanceCount  =   - 1 ;  //  实例个数,下文会详细用char来定义实例个数的好处
#pragma  data_seg()
#pragma  comment(linker, "/section:StarLee,rws")  //  共享该数据段(r - read, w - write, s - share)


    然后,在App类的InitInstance()方法的最前面加上下面的代码:



nInstanceCount ++ ;
if  (nInstanceCount  >   0 )
{
    MessageBox(NULL,  " 该进程已经启动 " ,  " 错误 " , MB_OK);
        
     return  FALSE;
}


    最后,在App类的ExitInstance()方法里加上下面的代码:



nInstanceCount--;


    PS:这里介绍一下上面代码中用把实例个数的类型定义为char的小技巧。我们知道char的长度为1个字节,是用-128~127之间的整型来表示的。而我们进程实例的最大值是1,而且在程序的数据段里添加的东西越少越好,所以char就成了最佳之选。

    在那篇《程序只启动一个实例的几种方法》的十几个回复中,很多网友都提到了如果进程被意外终止,恢复设置的代码将不会被调用,那样程序就不能再被启动了。为此我针对每种方法都做了测试,下面对结果进行一下分析:
    测试环境:
    Windows 2000,VC++ 6.0
    测试方法:
    1,启动程序,在任务管理器终止该进程,再次启动进程。
    2,删除App类的ExitInstance()方法里面添加的代码,编译通过以后,启动程序,关闭程序,再次启动程序。
    结果:
    对于方法一和方法二(文件法和注册表法),由于有I/O操作,如果恢复设置的代码不被调用,除非手动将设置恢复,否则程序就永远不能再被启动。这也是我不推荐这两种方法的主要原因。
    对于后3种方法(文件映射法,互斥量法和共享变量法),就算进程被异常终止,恢复设置的代码不被调用,也不会影响程序的再次启动。我觉得,这是因为这3种使用的对象(文件映射,互斥量,共享变量)虽然可以夸进程访问,但是他们还是属于创建者进程的,会随着创建者的销毁而销毁,Windows会在进程结束(无论是正常还是意外)的时候释放它们。
    另外,我在MSDN对CreateMutex的介绍中发现了下面这句话:
    The system closes the handle automatically when the process terminates. The mutex object is destroyed when its last handle has been closed.
    可以说这是明确的告诉我们互斥量在程序终止的时候会被自动释放。
    所以,在我介绍的这些让进程只启动一个实例的五种方法中,互斥量法是最好的解决方法。
回复

使用道具 举报

发表于 2024-4-3 22:53:23 | 显示全部楼层
没有简单的办法,甚至复杂的办法都不是正规的做法。所谓单实例,其实不是单实例。当第二次运行的时候,已经创建一个实例,此时或查找窗口,或互斥量等方法,查询是否有实例存在,若存在则将相应参数传递给第一个实例,第二次运行的实例退出。这个逻辑是写在软件里的。
回复

使用道具 举报

发表于 2024-4-4 22:39:20 | 显示全部楼层
如果程序本身没有单开的选项,那么只能通过外部程序来实现。不过倒是有可能制作一个通用的程序,监视所需要的程序,一旦检测到有第2个实例出现,就杀掉进程。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|手机版|小黑屋|网上读书园地

GMT+8, 2024-4-30 00:57 , Processed in 0.354815 second(s), 6 queries , Redis On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表