C# winform 一台电脑运行一个程序控制

一个私有云从业者 2010-06-24 08:58:18
如题,描述:我做一个C# winform程序。打开时候是个登录窗口,若登录成功则进入主窗口。
现在,我想控制一台电脑只可以有一个这样的程序在运行。当用户点击运行程序时,
若这个程序已经运行,则把这个程序的主窗口显示出来。
若没有运行则,显示登录窗口。


我用以下程序实现:
//查看是否有该程序的进程存在,若存在,将其结束,但是根本进入不了主页面。
private void btLogin_Click(object sender, EventArgs e)
{
//string processName = "123";//进程名
//foreach (System.Diagnostics.Process thisproc in System.Diagnostics.Process.GetProcesses())
//{
// if (thisproc.ProcessName.Equals(processName ))
// {
// thisproc.Kill();
// }
//}
}
...全文
737 25 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
sunkai572 2010-06-24
  • 打赏
  • 举报
回复
学习。。。
gohappy2008 2010-06-24
  • 打赏
  • 举报
回复
using System;
using System.Collections.Generic;
using System.Windows.Forms;

namespace WinFormStudy
{
static class Program
{
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
bool ret;
System.Threading.Mutex m = new System.Threading.Mutex(true, Application.ProductName, out ret);
if (ret)
{
System.Windows.Forms.Application.EnableVisualStyles(); //这两行实现 XP 可视风格
System.Windows.Forms.Application.DoEvents();
System.Windows.Forms.Application.Run(new Form1());
// frmMain 为你程序的主窗体,如果是控制台程序不用这句
m.ReleaseMutex();
}
else
{
MessageBox.Show(null, "有一个和本程序相同的应用程序已经在运行,请不要同时运行多个本程序。\n\n这个程序即将退出。", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
// 提示信息,可以删除。
Application.Exit();//退出程序
}
}
}
}
fangbuge 2010-06-24
  • 打赏
  • 举报
回复
防止程序运行多个实例的方法有多种,如:通过使用互斥量和进程名等.而我想要实现的是:在程序运行多个实例时激活的是第一个实例,使其获得焦点,并在前端显示.

主要用到两个API 函数:

ShowWindowAsync 该函数设置由不同线程产生的窗口的显示状态。
SetForegroundWindow 该函数将创建指定窗口的线程设置到前台,并且激活该窗口。键盘输入转向该窗口,并为用户改各种可视的记号。系统给创建前台窗口的线程分配的权限稍高于其他线程。
代码如下:

static class Program
{
/// <summary>
/// 该函数设置由不同线程产生的窗口的显示状态。
/// </summary>
/// <param name="hWnd">窗口句柄</param>
/// <param name="cmdShow">指定窗口如何显示。查看允许值列表,请查阅ShowWlndow函数的说明部分。</param>
/// <returns>如果函数原来可见,返回值为非零;如果函数原来被隐藏,返回值为零。</returns>
[DllImport("User32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
/// <summary>
/// 该函数将创建指定窗口的线程设置到前台,并且激活该窗口。键盘输入转向该窗口,并为用户改各种可视的记号。系统给创建前台窗口的线程分配的权限稍高于其他线程。
/// </summary>
/// <param name="hWnd">将被激活并被调入前台的窗口句柄。</param>
/// <returns>如果窗口设入了前台,返回值为非零;如果窗口未被设入前台,返回值为零。</returns>
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
private const int WS_SHOWNORMAL = 1;

/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Process instance = RunningInstance();
if (instance == null)
{
Form1 frm = new Form1();
Application.Run(new Form1());
}
else
{
HandleRunningInstance(instance);
}

}
/// <summary>
/// 获取正在运行的实例,没有运行的实例返回null;
/// </summary>
public static Process RunningInstance()
{
Process current = Process.GetCurrentProcess();
Process[] processes = Process.GetProcessesByName(current.ProcessName);
foreach (Process process in processes)
{
if (process.Id != current.Id)
{
if (Assembly.GetExecutingAssembly().Location.Replace("/", "\\") == current.MainModule.FileName)
{
return process;
}
}
}
return null;
}

/// <summary>
/// 显示已运行的程序。
/// </summary>
public static void HandleRunningInstance(Process instance)
{
ShowWindowAsync(instance.MainWindowHandle, WS_SHOWNORMAL); //显示,可以注释掉
SetForegroundWindow(instance.MainWindowHandle); //放到前端
}
}
记着引用以下命名空间:
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Reflection;



本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/baihe_591/archive/2008/08/22/2811731.aspx
pg1987ll 2010-06-24
  • 打赏
  • 举报
回复
学习,接分。
兔子-顾问 2010-06-24
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 hzzasdf 的回复:]
引用 8 楼 wuyazhe 的回复:
任何事都没绝对,这个前提是winform。非winform,都没窗体。你前置啥。直接把当前进程结束掉不就行了。

