如何实现一个程序只运行一个实例

如何实现一个程序只运行一个实例,第1张

关键字:VC如何使应用程序只运行一个实例,VC 只运行一次,只给冲侍一个程序运行

在开发网络应用程序的时候,由于端口分配和占用问题,经常出现某程序只给运行一个实例的情况.下面就介绍一下,如何使程序就只运行一个灶亮实例.

方法一:在应用程序类中使用互斥量

实现步骤:

1.用GUIDGEN.EXE产生一个全局标志,#define PROC_ID "产生的全局标志"

如本实例:#define PROC_ID "0xa9a66d98, 0x18c7, 0x447b, 0x80, 0xc, 0xa3, 0x20, 0xea, 0x4f, 0xb6, 0xe8" /隐判宽/注:GUIDGEN.EXE为VC自带工具,如果在开始->程序的Microsoft Visual C++ 6.0 Tools里找不到该程序可以到C:\Program Files\Microsoft Visual Studio\Common\Tools里找到.

//注:用此方法生成的串,只为保证该进程标识的唯一性,也可以自己定一个简单的串标识

2.

BOOL CEx1App::InitInstance()

{

handle=::CreateMutex(NULL,FALSE,PROC_ID)//handle为声明的HANDLE类型的全局变量

if(GetLastError()==ERROR_ALREADY_EXISTS)

{

AfxMessageBox("应用程序已经在运行")

return FALSE

}

......................//略

}

3.

在XXApp类里右件,添加ExitInstance虚函数:(函数里语句如下即可)

int CEx1App::ExitInstance()

{

CloseHandle(handle)

return CWinApp::ExitInstance()

}

///缺点:无法击活旧窗口

方法二:枚举进程法

#define ID_GUI "0xa9a66d98, 0x18c7, 0x447b, 0x80, 0xc, 0xa3, 0x20, 0xea, 0x4f, 0xb6, 0xe8"//Guidgen.exe生成保证唯一性

//添加的标识只运行一次的属性名

CString g_szPropName = ID_GUI?? //全局变量

HANDLE g_hValue = (HANDLE)1//全局变量

//添加一个枚举窗口的函数

BOOL CALLBACK EnumWndProc(HWND hwnd,LPARAM lParam)

{

HANDLE h = GetProp(hwnd,g_szPropName)

if( h == g_hValue)

{

?? *(HWND*)lParam = hwnd

?? return false

}

return true

}

BOOL CRunOnceApp::InitInstance()

{

?? //查找是否有本程序的前一个实例运行

HWND oldHWnd = NULL

EnumWindows(EnumWndProc,(LPARAM)&oldHWnd)//枚举所有运行的窗口

if(oldHWnd != NULL)

{

?? AfxMessageBox("本程序已经在运行了")

?? ::ShowWindow(oldHWnd,SW_SHOWNORMAL)??? //激活找到的前一个程序

?? ::SetForegroundWindow(oldHWnd)?? //把它设为前景窗口

?? return false??????? //退出本次运行

}

................//略

}

在XXDlg.cpp页

//声明全局变量

extern CString g_szPropName

extern HANDLE g_hValue

在主窗口的 OnInitDialog()中添加属性

//设置窗口属性

SetProp(m_hWnd,g_szPropName,g_hValue)

方法二优点:可以激活旧进程窗口

一般来说的办法就是怎么想让第二次运行知道已经有程序在运行了,或者说怎么闷坦能通知第二个程序已经有文件在运行了

例如程序运行后如果程序运行目录没有文件a.txt,就在程序运行目录新建一个文件a.txt,关闭的时候删除,这样第二次运行发现已存在了这个文件,说明程序已经在运行,故第二次运行直接退出

例如第一个运行程序用系统函数在本地监听一个socket端口,第二次运行程序发现这个端口已经被占用或者能连接,就知道已经有程序在运行了(例如smplayer就这样搞的)

例如第一个运行的程序在注册表某个地方写入一个1,退出时写入0,第二次运行的程序发现注册表这个地方是1就退出,如果是0就可以继续运行了,也就是其实是第一次运行伍罩坦

反正无论什么办法,具体要看你觉得怎么样合适才行的呢。还可以去找系统的进程列表,还可以腔桐测试某些环境变量啊,反正方法是很多的是死的,人是活的。

C#禁止应用程序同时运行的方法

using System

using System.Collections.Generic

using System.Windows.Forms

namespace SingleProcessStart