赫赫,忘了说了,这个程序对于已经最小化了的窗体好像无效哦。
对于已经最小化了的程序,需要先调用API函数ShowWindow(window, SW_SHOWNORMAL);然后再调用SetForegroundWindow
[/Quote]
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 wuyazhe 的回复:]
任何事都没绝对,这个前提是winform。非winform,都没窗体。你前置啥。直接把当前进程结束掉不就行了。
[/Quote]
赫赫,忘了说了,这个程序对于已经最小化了的窗体好像无效哦。
对于已经最小化了的程序,需要先调用API函数ShowWindow(window, SW_SHOWNORMAL);然后再调用SetForegroundWindow
wxm3630478 2010-06-24
  • 打赏
  • 举报
回复
参考:http://blog.csdn.net/zgke/archive/2009/07/29/4390545.aspx

但是这个有一点缺陷,如果添加一个托盘,然后窗体this.Visible = false,那么就找不到主窗体啦....我自己是用Socket解决的
zjy118 2010-06-24
  • 打赏
  • 举报
回复
判断程序的实例能否已经启动,无非是通过设立某个标识,让下次启动程序时知道该实例已经运行。嗯,可是在WIN32中每个进程都有自已独立的空间,那么如何处理呢,下面提供两种方案:

方案一,使用内核对象

因为内核对象是能够跨进程具有的,因而我们能够通过创建一个命名互斥体(Mutex)内核对象来判断,当用同一个名字的来创建Mutex时,CreateMutex会前往一个指向该互斥体的句柄,但是GetLastError会得到ERROR_ALREADY_EXISTS的返值。因而我们就能够判断程序已有一个实例在运行。下面是其中的关键代码



m_hmutex = ::CreateMutex( NULL,FALSE,appID);



if(m_hmutex == NULL) return FALSE; //



if( ::GetLastError() == ERROR_ALREADY_EXISTS ) //

{

return FALSE;

}

else

{

return TRUE;

}



方案二,使用共享数据段

背景学问:EXE和DLL文件映像由许多区组成如代码在.text段中,初始化数据在.data段中,未初始化数据在.bss段中。系统在加载EXE和DLL时,实际上是使用了内存映射,为了减少加载时间,同一EXE文件多个实例实际在系统中只有一份。但一般地如果其中某个实例对某个数据区进行写时,系统会使用Copy-On-Write机制将这个数据区在虚拟内存中复制一份出来,并映射到该实例原先的地址空间,也就实现了进程数据的独一性,而不会干扰其它进程。但是我们能够通过设置让系统关闭掉这个机制。哪么如何做呢?

在Visual Studio中你能够程序中加上以下几行:

#pragma comment(linker,"/SECTION:Share,RWS") //指示编译器Share是可读写和共享的,当然你也能够通过设置链接器选项间接加上 /SECTION:Share,RWS,不过我更喜欢这个,因而其他朋友就不必自已去设置这个选项了。

#pragma data_seg("Share") // 开始自已的数据段

int g_AppInit =0; //必需初始化,否则不会将编译器不会将其放入Share这个区

#pragma data_seg()



还有一种将某个变量置于特别数据段的方式

__declspec(allocate("Share")) int g_AppInit =0;

这种方式的好处是无论你初不初始化这个变量都将置于该Share段内

哪么如何判断呢能否启动了实例呢,很简单,看以下代码

g_AppInit ++ ;

if(g_AppInit >1)

{

AfxMessageBox("A instance are runed!");

return FALSE;
来源:www.va1314.com/bc

}



相关的问题:如何通知前一个实例

处理了重复启动的问题,为了获得更佳的用户体验,往往我们要使前一个实例激活,如何做呢?使用消息是一个不错的方法。首先你需要在启动程序时登记一个全局消息。



WM_APPACTIVE = ::RegisterWindowMessage(appID);



相同的appID字符串会给出相同的消息值,并且分是在0xC000- 0xFFFF区间中,然后当你发觉已启动程序实例时通知前一个实例:

DWORD dectype = BSM_APPLICATIONS; //仅向应用程序发送



BroadcastSystemMessage(BSF_POSTMESSAGE,

&dectype,

WM_APPACTIVE,

0,0);

前一个程序实例收到这个消息后,进行处理,能够前置窗口激活等等。
  • 打赏
  • 举报
回复
谢谢各位,我的问题解决。
有空加QQ 群:102738525 一起交流啊
zjy118 2010-06-24
  • 打赏
  • 举报
回复
http://bbs.eyuyan.com/read.php?tid=160751
兔子-顾问 2010-06-24
  • 打赏
  • 举报
回复
而且是自己写的,自己知道如何选择策略的。
兔子-顾问 2010-06-24
  • 打赏
  • 举报
回复
任何事都没绝对,这个前提是winform。非winform,都没窗体。你前置啥。直接把当前进程结束掉不就行了。
  • 打赏
  • 举报
回复
楼上的程序是有缺陷的,有些程序拿不到MainWindowHandle
兔子-顾问 2010-06-24
  • 打赏
  • 举报
回复
新建一个windows application,吧program.cs文件替换为以下内容即可。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication2
{
static class Program
{
[DllImport("user32.dll", EntryPoint = "SetForegroundWindow")]
public static extern int SetForegroundWindow(IntPtr hwnd);

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Process[] p = Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName);
//防止程序启动多次,只有一个运行的实例
if (p.Length > 1)
{
//将之前启动的窗体显示出来。
SetForegroundWindow(p[1].MainWindowHandle);
return;//退出软件
}
//正常情况下的窗体显示
Application.Run(new Form1());
}
}
}
  • 打赏
  • 举报
回复
楼主几位高手说的都很有道理,我都试过了,但是还是不行啊。
谁能够提供详细的解决方案啊?????
Baesky 2010-06-24
  • 打赏
  • 举报
回复

//string processName = "123";//进程名
//foreach (System.Diagnostics.Process thisproc in System.Diagnostics.Process.GetProcesses())
//{
// if (thisproc.ProcessName.Equals(processName ))
// {
// thisproc.Kill();
// }
//}
你的程序启动时候,进程肯定有你这个程序的名字了(就是123是吧?)
所以你判断的时候,必然能第2部分红字找找到你第一行红字设的进程名子进而必然执行thisproc.kill
vrhero 2010-06-24
  • 打赏
  • 举报
回复
老问题,用互斥体Mutex类即可...搜索一下例子多得是...
  • 打赏
  • 举报
回复
在codeproject网站有篇很好的帖子谈这个问题:

实现单实例并能够激活最小化了的程序
cecilia2006 2010-06-24
  • 打赏
  • 举报
回复
//string processName = "123";//进程名
//foreach (System.Diagnostics.Process thisproc in System.Diagnostics.Process.GetProcesses())
//{
// if (thisproc.ProcessName.Equals(processName ))
// {
// thisproc.Kill();
这个过程应该放在程序加载前吧 不能用thisproc.Kill(); 加载前如果发现存在 则这个程序 就不要加载了

Program 类里


//foreach (System.Diagnostics.Process thisproc in System.Diagnostics.Process.GetProcesses())
//{
// if !(thisproc.ProcessName.Equals(processName ))
// {
Application.Run(new Form6());
// // }
//}
ghost281536992 2010-06-24
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 wtpmcheng 的回复:]
运行通过~~~


C# code

/// <summary>
/// 应用程序的主入口点。
/// </summary>
[STAThread]
static void Main()
{

Process instance = RunningInstance();……
[/Quote]
这个方法貌似以前用过,而且就算窗体最小化了也没问题。
加载更多回复(5)

111,092

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