{

static class Program

{

/// <summary>

/// 应用程序的主入口点。

/// </summary>

//

//使用STAThread属性将程序的默认线程模型指定为单线程模型。

//注意,线程模型只影响使用COM interop的应用程序,将这个属性应用于不改信使用COM interop的程序将不会产生任何效果。

[STAThread]

//[MTAThreadAttribute]

static void Main()

{

////原始

//Application.EnableVisualStyles()

//Application.SetCompatibleTextRenderingDefault(false)

/桐此/Application.Run(new Form1())

//方法一,使用线程互斥

//bool createdNew = false

//System.Threading.Mutex mutex = new System.Threading.Mutex(true, "OnlyOnceTime", out createdNew)

//if (createdNew)

//{

//Application.EnableVisualStyles()

//Application.SetCompatibleTextRenderingDefault(false)

//Application.Run(new Form1())

//}

//else

//{

//MessageBox.Show("程序已经运行!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)

//}

//方法二,使用API实现

/*

* 关于方法二的调试,需要注意的是要将项目--属性--调试,选择启用外部程序,选择到你的EXE文件,然后先开启你的EXE文件

* 否则在调试时.NET默认会局歼迅使用vshost.exe的宿主进程(宿主进程随.NET启动而启动),而此宿主进程在外部无法启用,因此永远是唯一的

*/

System.Diagnostics.Process p = GetRunningInstance()

if (p != null) //已经有应用程序副本执行

{

HandleRunningInstance(p)

}

else //启动第一个应用程序

{

Application.EnableVisualStyles()

Application.SetCompatibleTextRenderingDefault(false)

Application.Run(new Form1())

}

}

//以下为方法二调用API代码

private const int WS_HIDE = 0//窗口隐藏

private const int WS_SHOWNORMAL = 1//窗口处于正常状态

private const int WS_SHOWMIN = 2//窗口处于最小化状态

private const int WS_SHOWMAX = 3//窗口处于最大化状态

/// <summary>

/// 显示窗口

/// </summary>

/// <param name="hWnd">句柄</param>

/// <param name="cmdShow">显示模式</param>

/// <returns></returns>

[System.Runtime.InteropServices.DllImport("User32.dll")]

private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow)

[System.Runtime.InteropServices.DllImport("User32.dll")]

private static extern bool SetForegroundWindow(IntPtr hWnd)

/// <summary>

/// 查找窗口的句柄

/// </summary>

/// <param name="className">指向包含了窗口类名的空中止(C语言)字串的指针;或设为零,表示接收任何类</param>

/// <param name="titleName">指向包含了窗口文本(或标签)的空中止(C语言)字串的指针;或设为零,表示接收任何窗口标题</param>

/// <returns>句柄</returns>

[System.Runtime.InteropServices.DllImport("User32.dll", EntryPoint = "FindWindow")]

public static extern int FindWindow(string className, string titleName)

/// <summary>

/// 获取应用程序进程实例,如果没有匹配进程,返回Null

/// </summary>

/// <returns>返回当前Process实例</returns>

public static System.Diagnostics.Process GetRunningInstance()

{

//获取当前进程

System.Diagnostics.Process currentProcess = System.Diagnostics.Process.GetCurrentProcess()

//获取当前运行程序完全限定名

string currentFileName = currentProcess.MainModule.FileName

//获取进程名为ProcessName的Process数组。

System.Diagnostics.Process[] processes = System.Diagnostics.Process.GetProcessesByName(currentProcess.ProcessName)

//遍历有相同进程名称正在运行的进程

foreach (System.Diagnostics.Process process in processes)

{

if (process.MainModule.FileName == currentFileName)

{

if (process.Id != currentProcess.Id)//根据进程ID排除当前进程

return process//返回已运行的进程实例

}

}

return null

}

/// <summary>

/// 获取应用程序句柄,设置应用程序前台运行,并返回bool值

/// </summary>

public static bool HandleRunningInstance(System.Diagnostics.Process instance)

{

IntPtr intPtr = new IntPtr(instance.MainWindowHandle.ToInt32() == 0 ?

FindWindow(null, "Form1") : instance.MainWindowHandle.ToInt32())

//使窗口最大化

ShowWindowAsync(intPtr, WS_SHOWMAX)

//设置前台进程为已运行的进程,而现有进程继续执行至进程结束(在这里跑完MAIN函数就结束掉了)

return SetForegroundWindow(instance.MainWindowHandle)

}

/// <summary>

/// 获取窗口句柄,设置应用程序前台运行,并返回bool值,重载方法

/// </summary>

/// <returns></returns>

public static bool HandleRunningInstance()

{

System.Diagnostics.Process p = GetRunningInstance()

if (p != null)

{

HandleRunningInstance(p)

return true

}

return false

}

}

}


欢迎分享,转载请注明来源:内存溢出

原文地址:https://www.54852.com/yw/12348930.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-05-22
下一篇2023-05-22

发表评论

登录后才能评论

评论列表(0条)

    保存